我需要读取Manifest
传递我的课程的文件,但是当我使用时:
getClass().getClassLoader().getResources(...)
我MANIFEST
从第一次.jar
加载到Java Runtime.
我的应用程序将从小程序或webstart运行,
因此.jar
我猜我无法访问自己的文件.
我实际上想要读取启动Felix OSGi 的Export-package
属性.jar
,所以我可以将这些包暴露给Felix.有任何想法吗?
您可以先找到您班级的URL.如果它是JAR,那么从那里加载清单.例如,
Class clazz = MyClass.class; String className = clazz.getSimpleName() + ".class"; String classPath = clazz.getResource(className).toString(); if (!classPath.startsWith("jar")) { // Class not from JAR return; } String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF"; Manifest manifest = new Manifest(new URL(manifestPath).openStream()); Attributes attr = manifest.getMainAttributes(); String value = attr.getValue("Manifest-Version");
你可以做以下两件事之一:
调用getResources()
并遍历返回的URL集合,将其作为清单读取,直到找到您的URL:
Enumerationresources = getClass().getClassLoader() .getResources("META-INF/MANIFEST.MF"); while (resources.hasMoreElements()) { try { Manifest manifest = new Manifest(resources.nextElement().openStream()); // check that this is your manifest and do what you need or get the next one ... } catch (IOException E) { // handle } }
您可以尝试检查是否getClass().getClassLoader()
是实例java.net.URLClassLoader
.大多数Sun类加载器都包括在内AppletClassLoader
.然后,您可以将其转换并调用findResource()
已知的 - 至少对于applet - 直接返回所需的清单:
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader(); try { URL url = cl.findResource("META-INF/MANIFEST.MF"); Manifest manifest = new Manifest(url.openStream()); // do stuff with it ... } catch (IOException E) { // handle }
您可以使用Manifests
从jcabi-清单和读取任何可用的MANIFEST.MF文件的任何属性只用一行:
String value = Manifests.read("My-Attribute");
您需要的唯一依赖是:
com.jcabi jcabi-manifests 0.7.5
此外,请参阅此博客文章了解更多详情:http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html
我认为获取任何bundle的清单(包括加载给定类的bundle)的最合适的方法是使用Bundle或BundleContext对象.
// If you have a BundleContext Dictionary headers = bundleContext.getBundle().getHeaders(); // If you don't have a context, and are running in 4.2 Bundle bundle = FrameworkUtil.getBundle(this.getClass()); bundle.getHeaders();
请注意,Bundle对象还提供getEntry(String path)
查找特定包中包含的资源,而不是搜索该包的整个类路径.
通常,如果您需要特定于包的信息,请不要依赖关于类加载器的假设,只需直接使用OSGi API.
以下代码适用于多种类型的存档(jar,war)和多种类型的类加载器(jar,url,vfs,...)
public static Manifest getManifest(Class> clz) { String resource = "/" + clz.getName().replace(".", "/") + ".class"; String fullPath = clz.getResource(resource).toString(); String archivePath = fullPath.substring(0, fullPath.length() - resource.length()); if (archivePath.endsWith("\\WEB-INF\\classes") || archivePath.endsWith("/WEB-INF/classes")) { archivePath = archivePath.substring(0, archivePath.length() - "/WEB-INF/classes".length()); // Required for wars } try (InputStream input = new URL(archivePath + "/META-INF/MANIFEST.MF").openStream()) { return new Manifest(input); } catch (Exception e) { throw new RuntimeException("Loading MANIFEST for class " + clz + " failed!", e); } }
我将首先承认这个答案不能回答最初的问题,即通常能够访问清单的问题。但是,如果真正需要读取多个“标准”清单属性之一,则以下解决方案比上面发布的解决方案简单得多。因此,我希望主持人允许。请注意,此解决方案是在Kotlin中而不是Java中进行的,但是我希望通向Java的端口很简单。(尽管我承认我不知道Java的“ .`package`”。
在我的情况下,我想读取属性“ Implementation-Version”,因此我从上面给出的解决方案开始获取流,然后对其进行读取以获取值。在此解决方案有效的同时,一位同事检查了我的代码,向我展示了一种更轻松的方法来完成我想要的事情。请注意,此解决方案位于Kotlin中,而不是Java中。
val myPackage = MyApplication::class.java.`package` val implementationVersion = myPackage.implementationVersion
再次注意,这并不能回答原始问题,特别是“ Export-package”似乎不是受支持的属性之一。也就是说,有一个myPackage.name返回一个值。也许有人比我理解得更多,但我无法评论它是否返回原始海报所要求的值。
最简单的方法是使用JarURLConnection类:
String className = getClass().getSimpleName() + ".class"; String classPath = getClass().getResource(className).toString(); if (!classPath.startsWith("jar")) { return DEFAULT_PROPERTY_VALUE; } URL url = new URL(classPath); JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); Manifest manifest = jarConnection.getManifest(); Attributes attributes = manifest.getMainAttributes(); return attributes.getValue(PROPERTY_NAME);
因为在某些情况下...class.getProtectionDomain().getCodeSource().getLocation();
会给出路径vfs:/
,所以这应该另外处理.
您可以像这样使用getProtectionDomain().getCodeSource():
URL url = Menu.class.getProtectionDomain().getCodeSource().getLocation(); File file = DataUtilities.urlToFile(url); JarFile jar = null; try { jar = new JarFile(file); Manifest manifest = jar.getManifest(); Attributes attributes = manifest.getMainAttributes(); return attributes.getValue("Built-By"); } finally { jar.close(); }