2016-08-25 2 views
2

Я пытаюсь настроить проект LWJGL с использованием Maven. Я использую пример «начального» исходного кода от the official website.Maven не включает атрибуты манифеста для установки LWJGL

Это включает в себя несколько строк с доступом манифеста атрибуты LWJGL, такие, как простая проверка версии:

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

Это работает без каких-либо проблем в среде Eclipse (конечно же после того, как построил проект с Maven), но при запуске clean install и затем запустить **-jar-with-dependencies.jar через ЦМД следующее исключение получить бросил:

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) 

Это происходит потому, Manifest объект, созданный APIUtil не содержит никаких атрибутов - , но только во встроенной версии Maven.

Почему это? Является ли мой pom.xml багги, или LWJGL 3.0.0 просто не готов к этому?

Это мой 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> 

ответ

2

Эта ошибка происходит потому, что LWJGL 3.0.0 is looking inside the Manifest a property called "Implementation-Version", но когда вы сделали убер-банку, это свойство не было установлено.

Это не проблема с тем, как вы сделали убер-банку: Манифест, который был создан maven-assembly-plugin выглядит следующим образом:

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 

Вы можете увидеть его в META-INF/MANIFEST.MF в jar-with-dependencies. Этот файл не имеет свойства "Implementation-Version". Это нормально: когда этот исполняемый JAR был создан, все MANIFEST всех зависимостей (по праву) игнорировались, только для генерации одного из них, содержащего "Main-Class", только так, чтобы JAR исполнялся.

uber-jar не может содержать то, что находится внутри каждого из манифеста зависимостей. Например, "Implementation-Version" является свойством, которое присутствует в манифесте из нескольких библиотек, поэтому его следует сохранить? (В конце может быть только один манифест, в uber-jar). Поэтому проблема возникает из-за того, что мы создаем исполняемый JAR, который может иметь только 1 манифест, чтобы он не мог агрегировать все свойства внутри каждого из манифеста зависимостей.

Есть 2 возможных решения:

  1. игнорировать его. В конце концов, это не ошибка.
  2. Не создавайте исполняемый банку, встраивая все зависимости внутри одного JAR, но создавайте ZIP-сборку с каждой зависимостью внутри папки lib: таким образом, каждый манифест будет сохранен. Это делается путем указания maven-jar-plugin добавления записи манифеста для основного класса с добавлением пути к классам и создания пользовательского дескриптора сборки.

    <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> 
    

    где /path/to/assembly.xml это путь к дескриптору сборки, относительно расположения POM, являющегося:

    <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> 
    

    При такой конфигурации, запуск mvn clean install создаст ZIP-файл artifactId-version-dist.zip. Распаковка его и работает (замена <finalName> с finalName вашего JAR)

    java -jar lib\<finalName>.jar 
    

    напечатает версию без каких-либо проблем.

+0

Отличный ответ, очень ясно. Мне не нравится второй вариант, так как это затрудняет выполнение пользователем программы. Есть ли возможность включить банки в основную банку? Будет ли это работать? Кроме того, просто игнорирование этого также не является вариантом, так как LWJGL вызывает эти методы в любом случае в статических блоках, когда инициализируются определенные классы (например, Libary calls checkHash(), который сравнивает фактический хэш хэда с значением, хранящимся в манифесте). – Frithjof

+0

@Frithjof Нет, в том числе библиотеки, банки внутри основной банки не будут работать. Банки будут рассматриваться как ресурсы, а классы, которые они содержат, не будут находиться в пути к классам (см. Http://stackoverflow.com/q/183292). Во втором варианте это так же просто, как и первое: вам нужно распаковать ZIP и запустить ту же команду, что и раньше. Если проблема состоит в том, что есть много банок (так что это запутывает, какой из них запускать), вы можете добавить скрипт оболочки ('start.bat' /' start.sh') в корень ZIP и выполнить эту оболочку вместо скрипта. (Очень похоже на то, что сам дистрибутив Maven поставляется в комплекте.) – Tunaki

+0

@Frithjof Еще одно решение - иметь основной артефакт не внутри папки 'lib', а вне его, в корне ZIP. Затем вы можете запустить 'java -jar finalName.jar' и не нужно беспокоиться о том, что находится внутри' lib'. Необходимые изменения: 1. ' false' (вместо 'true') в дескрипторе сборки 2. Добавить в дескриптор' $ {project.build.directory}/$ {project.finalName } .jar/ 'для копирования основного JAR и 3. Добавьте' lib 'в конфигурацию Jar Plugin. – Tunaki

Смежные вопросы