有关serviceloader的Java 9依赖性问题
我有一个问题,关于如何根据这种情况在Java 9中更改serviceloader
I have a question about how the serviceloader changed in Java 9 based on this scenario
项目 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("<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
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
<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
Class 主要
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项目并执行gert方法名为 test()
So the cristina main
loads the gert project and executes a method of gert named test()
Java 8
当项目使用java 8运行时,它可以工作
Java 8
When the project is run with java 8 it works
Command
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
输出
在gert.Main.test();之前。
gert.Main.test();.
Java 9
完成同样的操作后java 9它没有
Before gert.Main.test();.
After gert.Main.test();.
Java 9
When the same is done with java 9 it doesnt
命令
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依赖关系。
The 2 above are done directly from the command line.
BUT
When I uncomment the dependencies in the pom.xml
of the cristina
project and I do a maven install and run the project from eclipse, java 9 works. So it seems that eclipse also takes the maven dependencies into consideration when running a project.
当依赖项在 gert
项目中,仅由 gert
项目使用,为什么 cristina
项目在使用Java 9运行时抛出异常?
When the dependencies are in the gert
project and only used by the gert
project why does the cristina
project throw an exception when running it with Java 9?
异常的原因可能是 java.xml .bind
是一个可升级的模块。
The reason for the exception could probably be that java.xml.bind
is an upgradeable module.
作为 JEP 261:模块系统在模块的风险和假设中说明:
As the JEP 261: Module System states in the Risks and assumptions for modules :
如果在命名模块和类路径
中定义了包,则将忽略类路径上的包。因此,类路径
不再用于将
构建的包扩充到环境中。
If a package is defined in both a named module and on the class path then the package on the class path will be ignored. The class path can, therefore, no longer be used to augment packages that are built into the environment.
org.eclipse.persistence.jaxb 。最后,代码行 ContextFinder.newInstance
调用 JAXBContextFactory.createContext
,提供绑定的类( ClassDef
)。文档进一步指出
Hence seems like the package org.eclipse.persistence.jaxb
is ignored. Eventually, the line of code ContextFinder.newInstance
invokes the JAXBContextFactory.createContext
with the classes provided to be bound(ClassDef
). The documentation further states that
throws
JAXBException
- 如果在创建时遇到错误JAXBContext
,例如(但不限于):...
throws
JAXBException
- if an error was encountered while creating theJAXBContext
, such as (but not limited to) : ...
- classesToBeBound 未对
java.xml.bind
模块开放
-
classesToBeBound are not open to
java.xml.bind
module
您可以尝试做的是在运行应用程序时使用
What you can try to do is while running the application make use of the
--upgrade-module-path /path/to/jaxb-api/dependency...
A:分隔的目录列表,
每个目录是模块的目录,
替换运行时映像中的可升级模块
A : separated list of directories, each directory is a directory of modules that replace upgradeable modules in the runtime image