无法从 JAR 文件中读取自定义 Manifest 属性的原因及解决方案

无法从 JAR 文件中读取自定义 Manifest 属性的原因及解决方案

本文旨在解决无法从修改后的 JAR 文件中读取自定义 Manifest 属性的问题。通过使用 Filesystem API 修改 JAR 包中的 MANIFEST.MF 文件,添加自定义属性后,使用 JarFile 类读取时却无法获取到该属性。本文将分析问题原因,并提供正确的修改方法,确保自定义属性能够被正确读取。

问题分析与解决方案

当尝试向 JAR 文件的 Manifest 文件中添加自定义属性时,如果读取时发现该属性不存在,通常是因为在写入 Manifest 文件时缺少了必要的换行符。Manifest 文件的规范要求每个属性条目之间必须使用换行符分隔。

具体来说,在修改 Manifest 文件时,不仅需要在添加的属性前后添加换行符,还需要确保整个文件以换行符结尾。否则,Java.util.jar.Manifest 类在解析 Manifest 文件时可能无法正确识别新添加的属性。

以下代码片段展示了正确的修改 Manifest 文件的方式:

import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; import java.util.Map; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.nio.file.StandardCopyOption;  public class ManifestModifier {      public static void main(String[] args) throws IOException, URISyntaxException {         File jar = new File("C:Usersemployee1234Desktopauth-0.1.3.jar");         String testVersion = "1.2.3";          Map<String, String> env = new HashMap<>();         env.put("create", "true");          // Mount the jar         try (FileSystem fileSystem = FileSystems.newFileSystem(jarFileToURI(jar), env)) {             // Read the manifest             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();             Path manifestPath = fileSystem.getPath("/META-INF/MANIFEST.MF");             Files.copy(manifestPath, byteArrayOutputStream);              // Convert the manifest bytes to a string and construct a string builder             StringBuilder manifestData = new StringBuilder(byteArrayOutputStream.toString().trim());             // Add the custom manifest attribute, ensuring proper line breaks             manifestData.append(" ");             manifestData.append("Deployments-Version: ").append(testVersion).append(" ");             //Ensure the end of the file also has a new line character.             manifestData.append(" ");              // Write the manifest back to the jar             Files.copy(new ByteArrayInputStream(manifestData.toString().getBytes()), manifestPath,                     StandardCopyOption.REPLACE_EXISTING);              // Try-with-resources closes the mounted jar         }          // This part should now work         try (JarFile jarFile = new JarFile(jar)) {             Manifest manifest = jarFile.getManifest();             System.out.println(manifest.getMainAttributes().getValue("Deployments-Version"));         }     }      // Stolen from java.io.File with some modifications     private static URI jarFileToURI(File jarFile) throws URISyntaxException {         String sp = slashify(jarFile.getAbsoluteFile().getPath(), false);         if (sp.startsWith("//"))             sp = "//" + sp;         return new URI("jar:file", null, sp, null);     }      // Stolen from java.io.File;     private static String slashify(String path, boolean isDirectory) {         String p = path;         if (File.separatorChar != '/')             p = p.replace(File.separatorChar, '/');         if (!p.startsWith("/"))             p = "/" + p;         if (!p.endsWith("/") && isDirectory)             p = p + "/";         return p;     } }

关键修改:

manifestData.append(" "); manifestData.append("Deployments-Version: ").append(testVersion).append(" "); manifestData.append(" ");

这段代码在添加自定义属性后,以及文件末尾,都添加了换行符,确保 Manifest 文件格式正确。

注意事项

  • 编码问题: 确保在读取和写入 Manifest 文件时使用正确的字符编码,通常推荐使用 UTF-8。
  • 文件完整性: 修改 JAR 文件后,务必验证文件的完整性,确保没有损坏。
  • 依赖管理: 在实际项目中,修改第三方 JAR 文件可能不是一个好的实践。建议通过依赖管理工具(如 mavengradle)来管理依赖,并使用插件或构建脚本来修改 Manifest 文件。

总结

通过正确地添加换行符,可以解决无法从 JAR 文件中读取自定义 Manifest 属性的问题。在处理 Manifest 文件时,务必注意其格式规范,确保属性条目之间的分隔符正确。同时,建议在实际项目中采用更规范的依赖管理和构建方式,避免直接修改第三方 JAR 文件。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享