Maven dependency declaration triggers changes in compilation procedure? - java

So I have an application that uses both, Java and Kotlin sourcefiles (all placed in the /src/main/kotlin directory because we eventually want to migrate to kotlin anyway) and that generates an hibernate metamodel.
So our maven compile plugins look like this:
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--COMPILATION-->
<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>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
<compilerPlugins>
<plugin>all-open</plugin>
<plugin>jpa</plugin>
<plugin>spring</plugin>
<plugin>no-arg</plugin>
</compilerPlugins>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<pluginOptions>
<!-- Each annotation is placed on its own line -->
<option>all-open:annotation=javax.ejb.Stateless</option>
<option>no-arg:annotation=javax.ejb.Stateless</option>
<option>all-open:annotation=javax.ws.rs.ext.Provider</option>
<option>no-arg:annotation=javax.ws.rs.ext.Provider</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<!-- Check https://kotlinlang.org/docs/reference/using-maven.html#compiling-kotlin-and-java-sources -->
<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>
<!--END COMPILATION-->
<!-- ... -->
</plugins>
</build>
this results in
[WARNING] Duplicate source root: /home/cypherk/code/myapp/target/generated-sources/kapt/compile
[WARNING] Duplicate source root: /home/cypherk/code/myapp/target/generated-sources/kaptKotlin/compile
which I have no idea why but may be related.
If I do not declare a dependency to
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate.version}</version>
</dependency>
under <dependencies>, that's alright, everything gets generated the way it's supposed to get generated in /target/generated-sources/kapt/compile/. (/target/generated-sources-kaptKotlin/compile gets generated but remains empty).
However, if I do declare the dependency under <dependencies>, the java (but not kotlin) entities will get generated a second time in /target/generated-sources/annotations/, which will trigger a compilation error because all Java-based generated classes have a duplicate class in the kapt folder.
I'm no expert on Maven, I just use it because that's what we are supposed to use for the project. As such, I find simply declaring a dependency having such an effect exceedingly unintuitive.
Could anybody explain to me why this is happening?

I don't know why, but when you change the compile execution to:
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
It should work. Same with test-compile.

Related

How to initialize my Domain's data class property with a value computed in Spring's #RequestScope?

I have a simple Domain data class
#Document
data class Domain1Config(
#Id val id: String = <prop_to_init>,
val client: String,
val size: String
) : Serializable
and I want to initialize its id property with a value that will be computed in a #Component annotated with #RequestScope
#Component
#RequestScope
class CurrentInstance() {
private var currentInstance: String? = null
fun getCurrentInstanceId() = currentInstance
fun setCurrentInstanceId(instanceToSet: String) = {
currentInstance = instanceToSet
}
}
Solutions that I've tried so far weren't optimal:
access to the ThreadLocal from a static function call during initialization of the property which avoids the issue of dependency injection into objects that are not instantiated by Spring => but ThreadLocal use means potential memory leaks
Spring's #Configurable with AspectJ Weaving to inject Spring Beans into unmanaged objects (tried with both load-time & compile-time weaving, very setup-heavy and none seem to work properly with Kotlin + Java version 11+) => I'm also not sure if it's recommended or it's good practice to go on the AspectJ Weaving way
Regarding the AspectJ compile-time weaving, here are the plugins I'm using at compile time:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
<jvmTarget>${java.version}</jvmTarget>
</configuration>
<!-- Automatically opens all classes that are necessary for Spring to work -->
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
<sourceDir>target/generated-sources/annotations</sourceDir>
<sourceDir>target/generated-sources/openapi/src/main/kotlin</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<source>src/main/kotlin</source>
<source>src/main/java</source>
<source>target/generated-sources/annotations</source>
<source>target/generated-sources/openapi/src/main/kotlin</source>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<source>src/test/kotlin</source>
<source>src/test/java</source>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
<!-- jhipster-needle-maven-add-annotation-processor -->
</annotationProcessorPaths>
</configuration>
<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>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<forceAjcCompile>true</forceAjcCompile>
<sources />
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
<complianceLevel>11</complianceLevel>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.7</version>
</dependency>
</dependencies>
</plugin>
I was wondering what would be a good/best practice to follow in this specific case?

Proper Lifecycle Order For Annotation Processing In Maven

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>

Maven configuration for using Dagger 2 in a mixed Java/Kotlin project

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.

Maven lifecycle understanding

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.

XJC episode with maven

How can I generate an episode with maven? I now get an error message: an operand is missing (org.apache.cxf:cxf-xjc-plugin:2.4.0:xsdtojava:generate-sources:generate-sources)
Here my plugin:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-xjc-plugin</artifactId>
<version>2.4.0</version>
<configuration>
<extensions>
<extension>org.apache.cxf.xjcplugins:cxf-xjc-dv:2.4.0</extension>
</extensions>
</configuration>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>xsdtojava</goal>
</goals>
<configuration>
<xsdOptions>
<xsdOption>
<extension>true</extension>
<xsd>my.xsd</xsd>
<packagename>mypackage</packagename>
<extensionArgs>
<arg>-episode</arg>
</extensionArgs>
</xsdOption>
</xsdOptions>
</configuration>
</execution>
<execution>
<configuration>
<xsdOptions>
<xsdOption>
<extension>true</extension>
<xsd>my.xsd</xsd>
<extensionArgs>
<arg>-Xdv</arg>
</extensionArgs>
</xsdOption>
</xsdOptions>
</configuration>
</execution>
</executions>
Edit: Creation of the episode works fine. In another project the jar file containing the episode is given in though the episodes attribute. But I get an Exception: Error while parsing schema(s).Location [ file:/D:/workspace/XXX/src/test/resources/XXX.xsd{45,32}]. om.sun.istack.SAXParseException2: compiler was unable to honor this conversion customization. It is attached to a wrong place, or its inconsistent with other bindings. nested in com.sun.istack.SAXParseException2: (the above customization is attached to the following location in the schema)
Which is the xsd with episode info that will be included in the final product. Its some xjc:javaType adapter reference on that line. Can that cause problems?
Different plugin from what you're using, but below snipped used to work for me few years back. You might want to see if more recent version of plugin is available etc. Also tweak to use your schema and remove bindings customization if not needed.
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.7.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${basedir}/src/main/xsd</schemaDirectory>
<schemaIncludes>
<schemaInclude>Core.xsd</schemaInclude>
</schemaIncludes>
<bindingDirectory>${basedir}/src/main/xjb</bindingDirectory>
<bindingIncludes>
<bindingInclude>JaxbBindings.xjb</bindingInclude>
</bindingIncludes>
<generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory>
<episode>true</episode>
<episodeFile>${project.build.directory}/generated-sources/jaxb/META-INF/sun-jaxb.episode</episodeFile>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.1.10</version>
</dependency>
</dependencies>
</plugin>

Categories