Проблемы с зависимостью Java 9 относительно serviceloader
У меня есть вопрос о том, как изменился загрузчик сервисов в Java 9 на основе этого сценария
сценарий
проект gert
Учебный класс Main
package gert;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class Main {
static public void test() throws JAXBException {
InputStream is = new ByteArrayInputStream("<Classes RUNTIME_INCLUDE_JARS=\"\"><Class></Class></Classes>".getBytes(StandardCharsets.UTF_8));
JAXBContext jaxbContext = JAXBContext.newInstance(ClassesDef.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.unmarshal(is);
}
}
проект gert
Учебный класс ClassesDef
package gert;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="Classes")
public class ClassesDef {
@XmlAttribute(name="RUNTIME_INCLUDE_JARS")
public String jars=null;
@XmlElement(name="Class")
public String classes;
}
проект gert
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>gert</groupId>
<artifactId>gert</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>gert.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency><!-- org.eclipse.persistence.jaxb.JAXBContextFactory comes with this dependency-->
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.26</version>
</dependency>
</dependencies>
</project>
проект cristina
Учебный класс Main
package cristina;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception {
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");
String bWithDep = "C:\\Users\\gert\\eclipse-workspace91java\\gert\\target\\gert-0.0.1-SNAPSHOT-jar-with-dependencies.jar";
List<URL> jars = new java.util.ArrayList<URL>();
File f;
f = new File(bWithDep);
jars.add(f.toURL());
URL[] urls = (URL[])jars.toArray(new URL[jars.size()]);
URLClassLoader urlloader = URLClassLoader.newInstance(urls, ClassLoader.getSystemClassLoader());
System.out.println("Before\tgert.Main.test();.");
Class<?> c= Class.forName("gert.Main", true, urlloader);
Object gert = c.newInstance();
Method m = c.getMethod("test");
m.invoke(gert);
System.out.println("After\tgert.Main.test();.");
}
}
проект cristina
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cristina</groupId>
<artifactId>cristina</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- <dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.26</version>
</dependency> -->
</dependencies>
</project>
Так кристина main
загружает проект GERT и выполняет метод GERT по имени test()
тестирование
Java 8
Когда проект запускается с Java 8, он работает
команда
"C:\Program Files\Java\jre1.8.0_151\bin\java.exe" -cp C:\Users\gert\eclipse-workspace91java\cristina\target\cristina-0.0.1-SNAPSHOT.jar cristina.Main
Выход
Before gert.Main.test();.
After gert.Main.test();.
Java 9
Когда то же самое делается с Java 9, это не так
команда
"C:\Program Files\Java\jre-9.0.1\bin\java.exe" -cp C:\Users\gert\eclipse-workspace91java\cristina\target\cristina-0.0.1-SNAPSHOT.jar cristina.Main
Выход
Before gert.Main.test();.
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at cristina.Main.main(Main.java:23)
Caused by: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: org.eclipse.persistence.jaxb.JAXBContextFactory]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:278)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:397)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662)
at gert.Main.test(Main.java:14)
... 5 more
Caused by: java.lang.ClassNotFoundException: org.eclipse.persistence.jaxb.JAXBContextFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122)
at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276)
... 9 more
Вышеуказанные 2 выполняются непосредственно из командной строки.
НО
Когда я раскомментирую зависимости в pom.xml
из cristina
Project и я делаем Maven установить и запустить проект из Eclipse, Java 9 работает. Таким образом, кажется, что eclipse также учитывает зависимости maven при запуске проекта.
Вопрос
Когда зависимости находятся в gert
проект и используется только gert
проект почему cristina
проект выдает исключение при запуске его с Java 9?
1 ответ
Причиной исключения может быть то, что java.xml.bind
это обновляемый модуль.
Как указано в JEP 261: модульная система в рисках и допущениях для модулей:
Если пакет определен как в именованном модуле, так и в пути к классам, то пакет в пути к классам будет игнорироваться. Следовательно, путь к классу больше нельзя использовать для дополнения пакетов, встроенных в среду.
Отсюда похоже на пакет org.eclipse.persistence.jaxb
игнорируется В конце концов, строка кода ContextFinder.newInstance
вызывает JAXBContextFactory.createContext
с классами, предоставляемыми для привязки (ClassDef
). В документации также говорится, что
бросает
JAXBException
- если при созданииJAXBContext
, таких как (но не ограничиваясь): ...
- ClassToBeBound не открыты для
java.xml.bind
модуль
То, что вы можете попытаться сделать, это при запуске приложения использовать
--upgrade-module-path /path/to/jaxb-api/dependency...
A: отдельный список каталогов, каждый каталог представляет собой каталог модулей, которые заменяют обновляемые модули в образе среды выполнения