有关serviceloader的Java 9依赖性问题

基于这种情况,我有一个关于serviceloader如何在Java 9中发生变化的问题


脚本

项目gert Class 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("".getBytes(StandardCharsets.UTF_8)); JAXBContext jaxbContext = JAXBContext.newInstance(ClassesDef.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.unmarshal(is); } } 

Project gert Class 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

  4.0.0 gert gert 0.0.1-SNAPSHOT  src   maven-compiler-plugin 3.7.0  1.8    org.apache.maven.plugins maven-assembly-plugin 3.1.0   jar-with-dependencies    gert.Main      make-assembly package  single         javax.xml.bind jaxb-api 2.3.0   org.glassfish.jersey.media jersey-media-moxy 2.26    

项目cristina Class 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 jars = new java.util.ArrayList(); 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

  4.0.0 cristina cristina 0.0.1-SNAPSHOT  src   maven-compiler-plugin 3.7.0  1.8      <!--  javax.xml.bind jaxb-api 2.3.0   org.glassfish.jersey.media jersey-media-moxy 2.26  -->   

所以cristina 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是直接从命令行完成的。

当我取消注释cristina项目的pom.xml中的依赖项并且我执行maven安装并从eclipse运行项目时 ,java 9可以工作。 因此,在运行项目时,eclipse似乎也会考虑maven依赖项。

当依赖项在gert项目中并且仅由gert项目使用时,为什么cristina项目在使用Java 9运行时抛出exception?

exception的原因可能是java.xml.bind是可升级的模块。

正如JEP 261:模块系统在模块的风险和假设中所述:

如果在命名模块和类路径中都定义了包,则将忽略类路径上的包。 因此,类路径不再用于扩充内置于环境中的包。

因此看起来像包org.eclipse.persistence.jaxb被忽略了。 最后,代码行ContextFinder.newInstance调用JAXBContextFactory.createContext ,并提供要绑定的类( ClassDef )。 文件进一步指出

抛出JAXBException – 如果在创建JAXBContext时遇到错误,例如(但不限于):…

  • classesToBeBound不对java.xml.bind模块开放

您可以尝试做的是在运行应用程序时使用

 --upgrade-module-path /path/to/jaxb-api/dependency... 

A:分隔的目录列表,每个目录是替换运行时映像中可升级模块的模块目录