读我自己的jar子的舱单
我需要阅读提供我的课程的Manifest
文件,但是当我使用:
getClass().getClassLoader().getResources(...)
我从加载到Java运行时的第一个.jar
获取MANIFEST
。
我的应用程序将从applet或webstart运行,
所以我不会访问我自己的.jar
文件。
我实际上想从启动Felix OSGi的.jar
读取Export-package
属性,所以我可以将这些包暴露给Felix。 有任何想法吗?
你可以做两件事之一:
-
调用
getResources()
并遍历返回的URL集合,将它们作为清单读取,直到find你的:Enumeration<URL> resources = 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()
至less是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 }
您可以先find您的class级的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");
您可以使用jcabi-manifests中的 Manifests
,并使用任意一个可用的MANIFEST.MF文件中的任何属性,只需一行:
String value = Manifests.read("My-Attribute");
你需要的唯一依赖是:
<dependency> <groupId>com.jcabi</groupId> <artifactId>jcabi-manifests</artifactId> <version>0.7.5</version> </dependency>
此外,请参阅此博客文章的更多细节: http : //www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html
我相信,获取任何包(包括加载给定类的包)的清单最合适的方法是使用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)
来查找包含在特定包中的资源,而不是search该包的整个类path。
一般来说,如果你想要捆绑特定的信息,不要依赖关于类加载器的假设,直接使用OSGi API。
下面的代码适用于多种types的归档(jar,war)和多种types的类加载器(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); } }
您可以使用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(); }
最简单的方法是使用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:/
path,所以这应该额外处理。
你为什么包括getClassLoader步骤? 如果你说“this.getClass()。getResource()”你应该获取相对于调用类的资源。 我从来没有使用过ClassLoader.getResource(),但是从Java Docs中快速浏览一下,它会让你获得在任何当前类path中find的那个名字的第一个资源。
我使用了Anthony Juckel的解决scheme,但是在MANIFEST.MF中,密钥必须以大写字母开头。
所以我的MANIFEST.MF文件包含一个键如:
Mykey:价值
然后在激活器或其他类中,您可以使用Anthony的代码来读取MANIFEST.MF文件和您需要的值。
// 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();
public static Manifest getManifest( Class<?> cl ) { InputStream inputStream = null; try { URLClassLoader classLoader = (URLClassLoader)cl.getClassLoader(); String classFilePath = cl.getName().replace('.','/')+".class"; URL classUrl = classLoader.getResource(classFilePath); if ( classUrl==null ) return null; String classUri = classUrl.toString(); if ( !classUri.startsWith("jar:") ) return null; int separatorIndex = classUri.lastIndexOf('!'); if ( separatorIndex<=0 ) return null; String manifestUri = classUri.substring(0,separatorIndex+2)+"META-INF/MANIFEST.MF"; URL url = new URL(manifestUri); inputStream = url.openStream(); return new Manifest( inputStream ); } catch ( Throwable e ) { // handle errors ... return null; } finally { if ( inputStream!=null ) { try { inputStream.close(); } catch ( Throwable e ) { // ignore } } } }