Search code examples
javajarmanifest

Why can't I read custom manifest attributes from a jar?


I want to add custom manifest attributes to an existing jar file. The file is an external jar and is not the jar containing my application, nor is it a dependency of my application.

I drafted up some test code and verified that it makes the desired changes (by accessing the manifest with 7zip). However, it seems like Java is ignoring the manifest entry. When I call java.util.jar.Attributes.getValue(String), it returns null. This is the code I am using:

public static void main(String[] args) throws IOException, URISyntaxException {
    File jar = new File("C:\\Users\\employee1234\\Desktop\\auth-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
        manifestData.append("\n");
        manifestData.append("Deployments-Version: ");
        manifestData.append(testVersion);

        // 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 doesn't 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;
}

I inspected the Manifest instance in my debugger and the attribute was not anywhere present. I double and triple checked the jar file, and the manifest reflects my changes:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: employee1234
Build-Jdk: 1.8.0_202
Deployments-Version: 1.2.3

Is my issue with the way I am adding the attribute, or is the way I am attempting to read it? What am I doing wrong?


Solution

  • Make sure you append another linefeed after your newly added entry in the manifest and you should be good to go.

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