HotswapProjects / HotswapAgent

Java unlimited redefinition of classes at runtime.
GNU General Public License v2.0
2.36k stars 493 forks source link

HotSwapAgent + JetBrainsRuntime 17 not working #416

Closed lorenzoferrante closed 2 years ago

lorenzoferrante commented 2 years ago

I'm trying to use HotSwap Agent with JBR 17.0.1 and I'm using hotswap-agent-1.4.2-SNAPSHOT.jar. When I run the app this is the errors I get:

java.lang.reflect.InaccessibleObjectException: Unable to make field private final jdk.internal.loader.URLClassPath java.net.URLClassLoader.ucp accessible: module java.base does not "opens java.net" to unnamed module @1e730495
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
        at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
        at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
        at org.hotswap.agent.util.classloader.URLClassLoaderHelper.prependClassPath(URLClassLoaderHelper.java:86)
        at org.hotswap.agent.config.PluginConfiguration.initExtraClassPath(PluginConfiguration.java:200)
        at org.hotswap.agent.config.PluginConfiguration.init(PluginConfiguration.java:181)
        at org.hotswap.agent.config.PluginConfiguration.<init>(PluginConfiguration.java:80)
        at org.hotswap.agent.config.PluginManager.initClassLoader(PluginManager.java:191)
        at org.hotswap.agent.util.HotswapTransformer$1.executeCommand(HotswapTransformer.java:316)
        at org.hotswap.agent.command.impl.CommandExecutor.run(CommandExecutor.java:43)

And also:

HOTSWAP AGENT: 16:33:56.160 RELOAD (org.hotswap.agent.config.PluginManager) - Reloading classes [com.lorenzoferrante.demo.HelloServlet] (autoHotswap)
HOTSWAP AGENT: 16:33:56.162 ERROR (org.hotswap.agent.plugin.jdk.JdkPlugin) - flushClassInfoCache() exception Unable to make public final void com.sun.beans.util.Cache.clear() accessible: module java.desktop does not "exports com.sun.beans.util" to unnamed module @1e730495.

These are the java opts:

-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n 
-javaagent:/opt/hotswap-agent/hotswap-agent.jar 
-Dextra.class.path=/extra_class_path 
-Dwebapp.dir=/webapp_dir 
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED 
--add-opens java.desktop/com.sun.beans.introspect=ALL-UNNAMED

How can I fix these errors?

Thank you very much

skybber commented 2 years ago

Could you try --add-opens java.base/java.net=ALL-UNNAMED ?

lorenzoferrante commented 2 years ago

I've added --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.desktop/java.beans=ALL-UNNAMED and now the errors are gone and when I edit a class it gives me this log:

HOTSWAP AGENT: 17:36:21.146 RELOAD (org.hotswap.agent.config.PluginManager) - Reloading classes [com.lorenzoferrante.demo.HelloServlet] (autoHotswap)

so I assume it's working, but sadly nothing is happening in the webapp

Edit: If you want to see my repo to check my setup here it is: https://github.com/lorenzoferrante/docker_hotswap

skybber commented 2 years ago

Are you using -XX:+AllowEnhancedClassRedefinition ?

skybber commented 2 years ago

You can also use -XX:HotswapAgent=external (and pby --add-opens=... is not necessary).

lorenzoferrante commented 2 years ago

Yes, here's all my java opts:

ENV JAVA_OPTS="-XX:+AllowEnhancedClassRedefinition -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/hotswap-agent/hotswap-agent.jar -Dextra.class.path=/extra_class_path -Dwebapp.dir=/webapp_dir --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens java.desktop/com.sun.beans.introspect=ALL-UNNAMED --add-opens java.desktop/com.sun.beans.util=ALL-UNNAMED --add-exports java.desktop/com.sun.beans.util=ALL-UNNAMED --add-exports java.base/java.net=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.desktop/java.beans=ALL-UNNAMED"
skybber commented 2 years ago

Is the standard redefinition working?

lorenzoferrante commented 2 years ago

I'm sorry, what do you mean by standard redefinition?

