5

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:

  • Jmockit seems to instrument classes it need.
  • JaCoCo can not instrument classes which is already instrumented by Jmockit and spits out a HUGE amount of exceptions, saying that it's impossible to instrument class, which were already instrumented. However Sonar seems to have a valid output for such a scenario.
    So first question is: can I somehow suppress such an exceptions? It is really critical because the size of the log file on our CI system achieves 50Mb (!), which is not acceptable. A lot of free space is just eaten up by such a logs on our CI machine.

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>
mr.nothing
  • 5,141
  • 10
  • 53
  • 77
  • 1
    I have the same issue but I dont' use jmocket. But it seems JaCoCo doesn't support mocking framework, you can reference https://groups.google.com/forum/#!msg/jenkins-jacoco-plugin-mailing-list/4SwvdUwLNAg/_JboWc140PMJ – Dennys Jul 16 '13 at 15:23
  • @Dennys, yeah, it seems the only solution here is to switch sonar to another code coverage tool like Cobertura. – mr.nothing Jul 17 '13 at 10:09

5 Answers5

4

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 ^_-

jjcosare
  • 1,463
  • 9
  • 9
3

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

Stuti Verma
  • 1,059
  • 13
  • 32
2

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.

Godin
  • 9,801
  • 2
  • 39
  • 76
1

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

bad robot
  • 148
  • 1
  • 4
0

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
LoganMzz
  • 1,597
  • 3
  • 18
  • 31