读我自己的jar子的舱单

我需要阅读提供我的课程的Manifest文件,但是当我使用:

 getClass().getClassLoader().getResources(...) 

我从加载到Java运行时的第一个.jar获取MANIFEST
我的应用程序将从applet或webstart运行,
所以我不会访问我自己的.jar文件。

我实际上想从启动Felix OSGi的.jar读取Export-package属性,所以我可以将这些包暴露给Felix。 有任何想法吗?

你可以做两件事之一:

  1. 调用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 } } 
  2. 您可以尝试检查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 } } } }