mr.nothing
mr.nothing

Reputation: 5399

Sonar (jacoco) + jmockit spamming with exceptions

I'm facing a error which starting to be really irritating.
Here is what I have: 1) Sonar 3.5 which uses JaCoCo as coverage tool. 2) Jmockit lib to perform testing with use of mocks. 3) Build process automized with maven.

So when I run first mvn clean install which is ok and then I'm running mvn sonar:sonar and what is happening here:

Here are the exceptions I've got:

java.lang.instrument.IllegalClassFormatException: Error while instrumenting class app/MyClass.
Caused by: java.lang.IllegalStateException: Class app/MyClass is already instrumented.

Assuming that suppression of such an exceptions is impossible I investigated it a little bit and found out that JaCoCo (a tool, which Sonar uses and a tool, which can't instrument already instrumented classes) have such a mode as offline instrumentation (AFAIK Sonar neither support this offline instrumentation or can suppress such a warnings). This thing is designed to be used exactly for such a cases. So I tried to set up JaCoCo as a plugin in maven, but I failed to do this cause JaCoCo can't find some execution file. When I'm running mvn clean install the following error pops up:

[INFO] --- jacoco-maven-plugin:0.6.2.201302030002:report (report) @ webservice-mws --- [INFO] Skipping JaCoCo execution due to missing execution data file

If I'm not mistaken this execution file is the RESULT of the JaCoCo plugin. I'm totally frustrated and do not know what to do with this.

If somebody can help me with that it will be greatly appreciated!
Thanks in advance!

my pom.xml settings for JaCoCo plugin:

             <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.6.2.201302030002</version>
                <executions>
                    <execution>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Upvotes: 5

Views: 7777

Answers (5)

Stuti Verma
Stuti Verma

Reputation: 1069

As per my insight into this research: It is possible to also use offline-instrumented classes with the JaCoCo Java agent. In this case, the configuration is taken from the agent options. The agent must be configured in a way that pre-instrumented classes are excluded, e.g. with " excludes=* ". Otherwise it will result in error messages on the console if the agent instruments such classes again likewise in your case. Jacoco plugin entry:-

<configuration> 
     <excludes> 
          <exclude>*</exclude> 
     </excludes> 
</configuration>

The agent jacocoagent.jar is part of the JaCoCo distribution and includes all required dependencies. A Java agent can be activated with the following JVM option(in command line):

-javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2]

For JaCoCo agent options, consider the following link: http://www.jacoco.org/jacoco/trunk/doc/agent.html

As the agent jacocoagent.jar is part of the JaCoCo distribution, it gets automatically included in argLine parameter and need not be set explicitly, but we should to verify if jacocoagent.jar is shown as set in argLine while doing mvn clean install command

Upvotes: 3

bad robot
bad robot

Reputation: 148

I had the same problem. It appears to be fixed in jacoco plugin 0.7.1+. I am using 0.7.3.201502191951 and the problem went away for me.

Essentially the jMockit agent loads classes and retransforms them before the JaCoCo agent sees them. Afterwards JaCoCo can not perform the required instrumentations any more. see this link

https://github.com/jacoco/jacoco/issues/208

Upvotes: 1

LoganMzz
LoganMzz

Reputation: 1623

The problem is JMockit "reload" the class to mock them. Then JaCoCo try to instrument them again. It's at this moment the error occurs.

Note: It doesn't happen for mocked interfaces.

See the following stacktrace when running EclEmma+JaCoCo

