I'm currently working on a java project where I need to generate and compile JPA metamodel classes as part of the build. I did some research and found an answer here: Generate the JPA metamodel files using maven-processor-plugin - What is a convenient way for re-generation? that seems like a reasonable solution. The problem is, my project also contains some groovy classes that need to be compiled alongside the java. If I enable the maven-processor-plugin, the maven build will fail as soon as it encounters a java class that depends on a groovy class. Looking at the console output, I can see that maven-processor-plugin is running before the groovy compiler, so those groovy classes have not had a chance to be compiled.
Does anyone know if there is a good way to handle this? Is there some way to break the compilation process up into stages so that I can control what gets processed when?
Here is a snippet of my pom.xml:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>false</showWarnings>
<compilerId>groovy-eclipse-compiler</compilerId>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>3.6.0-03</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>3.0.7-02</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>4.5-jdk8</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<outputDirectory>${project.build.directory}/../src/main/generated-sources/java/jpametamodel</outputDirectory>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.13.Final</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/../src/main/generated-sources/java/jpametamodel</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
After a good bit of trial and error I finally found a solution that seems to work. maven-processor-plugin can use include/exclude filters to limit the scope of the files it looks at. I added an includes filter that restricts the processing to my domain classes. Now when I build it can process my annotated classes without getting hung up on the groovy files.
My final result ended up looking like this:
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>4.5-jdk8</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<includes>
<include>com/tura/product/domain/*.java</include>
</includes>
<outputDirectory>${project.build.directory}/generated-sources/java</outputDirectory>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.13.Final</version>
</dependency>
</dependencies>
</plugin>
Related
It's the first I am working with SOAP interface.
I have WSDL that I suppose to generate stub classes from.
I use axistools-maven-plugin but not all classes were generated. For instance, ConnectWithToken wasn't present into generated stubs.
My pom.xml plugins section:
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>axistools-maven-plugin</artifactId>
<version>${axis.version}</version>
<configuration>
<urls>
<url>https://api.e-conomic.com/secure/api1/EconomicWebService.asmx?WSDL</url>
</urls>
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<subPackageByFileName>true</subPackageByFileName>
<verbose>true</verbose>
<allElements>true</allElements>
<indentSize>4</indentSize>
</configuration>
</plugin>
</plugins>
Is it the way for me to generate all classes specified into wsdl using above plugin?
My solution was to change SOAP class generator provider. QA helped a lot but I had to adopt solution based on the jaxws-maven-plugin plugin documentation and project.
pom.xml dependencies section:
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.10</version>
</dependency>
pom.xml build section:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>generate-source-by-wsdl</id>
<goals>
<goal>wsimport</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<vmArgs>
<vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
</vmArgs>
<wsdlUrls>
<wsdlUrl>https://api.e-conomic.com/secure/api1/EconomicWebService.asmx?WSDL</wsdlUrl>
</wsdlUrls>
<sourceDestDir>src/main/java</sourceDestDir>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
What is the recommended Maven setup for using Dagger 2 in a mixed Java/Kotlin project?
I found a sample project which uses Gradle: https://github.com/damianpetla/kotlin-dagger-example
Something similar with Maven would be very helpful.
UPDATE: What have I tried?
I used the Kotlin configuration from kotlinlang.org/docs/reference/using-maven.html
and the Dagger configuration from google.github.io/dagger.
I also used the build-helper-maven-plugin plugin to integrate the annotation processing in IDEA.
My main problem was that I run into compilation cycles. My configuration mixed the compilation of Kotlin and calling the annotation processor, which generates Dagger2 classes. I unsystematically tried to separate both phases but lacked the deeper Maven understanding to get it working.
javac can scan both source files (java) and classes in search for annotations:
http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#processing
This means that you can make this work if you don't have any Dagger-generated classes referenced in Kotlin code (which means Dagger module implementations)
invoke kotlin compiler (no Dagger generated types in Kotlin code)
invoke annotation processor (processes annotations in both java files and kotlin-compiled files)
invoke java compiler - has access to both Dagger generated types and Kotlin types
You can write your services in both java and kotlin, but the module must be created by a java class
Here is the corresponding pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>testkotlindagger</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<kotlin.version>1.0.6</kotlin.version>
<dagger2.version>2.7</dagger2.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<!-- Dagger 2 -->
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger2.version}</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>${dagger2.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<source>src/main/java</source>
<source>src/main/kotlin</source>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.2.4</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>compile</phase>
<configuration>
<outputDirectory>target/generated-sources/annotations</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals> <goal>testCompile</goal> </goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
On the other hand, if you include Dagger-generated types in your kotlin code, you must have these available before kotlin code is compiled, which means you need Kotlin-aware annotation processor (KAPT)
In this scenario the problem boils down to the question:
Is kapt supported in maven?
Sadly, the answer is no, but there is a bug filed to support it:
https://youtrack.jetbrains.com/issue/KT-14478
Since kapt is now supported in maven, you can write your services in both Java and Kotlin, and the module can be created by either a Java class or a Kotlin class. You can configure pom.xml build file like this:
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.7.20</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>2.22</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<!-- Specify your annotation processors here. -->
<annotationProcessorPath>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.22</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
<sourceDir>src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
These are the links usefull to read when you want to create maven project with java, kotlin and dagger:
https://www.baeldung.com/kotlin/maven-java-project
https://kotlinlang.org/docs/kapt.html#using-in-maven
https://github.com/google/dagger#installation
Please note that kapt is still not supported for IntelliJ IDEA's own build system. Because of this, you will not be able to compile and run the application in the Intellij IDE by clicking on the Play button next to the Main method. To run the application, first build the project using the maven toolbox. After that, you can run the application in the Intellij IDE by clicking on the Play button next to the Main method. Alternatively you can create a run configuration to run the jar file. After that, you can run this configuration, or run it in debug mode by clicking on the run or debug button next to the run configuration combobox.
I have a JavaEE, maven application. In this application I use classes generated from XSD, and mappers via Mapstruct.
In my EJB module, the maven build should do the following:
generate the java classes from XSD by jaxb2-maven-plugin
add these generated classes to sources folder by
build-helper-maven-plugin, because:
maven-processor-plugin generates Mapstruct mapper implementions by generate-mapstruct-mappers, which use these XSD generated classes
finally add these mapper implementations to the sources folder also
Unfortunately, it does not work for me. This is the plugins part of the ejb's pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>${version.jaxb2-maven-plugin}</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
<packageName>com.my.project</packageName>
<catalog>src/main/resources/xsd/CustomCatalog.xml</catalog>
<xjbSources>
<xjbSource>${project.basedir}/src/main/resources/jaxb2/</xjbSource>
</xjbSources>
<sources>
<source>${project.basedir}/src/main/resources/xsd/applications/MyNewClass.xsd</source>
</sources>
<xsdPathWithinArtifact>my/source/xsds</xsdPathWithinArtifact>
</configuration>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<configuration>
<defaultOutputDirectory>
${project.build.directory}/generated-sources
</defaultOutputDirectory>
</configuration>
<executions>
<execution>
<id>generate-mapstruct-mappers</id>
<phase>compile</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<processors>
<processor>org.mapstruct.ap.MappingProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${version.mapstruct}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${version.mapstruct}</version>
</dependency>
</dependencies>
</plugin>
<!-- attach sources -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>compile</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
This generates the classes from JAXB, and put into the sources to the JAR file. But the generated Mapper implementations aren't in the sources.
In eclipse I can set the generated classes to be part of the build path, but the generated JAR doesn't contain the mapperimplementations.
If I change the phase of the plugins, the maven-processor-plugin will throw a cannot find simbol ERROR, and the symbol is the generated class from jaxb.
Thanks for helping me.
According to my understanding, the desired flow would be as following:
Generate classes from XSD
Add them as sources (via Builder helper)
Generate mappers from MapStruct (which requires classes from XSD)
Add them as sources (via Builder helper)
compile all
Hence, you could try to:
set the execution of jaxb2-maven-plugin to phase generate-sources
set a first execution of build-helper-maven-plugin to phase generate-sources (which should add the classes from XSD as sources)
set the mappers generation execution to phase process-sources (which should find XSD classes as sources), but declare it after the build-helper-maven-plugin entry
set a second execution of build-helper-maven-plugin to phase process-sources, which should add the mappers as sources
To better clarify it: two executions of the build-helper-maven-plugin in two different phases for two different generated sources. Also better to point at two different folders for each generated sources (i.e. generate-sources-xsd and generated-sources-mappers). In your pom follow this declaration order: jaxb2 plugin, mappers plugin, build helper plugin.
Below a possible example:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>xjc</id>
<phase>generate-sources</phase>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources-xsd</outputDirectory>
<packageName>com.my.project</packageName>
<catalog>src/main/resources/xsd/CustomCatalog.xml</catalog>
<xjbSources>
<xjbSource>${project.basedir}/src/main/resources/jaxb2/</xjbSource>
</xjbSources>
<sources>
<source>${project.basedir}/src/main/resources/xsd/applications/MyNewClass.xsd</source>
</sources>
<xsdPathWithinArtifact>my/source/xsds</xsdPathWithinArtifact>
</configuration>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.2.4</version>
<configuration>
<defaultOutputDirectory>
${project.build.directory}/generated-sources-mappers
</defaultOutputDirectory>
</configuration>
<executions>
<execution>
<id>generate-mapstruct-mappers</id>
<phase>process-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<processors>
<processor>org.mapstruct.ap.MappingProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.0.0.Final</version>
</dependency>
</dependencies>
</plugin>
<!-- attach sources -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources-xsd</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-source2</id>
<phase>process-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources-mappers</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
Note: in the snippet above I had to add some versions in order to make it work.
For a full list of Maven lifecycle phases, here.
Given that Jacoco doesn't play nicely with PowerMockito when instrumenting "on the fly", I've been trying to configure offline instrumentation in the hope this will give me proper unit test coverage for classes that use PowerMockito.
I've setup my pom as below but I still get zero % coverage on my test class. Any help much appreciated as it's driving me slowly bonkers!
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mandy</groupId>
<artifactId>jacoco-test</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>jacoco-test Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<powermock.version>1.5.4</powermock.version>
<jacoco.version>0.7.1.201405082137</jacoco.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<classifier>runtime</classifier>
<version>${jacoco.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>instrument</id>
<phase>process-classes</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>restore-report</id>
<phase>prepare-package</phase>
<goals>
<goal>restore-instrumented-classes</goal>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<!--<argLine>${argLine}</argLine>-->
<systemPropertyVariables>
<!-- JaCoCo runtime must know where to dump coverage: -->
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
<finalName>jacoco-test</finalName>
</build>
</project>
here is my class under test:
public class Utils {
private Utils() {
}
public static String say(String s) {
return "hello:"+s;
}
}
here is my test:
#RunWith(PowerMockRunner.class)
#PrepareOnlyThisForTest(Utils.class)
#PowerMockIgnore("org.jacoco.agent.rt.*")
public class UtilsTest {
#Test
public void testSay() throws Exception {
PowerMockito.mockStatic(Utils.class);
Mockito.when(Utils.say(Mockito.anyString())).thenReturn("hello:mandy");
assertEquals("hello:mandy", Utils.say("sid"));
}
}
I run mvn clean install which generates the jacoco.exe
Coverage report (generated from jacoco.exec using an ant script ):-
This pom worked for me:
<build>
<finalName>final-name</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.2.201409121644</version>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See this link.
I saw the same behavior, though after following the thread on the GitHub issue it seems to be fixed in 1.6.5, which proved true for me.
Hopefully this will save someone a headache later :).
Working configuration with:
jacoco-maven-plugin 0.7.7.201606060606
powermock 1.6.5
I am not using offline instrumentation.
For me this sample of Offline Instrumentation works well.
But it turns in my case that there is a simplier solution: just do not include the tested class in #PrepareForTest({}) annotation before its declaration.
I used Jacoco offline instrumentation and after execution of test restore ed original classes with help of "restore-instrumented-classes" goal. My JaCoCo configuration look like this:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>jacoco-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>*</exclude>
</excludes>
</configuration>
</plugin>
I made it work using the javaagent of PowerMock.
see here: https://github.com/powermock/powermock/wiki/PowerMockAgent
Remove the #RunWith annotations, put the PowerMockRule as described in the link above. Make it public.
Put the following line in the maven-surefire-plugin configuration:
-javaagent:${org.powermock:powermock-module-javaagent:jar}
(used the technique described here : Can I use the path to a Maven dependency as a property?)
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.stackoverflow</groupId>
<artifactId>q2359872</artifactId>
<version>2.0-SNAPSHOT</version>
<name>q2359872</name>
<properties>
<!-- Must be listed in the dependencies section otherwise it will be null. -->
<my.lib>${org.jmockit:jmockit:jar}</my.lib>
</properties>
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
<build>
<defaultGoal>generate-sources</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Example usage: -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
<configuration>
<executable>echo</executable>
<arguments>
<argument>path to jar=</argument>
<argument>${org.jmockit:jmockit:jar}</argument>
<argument>my.lib=</argument>
<argument>${my.lib}</argument>
</arguments>
</configuration>
</plugin>
<!-- end of Example usage -->
</plugins>
</build>
</project>
I ended up using offline instrumentation and Jacoco (similar to what you have done) in conjunction with sonar and I was able to get the coverage numbers from that.
I was also facing the same issue. I was able to generate report partially. I have used both these tags for my test cases #RunWith(PowerMockRunner.class)
#PrepareForTest({}). And the report was not getting generated for the test cases where i used the above mentioned tags. But for one of the test case there was only this tag #RunWith(PowerMockRunner.class). Somehow the report was getting generated for that case. And also i have never used offline instrumentation. When i tried using the offline instrumentation i was getting error saying that the class was already instrumented. I tried various scenarios and followed various links but could not generate the report. Finally as per the above comment i upgraded my version of powermock from 1.5.5 to 1.6.5 and i was able to generate the report. Following is my pom.xml entry
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.5.201505241946</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<destFile>${basedir}/target/jacoco.exec</destFile>
<!--
Sets the name of the property containing the settings
for JaCoCo runtime agent.
-->
</configuration>
</execution>
<execution>
<!--<id>post-unit-test</id>
<phase>test</phase>-->
<id>default-report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${basedir}/target/jacoco.exec</dataFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${basedir}/target/jacoco-ut</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Following is my entry in pom .xml for maven-surefire-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>#{argLine}</argLine>
<skipTests>false</skipTests>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
#{argLine} was set as a property
<properties>
<argLine>-noverify -Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=512m</argLine>
</properties>
And upgraded my powermock version from 1.5.5 to 1.6.5 . Finally i could see my report generation for the classes where i used the following tags in my test cases
#RunWith(PowerMockRunner.class) #PrepareForTest({})
Use below maven plugin code snippet this works fine in jenkins as well as in local and shows full code coverage for PowermockRunner unit tests
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<id>pre-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<append>true</append>
</configuration>
</execution>
<execution>
<id>pre-integ-test</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<append>true</append>
</configuration>
</execution>
<execution>
<id>jacoco-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>jacoco-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
Code Coverage with JaCoCo explained the reason
The simplest way to use JaCoCo it is — on-the-fly instrumentation with using JaCoCo Java Agent. In this case a class in modified when it is being loaded. You can just run you application with JaCoCo agent and a code coverage is calculated. This way is used by Eclemma and Intellij Idea. But there is a big issue. PowerMock instruments classes also. Javassist is used to modify classes. The main issue is that Javassist reads classes from disk and all JaCoCo changes are disappeared. As result zero code coverage for classes witch are loaded by PowerMock class loader.
We are going to replace Javassist with ByteBuddy (#727) and it should help to resolve this old issue. But right now there is NO WAY TO USE PowerMock with JaCoCo On-the-fly instrumentation. And no workaround to get code coverage in IDE.
JaCoCo Offline Instrumentation can solve this problem.
The sample of Offline Instrumentation fixed my problem .
I have tried these versions of the below softwares; they work together and generate the jacoco report without any extra effort. I use the gradle build tool with powermock, mockito and wiremock.
powermock-api-mockito2:2.0.2
powermock-module-junit4:2.0.2
gradle 5.6.2
The above correctly generates the jacoco coverage report.
I had same issue with JaCoCo On-the-fly and PowerMock. 0% code coverage was generated every time
Found out that JaCoCo version 0.7.7.201606060606 and PowerMock version 1.6.2 are compatible and code coverage is generated successfully.
The report is correct. The provided test leads to no coverage as you mock what happens when calling the method "say". One should never mock the "instance/class under test", only do this for the dependencies and surroundings of the test subject.
In this case: The code return "hello:"+s; is never reached by the test and the constructor of Utils is not called. There is no coverage displayed as there is no test coverage of these lines at all.
Nevertheless using JaCoCo and PowerMock together is not trivial. I am currently looking for how to get it to run, too. Maybe your provided test is just unluckily written and JaCoCo is already working as it should?
We had configured the generation of QueryDSL in our project using the maven plugin:
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
<dependencies>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
At some point, we made changes in our project, and the generation process begin to fail with this error:
cannot find symbol import xxx.xxxx.xxxx.domain.QContact;
After some investigation, this problem is caused by a class that has been entirely commented.
For example:
//package xxx.xxxx.xxxxx;
////
//public class Test {
////
//}
If you put a class like this in your domain package, the generation process fails.
Well, on the other hand, this kind of classes wouldn't have to exist in your project.