skybber commented 2 years ago

If the hotswap is working without HotswapAgent+AllowEnhancedClassRedefinition - in standard JVM without any addition.

lorenzoferrante commented 2 years ago

Oh I'm sorry, yes it's working for example with Java 11 + Tomcat in Intellij but the dockerized container with jbr17.0.1 + HotswapAgent is not.

skybber commented 2 years ago

No problem, did you see https://github.com/HotswapProjects/hotswap-docklands ?

lorenzoferrante commented 2 years ago

Yes, that's what I'm using as a base. I built the same environment but instead I installed JBR with JCEF (DCEVM) from JetBrainsRuntime.

Here's my Dockerfile:

FROM jetbrains/runtime:jbr17env

RUN curl -L -o /jdk17.0.1.tar.gz "https://cache-redirector.jetbrains.com/intellij-jbr/jbr_dcevm-17-linux-x64-b135.1.tar.gz"
RUN tar -xvf /jdk17.0.1.tar.gz
RUN mv /jbr /jdk17.0.1

# Set JDK 17.0.1
ENV JAVA_HOME="/jdk17.0.1"
ENV PATH="${JAVA_HOME}/bin:$PATH"

# Install HotSwap Agent
RUN mkdir -p /opt/hotswap-agent/ \
    && curl -L -o /opt/hotswap-agent/hotswap-agent-1.4.2-SNAPSHOT.jar "https://github.com/HotswapProjects/HotswapAgent/releases/download/1.4.2-SNAPSHOT/hotswap-agent-1.4.2-SNAPSHOT.jar" \
    && ln -f -s /opt/hotswap-agent/hotswap-agent-1.4.2-SNAPSHOT.jar /opt/hotswap-agent/hotswap-agent.jar

# Set up Tomcat
ENV ARCHIVE apache-tomcat-8.5.73
ENV INSTALL_DIR /opt
ENV SERVER_HOME ${INSTALL_DIR}/${ARCHIVE}
RUN curl -o ${SERVER_HOME}.zip -L http://apache.mirror.iphh.net/tomcat/tomcat-8/v8.5.73/bin/apache-tomcat-8.5.73.zip
RUN unzip ${SERVER_HOME}.zip -d /opt
RUN chmod a+x ${SERVER_HOME}/bin/catalina.sh
ENV DEPLOYMENT_DIR ${SERVER_HOME}/webapps/
ENTRYPOINT ${SERVER_HOME}/bin/catalina.sh run
EXPOSE 8080

RUN mkdir -p /extra_class_path
COPY ./target/demo-1.0-SNAPSHOT.war ${DEPLOYMENT_DIR}
EXPOSE 8000
ENV JAVA_OPTS="-XX:+AllowEnhancedClassRedefinition -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -javaagent:/opt/hotswap-agent/hotswap-agent.jar -Dextra.class.path=/extra_class_path -Dwebapp.dir=/webapp_dir --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens java.desktop/com.sun.beans.introspect=ALL-UNNAMED --add-opens java.desktop/com.sun.beans.util=ALL-UNNAMED --add-exports java.desktop/com.sun.beans.util=ALL-UNNAMED --add-exports java.base/java.net=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.desktop/java.beans=ALL-UNNAMED"

Here's my launch script:

#!/bin/sh
mvn clean package && docker build -t jetbrains/runtime:jbr17env .
docker run -ti --rm -p 8080:8080 -p 8000:8000 -v `pwd`/target/classes:/extra_class_path -v /var/run/docker.sock:/var/run/docker.sock jetbrains/runtime:jbr17env
skybber commented 2 years ago

Is there hotswap-agent.properties in demo-1.0-SNAPSHOT.war ? https://github.com/skybber/ping/blob/master/src/main/resources/hotswap-agent.properties

lorenzoferrante commented 2 years ago

Problem solved. I was updating a variable inside the initmethod:

public void init() {
        message = "Hello World!";
}

and probably that's not possible. Once I moved the variable in the doGetmethod everything is working fine. We can close this issue. Thank you so much for your help!