java.lang.instrument.IllegalClassFormatException: Error while instrumenting class com/company/AbstractClass.
    at org.jacoco.agent.rt.internal_9dd1198.CoverageTransformer.transform(CoverageTransformer.java:89)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
    at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
    at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
    at mockit.internal.startup.Startup.redefineMethods(Startup.java:260)
    at mockit.internal.RedefinitionEngine.redefineClasses(RedefinitionEngine.java:26)
    at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineClass(BaseTypeRedefinition.java:172)
    at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineClassAndItsSuperClasses(BaseTypeRedefinition.java:147)
    at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineMethodsAndConstructorsInTargetType(BaseTypeRedefinition.java:134)
    at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineTargetClassAndCreateInstanceFactory(BaseTypeRedefinition.java:197)
    at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineType(BaseTypeRedefinition.java:57)
    at mockit.internal.expectations.mocking.TypeRedefinition.redefineType(TypeRedefinition.java:47)
    at mockit.internal.expectations.mocking.SharedFieldTypeRedefinitions.redefineTypeForMockField(SharedFieldTypeRedefinitions.java:60)
    at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldType(FieldTypeRedefinitions.java:48)
    at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldTypes(FieldTypeRedefinitions.java:38)
    at mockit.internal.expectations.mocking.SharedFieldTypeRedefinitions.redefineTypesForTestClass(SharedFieldTypeRedefinitions.java:43)
    at mockit.integration.internal.TestRunnerDecorator.handleMockFieldsForWholeTestClass(TestRunnerDecorator.java:135)
    at mockit.integration.internal.TestRunnerDecorator.updateTestClassState(TestRunnerDecorator.java:34)
    at mockit.integration.junit4.internal.JUnit4TestRunnerDecorator.handleMockingOutsideTestMethods(JUnit4TestRunnerDecorator.java:107)
    at mockit.integration.junit4.internal.JUnit4TestRunnerDecorator.invokeExplosively(JUnit4TestRunnerDecorator.java:37)
    at mockit.integration.junit4.internal.MockFrameworkMethod.invokeExplosively(MockFrameworkMethod.java:32)
    at sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at mockit.internal.util.MethodReflection.invokeWithCheckedThrows(MethodReflection.java:106)
    at mockit.internal.mockups.MockMethodBridge.callMock(MockMethodBridge.java:85)
    at mockit.internal.mockups.MockMethodBridge.invoke(MockMethodBridge.java:44)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.io.IOException: Error while instrumenting class com/afklm/cco/slt/integrator/batch/AbstractData.
    at org.jacoco.agent.rt.internal_9dd1198.core.instr.Instrumenter.instrumentError(Instrumenter.java:147)
    at org.jacoco.agent.rt.internal_9dd1198.core.instr.Instrumenter.instrument(Instrumenter.java:98)
    at org.jacoco.agent.rt.internal_9dd1198.CoverageTransformer.transform(CoverageTransformer.java:87)
    ... 44 more
Caused by: java.lang.IllegalStateException: Class com/company/AbstractClass is already instrumented.
    at org.jacoco.agent.rt.internal_9dd1198.core.internal.instr.InstrSupport.assertNotInstrumented(InstrSupport.java:81)
    at org.jacoco.agent.rt.internal_9dd1198.core.internal.instr.ClassInstrumenter.visitField(ClassInstrumenter.java:79)
    at org.jacoco.agent.rt.internal_9dd1198.asm.ClassVisitor.visitField(Unknown Source)
    at org.jacoco.agent.rt.internal_9dd1198.asm.ClassReader.a(Unknown Source)
    at org.jacoco.agent.rt.internal_9dd1198.asm.ClassReader.accept(Unknown Source)
    at org.jacoco.agent.rt.internal_9dd1198.asm.ClassReader.accept(Unknown Source)
    at org.jacoco.agent.rt.internal_9dd1198.core.instr.Instrumenter.instrument(Instrumenter.java:78)
    at org.jacoco.agent.rt.internal_9dd1198.core.instr.Instrumenter.instrument(Instrumenter.java:96)
    ... 45 more

Upvotes: 0

jjcosare
jjcosare

Reputation: 1473

You may use Cobertura as your code coverage on Sonar 3.5.1.

To change it:

  1. Login as admin
  2. Go to Settings > Configuration
  3. In General Settings Category > Java
  4. Set Code coverage plugin = cobertura

Worked like charm on my project ^_-

Upvotes: 4

Godin
Godin

Reputation: 10564

As far as I know message "Class app/MyClass is already instrumented." means that this class was already instrumented by JaCoCo. Here is some of possible reasons why this might happen:

  • offline instrumentation mixed with online - they should be used exclusively
  • two JaCoCo agents attached to the JVM during tests - this might happen, because Sonar tries to automatically attach JaCoCo agent and execute tests, and jacoco-maven-plugin also attaches agent, so to avoid this take a look on property "sonar.dynamicAnalysis=reuseReports" or don't use jacoco-maven-plugin and Sonar will do the job on its own

For me your message looks a bit challenging to understand configuration, so I can't precisely say which of the cases above you're facing, but my bet on second one.

Hope this information will be useful for you. Feel free to come back to Sonar Users Mailing list, if this would not help you to solve issue.

Upvotes: 2

Related Questions