有关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:分隔的目录列表,每个目录是替换运行时映像中可升级模块的模块目录