Search code examples
javaeclipsemavenlwjglpom.xml

Maven not including manifest attributes for LWJGL install


I am trying to setup a LWJGL project using Maven. I am using the example "getting started" source code from the official website.

This includes a few lines accessing LWJGL's manifest attributes, such as a simple version check:

System.out.println("Hello LWJGL " + Version.getVersion() + "!");

This runs without any problems in the Eclipse environment (of course after having built the project with Maven), but when running clean install and then running **-jar-with-dependencies.jar through cmd, the following exception get's thrown:

java.lang.NullPointerException
        at org.lwjgl.system.APIUtil.apiGetManifestValue(APIUtil.java:97)
        at org.lwjgl.Version.getVersion(Version.java:33)
        at HelloWorld.run(HelloWorld.java:43)
        at HelloWorld.main(HelloWorld.java:130)

This is because the Manifest object created by APIUtil does not include any attributes - but only in the built version by Maven.

Why is this? Is my pom.xml buggy, or is LWJGL 3.0.0 just not ready for this?

This is my pom.xml:

<properties>
    <mainClass>HelloWorld</mainClass>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <finalName>${project.artifactId}-${project.version}.jar</finalName>
</properties>

<dependencies>
    <dependency>
        <groupId>org.lwjgl</groupId>
        <artifactId>lwjgl</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.lwjgl</groupId>
        <artifactId>lwjgl-platform</artifactId>
        <version>3.0.0</version>
        <classifier>natives-windows</classifier>
    </dependency>
    <dependency>
        <groupId>org.lwjgl</groupId>
        <artifactId>lwjgl-platform</artifactId>
        <version>3.0.0</version>
        <classifier>natives-linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.lwjgl</groupId>
        <artifactId>lwjgl-platform</artifactId>
        <version>3.0.0</version>
        <classifier>natives-osx</classifier>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>${mainClass}</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

Solution

  • This errors happens because LWJGL 3.0.0 is looking inside the Manifest a property called "Implementation-Version", but when you made the uber-jar, this property was not set.

    This is not really an issue with how you made the uber-jar: the Manifest that was created by maven-assembly-plugin looks like:

    Manifest-Version: 1.0
    Archiver-Version: Plexus Archiver
    Built-By: Me
    Created-By: Apache Maven 3.3.9
    Build-Jdk: 1.8.0_102
    Main-Class: HelloWorld
    

    You can see it inside META-INF/MANIFEST.MF of the jar-with-dependencies. This file does not have a "Implementation-Version" property. This is normal: when this executable JAR was created, all the MANIFEST of all dependencies were (rightfully) ignored, only to generate one containing the "Main-Class", just so that the JAR is executable.

    The uber-jar cannot contain what is inside each of the dependencies manifest. For example, "Implementation-Version" is a property that is present in the manifest of multiple libraries, so which one should it keep? (There can be only one Manifest at the end, in the uber-jar). So the issue comes up because we're making an executable JAR, which can only have 1 Manifest so it cannot aggregate all the properties inside each of the dependencies manifest.

    There are 2 possible solutions:

    1. Ignore it. After all, this is not really an error.
    2. Don't make an executable jar by embedding all the dependencies inside a single JAR, but create a ZIP assembly with each dependencies inside a lib folder: this way, each Manifest will be kept. This is done by telling the maven-jar-plugin to add a Manifest entry for the main class with the addition of the classpath and creating a custom assembly descriptor.

      <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
          <configuration>
              <archive>
                  <manifest>
                      <mainClass>${mainClass}</mainClass>
                      <addClasspath>true</addClasspath>
                  </manifest>
              </archive>
          </configuration>
      </plugin>
      <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.6</version>
          <executions>
              <execution>
                  <phase>package</phase>
                  <goals>
                      <goal>single</goal>
                  </goals>
              </execution>
          </executions>
          <configuration>
              <descriptors>
                  <descriptor>/path/to/assembly.xml</descriptor>
              </descriptors>
          </configuration>
      </plugin>
      

      where /path/to/assembly.xml is the path to the assembly descriptor, relative to the location of the POM, being:

      <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
        <id>dist</id>
        <formats>
          <format>zip</format>
        </formats>
        <dependencySets>
          <dependencySet>
            <outputDirectory>lib</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
          </dependencySet>
        </dependencySets>
      </assembly>
      

      With such a configuration, running mvn clean install will create a ZIP file artifactId-version-dist.zip. Unpacking it and running (replacing <finalName> with the finalName of your JAR)

      java -jar lib\<finalName>.jar
      

      will print the version without any issues.