我对基于此场景的Java 9中serviceloader的变化提出了疑问
项目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>
因此cristina main
加载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是直接从命令行完成的
的 BUT
当我取消注释pom.xml
项目的cristina
中的依赖项并进行maven安装和从eclipse运行项目时,java 9可以正常工作。因此,在运行项目时,eclipse似乎也会考虑maven依赖关系。
当依赖项位于gert
项目中且仅由gert
项目使用时,为什么cristina
项目在使用Java 9运行时会引发异常?
答案 0 :(得分:1)
异常的原因可能是java.xml.bind
是可升级的模块。
由于风险中的JEP 261: Module System状态和模块的假设:
如果在命名模块和类路径中定义了包 然后将忽略类路径上的包。班级路径 因此,不再可以用于增加构建的包 进入环境。
因此似乎忽略了包org.eclipse.persistence.jaxb
。最后,代码行ContextFinder.newInstance
调用 JAXBContextFactory.createContext
,并提供要绑定的类(ClassDef
)。文档进一步指出
抛出
JAXBException
- 如果在创建JAXBContext
时遇到错误,例如(但不限于):...
- classesToBeBound 未向
java.xml.bind
模块开放
您可以尝试做的是在运行应用程序时使用
--upgrade-module-path /path/to/jaxb-api/dependency...
A:分隔的目录列表, 每个目录都是模块的目录 替换运行时映像中的可升级模块