Gradle JRE vs JDK please add lib/tools.jar from yo

2019-07-18 02:13发布

问题:

I'm running java tests with gradle. here is the exception I have:

java.lang.RuntimeException: java.lang.IllegalStateException: Unable to load Java agent; please add lib/tools.jar from your JDK to the classpath
at org.powermock.modules.agent.PowerMockClassRedefiner.redefine(PowerMockClassRedefiner.java:59)
at org.powermock.modules.agent.support.PowerMockAgentTestInitializer.redefine(PowerMockAgentTestInitializer.java:49)
at org.powermock.modules.agent.support.PowerMockAgentTestInitializer.initialize(PowerMockAgentTestInitializer.java:41)
at com.blablacompany.app.weight.WeightMilestonesViewBeanUnitTest.setUpMock(WeightMilestonesViewBeanUnitTest.java:41)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:80)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:47)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:103)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Unable to load Java agent; please add lib/tools.jar from your JDK to the classpath
at org.powermock.modules.agent.JDK6AgentLoader.getVirtualMachineImplementationFromEmbeddedOnes(JDK6AgentLoader.java:97)
at org.powermock.modules.agent.JDK6AgentLoader.loadAgent(JDK6AgentLoader.java:70)
at org.powermock.modules.agent.AgentInitialization.initializeAccordingToJDKVersion(AgentInitialization.java:40)
at org.powermock.modules.agent.PowerMockAgent.verifyInitialization(PowerMockAgent.java:83)
at org.powermock.modules.agent.PowerMockAgent.instrumentation(PowerMockAgent.java:76)
at org.powermock.modules.agent.PowerMockClassRedefiner.redefine(PowerMockClassRedefiner.java:57)
... 37 more

It turns out that for some reason my gradle uses JRE's folder as java.home and this is why it can not find the tools.jar. I on't think that I want manually add it to my classpath though. I'm wondering if there any way to tell gradle to use JDK's java home instead of JRE's? I also tried overriding it using org.gradle.java.home in gradle.properties file and it did not work. Any help is greatly appreciated.

WHen I run the same tests from my IDE(Intellij IDEA) all tests are passed successfully. I'm running all it on Mac OS.

println System.getenv("JAVA_HOME")
println System.properties['java.home']

displays:

/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home                                                                                                                                                                
/Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/jre 

回答1:

It's not a JDK vs. JRE problem. The values of JAVA_HOME vs. java.home are correct and expected (see other SO question on this topic). tools.jar is necessary to execute tools such as javac and javadoc. However, neither the JDK's javac command line compiler nor Gradle's JavaCompile task will automatically put tools.jar on the compile class path of user code. Instead you'll have to add it explicitly. For example:

def jdkHome = System.getenv("JAVA_HOME")

dependencies {
    compile files("$jdkHome/lib/tools.jar")
}


回答2:

Ok, seems that JRE is actually the right one that I need to use. No reason java.home to be set to JDK. So the way I solved it was just adding tools library to my classpath:

testCompile ([fileTree(dir: "${System.properties['java.home']}/../lib", include: '*tools.jar'),fileTree(dir: "lib/test", include: '*.jar') ])

Initially the reason why I did not wanted to do this was that once I added it I had a bunch of

java 7 errors: java.lang.VerifyError: Expecting a stackmap frame at branch target 10

I did fix it by adding "-noverify" parameter to my tests closure:

Closure basicTestConfiguration = {
jvmArgs "-Dactivemq.directory=${testActivemqDir}",
        "-Duser.timezone=Etc/UTC",
        "-javaagent:${configurations.testAgent.singleFile}",
        "-XX:MaxPermSize=256m",
        "-noverify"
...
}

and applying this closure to my test suite:

postCommitSuite basicTestConfiguration


回答3:

Edited

Check this out http://www.gradle.org/docs/current/userguide/build_environment.html. Especially this section

The configuration is applied in following order (in case an option is configured in multiple locations the last one wins):


from gradle.properties located in project build dir.
from gradle.properties located in gradle user home.
from system properties, e.g. when -Dsome.property is used in the command line.