突然无法通过vscode启动配置运行java

jaql4c8m  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(1005)

这个问题在这里已经有答案了

如何解决Java9上的inaccessibleobjectexception(“无法使{member}可访问:模块{a}没有向{b}打开{package}”)(4个答案)
六天前关门了。
我正在使用vscode devcontainer来编写java应用程序。我把它放了大约一个月,回来工作,现在我得到了一些不熟悉的错误。

配置

这里我将提供devcontainer环境的相关配置文件。
我的文档如下:

FROM openjdk:16-slim-buster

# Install things

RUN apt-get update \
    && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
    #
    # Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
    && apt-get -y install curl git openssh-client vim less iproute2 procps lsb-release

# Install Maven CLI things

ARG MAVEN_VERSION=3.6.3
ARG MAVEN_SHA=c35a1803a6e70a126e80b2b3ae33eed961f83ed74d18fcd16909b2d44d7dada3203f1ffe726c17ef8dcca2dcaa9fca676987befeadc9b9f759967a8cb77181c0
RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
  && curl -fsSL -o /tmp/apache-maven.tar.gz https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
  && echo "${MAVEN_SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \
  && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
  && rm -f /tmp/apache-maven.tar.gz \
  && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
ENV MAVEN_HOME /usr/share/maven
ENV MAVEN_CONFIG /root/.m2

# Allow for a consistant java home location for settings - image is changing over time

RUN if [ ! -d "/docker-java-home" ]; then ln -s "${JAVA_HOME}" /docker-java-home; fi

我的devontainer json在这里:

{
    "name": "Java Development",
    "dockerFile": "Dockerfile",

    // Set *default* container specific settings.json values on container create.
    "settings": { 
        "terminal.integrated.shell.linux": "/bin/bash",
        "java.home": "/docker-java-home"
    },

    // Add the IDs of extensions you want installed when the container is created.
    "extensions": [
        "vscjava.vscode-java-pack",
        "redhat.vscode-xml"
    ]
}

问题

当我之前停止使用这个应用程序时,一切都编译好了,运行正常,我可以通过vscode启动配置进行测试。现在,我遇到了两个问题,我认为它们是相关的。首先,当我尝试使用启动配置运行我的应用程序时,它不起作用,我得到一个奇怪的错误:

所以我不能通过vscode启动任何东西。接下来,我试着 mvn package 我的测试失败了,错误如下:

com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item
        at com.insurexcel.poipoi.input.InputProcessorTest.setup(InputProcessorTest.java:34)
Caused by: java.lang.IllegalStateException: Unable to load cache item
        at com.insurexcel.poipoi.input.InputProcessorTest.setup(InputProcessorTest.java:34)
Caused by: java.lang.ExceptionInInitializerError
        at com.insurexcel.poipoi.input.InputProcessorTest.setup(InputProcessorTest.java:34)
Caused by: com.google.inject.internal.cglib.core.$CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @523fa30b
        at com.insurexcel.poipoi.input.InputProcessorTest.setup(InputProcessorTest.java:34)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @523fa30b
        at com.insurexcel.poipoi.input.InputProcessorTest.setup(InputProcessorTest.java:34)

所以它看起来和一些反射有关。我用的是gson和guice,这里是 pom.xml :

<!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.google.inject/guice -->
        <dependency>
            <groupId>com.google.inject</groupId>
            <artifactId>guice</artifactId>
            <version>4.2.3</version>
        </dependency>

我试着把guice升级到 5.0.0-BETA-1 这就修正了测试中的错误,并使编译成功。但是,现在我在执行一些序列化时遇到运行时错误。下面是错误的样子:

Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String java.lang.Throwable.detailMessage accessible: module java.base does not "opens java.lang" to unnamed module @523fa30b
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
        at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:177)
        at java.base/java.lang.reflect.Field.setAccessible(Field.java:171)
        at com.google.gson.internal.reflect.UnsafeReflectionAccessor.makeAccessible(UnsafeReflectionAccessor.java:44)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:159)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
        at com.google.gson.Gson.getAdapter(Gson.java:458)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)
        at com.google.gson.Gson.getAdapter(Gson.java:458)
        at com.google.gson.Gson.toJson(Gson.java:696)
        at com.google.gson.Gson.toJson(Gson.java:683)
        at com.google.gson.Gson.toJson(Gson.java:638)
        at com.google.gson.Gson.toJson(Gson.java:618)
        ...

所以很明显这和gson有关。似乎无法访问专用字段?我尝试序列化的对象如下所示:

public class MapContainer {
    private MyMapObject map;
    private String status;
    private Exception errorInformation;

    public MapContainer(MyMapObject map) {
        this.map = map;
        this.status = "okay";
        this.errorInformation = null;
    }
    public MapContainer(Exception error) {
        this.map = null;
        this.status = "error";
        this.errorInformation = error;
    }

    ...
    getters and setters
    ...
}

基于这个错误,我的对象中的exception字段似乎很难处理。我找遍了所有的地方,找不到一个很好的理由来解释这一切。我检查了docker图像,我正在运行这个,它似乎最近更新了。我的 java --version 在容器中返回:

openjdk 16-ea 2021-03-16
OpenJDK Runtime Environment (build 16-ea+30-2130)
OpenJDK 64-Bit Server VM (build 16-ea+30-2130, mixed mode, sharing)

如果有人能提供任何线索或想法,这可能是从哪里来的,我将不胜感激!

xzabzqsa

xzabzqsa1#

问题是gson试图使用反射来访问 java.lang 模块。
在Java9之前的日子里,这很好。对于Java9,这可能引发异常。
快速而肮脏的解决方法是使用 -add-opens 选择 java 命令行。有关详细信息,请参阅第一个参考资料。
另一个选择是实现一个定制的对象Map器来序列化/反序列化触发该Map的jdk类。应用程序的序列化/反序列化依赖于jdk类的私有字段的细节,这有点狡猾。它们可能会更改,导致应用程序在没有警告的情况下中断。
(我猜这是由于 errorInformation 字段…)
有关这些选项的详细信息,请参阅:
如何解决Java9上的inaccessibleobjectexception(“无法使{member}可访问:模块{a}没有向{b}打开{package}”)?
gson高级-用于简化的自定义序列化
我检查了docker图像,我正在运行这个,它似乎最近更新了。
对。看起来您现在正在使用新的java16ea版本。我不确定这是否明智。在你脚下更新 Docker 的形象当然是不明智的。您应该针对java的特定目标(主要)版本进行开发。
更新
但是,如果由于容器中的java版本更改而导致此问题“突然”开始发生,则以前的版本必须是Java8或更早版本。
在查看openjdk站点上的java16页面时,我看到它正在实现jep396:默认情况下强封装jdk内部,这将阻止gson干扰私有字段的访问。如果你读了jep,可能还有另一个解决方法。

相关问题