2

我对基于这种情况的 Java 9 中的服务加载器如何更改有疑问


设想

项目gertMain

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);
    }
}

项目gertClassesDef

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>

项目cristinaMain

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>

于是cristinamain加载了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.xmlcristina并执行 maven 安装并从 eclipse 运行项目时,java 9 可以工作。所以看起来eclipse在运行项目时也考虑了maven依赖。

问题

当依赖项在gert项目中并且仅由gert项目使用时,为什么cristina项目在使用 Java 9 运行时会引发异常?

4

1 回答 1

2

异常的原因可能java.xml.bind是一个可升级的模块。

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

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

因此似乎包裹org.eclipse.persistence.jaxb被忽略了。最终,这行代码使用提供的类ContextFinder.newInstance调用JAXBContextFactory.createContext绑定( ClassDef)。该文件进一步指出

throws JAXBException- 如果在创建 时遇到错误JAXBContext,例如(但不限于): ...

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

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

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

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

于 2017-11-22T17:24:29.607 回答