Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Mapstruct and Lombok #874

Closed
fvanhille opened this issue Apr 20, 2019 · 8 comments
Closed

Support for Mapstruct and Lombok #874

fvanhille opened this issue Apr 20, 2019 · 8 comments
Labels

Comments

@fvanhille
Copy link

fvanhille commented Apr 20, 2019

I would like to re-open the topic that has already been discussed, and related to compilation problems occuring when using the groovy-eclipse-commpiler, Mapstruct and Lomboc together.
Something is not clear for me when you combile these different components in a maven config.

Here is the maven config I use :

<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<compilerId>groovy-eclipse-compiler</compilerId>
					<source>${java.version}</source>
					<target>${java.version}</target>
					<encoding>${project.build.sourceEncoding}</encoding>
					<useIncrementalCompilation>true</useIncrementalCompilation>
					<fork>true</fork>
					<compilerArguments>
						<javaAgentClass>lombok.launch.Agent</javaAgentClass>
					</compilerArguments>
					<showWarnings>true</showWarnings>
					<showDeprecation>true</showDeprecation>

					<!--annotationProcessorPaths>
						<path>
							<groupId>org.mapstruct</groupId>
							<artifactId>mapstruct-processor</artifactId>
							<version>${org.mapstruct.version}</version>
						</path>
						<path>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
							<version>${lombok.version}</version>
						</path>
					</annotationProcessorPaths-->
					<compilerArgs>
						<compilerArg>-Amapstruct.suppressGeneratorTimestamp=true</compilerArg>
						<compilerArg>-Amapstruct.suppressGeneratorVersionInfoComment=true</compilerArg>
						<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
					</compilerArgs>
				</configuration>
				<dependencies>
					<dependency>
						<groupId>org.codehaus.groovy</groupId>
						<artifactId>groovy-eclipse-compiler</artifactId>
						<version>2.9.2-01</version>
					</dependency>
					<dependency>
						<groupId>org.codehaus.groovy</groupId>
						<artifactId>groovy-eclipse-batch</artifactId>
						<version>2.5.6-02</version>
					</dependency>
					<dependency>
						<groupId>org.mapstruct</groupId>
						<artifactId>mapstruct-processor</artifactId>
						<version>${org.mapstruct.version}</version>
					</dependency>
					<dependency>
						<groupId>org.projectlombok</groupId>
						<artifactId>lombok</artifactId>
						<version>${lombok.version}</version>
					</dependency>
					<!--dependency>
						<groupId>org.projectlombok</groupId>
						<artifactId>lombok-maven-plugin</artifactId>
						<version>1.18.6.0</version>
					</dependency-->
				</dependencies>
			</plugin>

Versions specified :

java.version = 1.8
org.mapstruct.version = 1.3.0.Final
lombok.version = 1.18.6

With this config I run into the classnotfoundexception: org.mapstruct.ap.spi.AstModifyingAnnotationProcessor error.

If I add lombok.jar in the classpath argument for the compiler, like this for exemple :

...\repository\org\mapstruct\mapstruct-processor\1.3.0.Final/mapstruct-processor-1.3.0.Final

-> this time the compilation is ok but the mapper implementations are not generated by MapStruct !

Commenting or not the annotationProcessorPaths part does not change anything.

Is this still a bug in the groovy-eclipse-compiler plugin or did I miss something ?

@eric-milles
Copy link
Member

Support for annotationProcessorPaths was added in groovy-eclipse-compiler version 3.3.0-01. You are using 2.9.2-01. Can you try with that version? If it still does not work, can you supply a simple project that demonstrates the issue?

@eric-milles
Copy link
Member

It seems there is some compiler classpath isolation going on. I tried mapstruct-jdk8 and mapstruct-processor as project and compiler dependencies. When I force the processor jar onto the bootclasspath of the JVM, it can be found but errors out.

[INFO] Compiling in a forked process using C:\Users\U0076777\.m2\repository\org\codehaus\groovy\groovy-eclipse-batch\2.5.6-02\groovy-eclipse-batch-2.5.6-02.jar
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] Failure executing groovy-eclipse compiler:
----------
1. ERROR in C:\Users\U0076777\pde-workspaceg\eclipse-space\mapstruct\src\main\java\com\baeldung\mapper\SimpleSourceDestinationMapper.java (at line 8)
	public interface SimpleSourceDestinationMapper {
	                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Internal error in the mapping processor: java.lang.ExceptionInInitializerError  	at org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext.<init>(DefaultModelElementProcessorContext.java:50)  	at org.mapstruct.ap.MappingProcessor.processMapperElements(MappingProcessor.java:218)  	at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:156)  	at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.handleProcessor(RoundDispatcher.java:142)  	at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.round(RoundDispatcher.java:124)  	at org.eclipse.jdt.internal.compiler.apt.dispatch.BaseAnnotationProcessorManager.processAnnotations(BaseAnnotationProcessorManager.java:171)  	at org.eclipse.jdt.internal.compiler.Compiler.processAnnotations(Compiler.java:952)  	at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:460)  	at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:436)  	at org.eclipse.jdt.internal.compiler.batch.Main.performCompilation(Main.java:4749)  	at org.eclipse.jdt.internal.compiler.batch.Main.compile(Main.java:1770)  	at org.eclipse.jdt.internal.compiler.batch.Main.main(Main.java:1493)  Caused by: java.lang.NullPointerException  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.initMapStructVersion(DefaultVersionInformation.java:208)  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.<clinit>(DefaultVersionInformation.java:36)  	... 12 more  
----------
1 problem (1 error)
<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>

    <artifactId>mapstruct</artifactId>
    <groupId>xyz</groupId>
    <version>1.0</version>

    <properties>
        <m2e.apt.activation>jdt_apt</m2e.apt.activation>

        <maven.compiler.fork>true</maven.compiler.fork>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
        <org.projectlombok.version>1.18.6</org.projectlombok.version>
        <org.springframework.version>4.3.23.RELEASE</org.springframework.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy</artifactId>
            <version>2.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${org.mapstruct.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${org.springframework.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                      <goals>
                          <goal>properties</goal>
                      </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                    <compilerArguments>
                        <javaAgentClass>lombok.launch.Agent</javaAgentClass>
                    </compilerArguments>
                    <compilerArgument>-J-Xbootclasspath/a:${org.mapstruct:mapstruct-processor:jar}</compilerArgument>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>3.3.0-01</version>
                    </dependency>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-batch</artifactId>
                        <version>2.5.6-02</version>
                    </dependency>
                    <dependency>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>${org.projectlombok.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project> 

@fvanhille
Copy link
Author

I tried with groovy-eclipse-compiler version 3.3.0-01 but still got errors ; strange I don't fall into the same case like you :

  • first, I think <fork>true</fork> is missing in the pom you provided
  • when I tried to compile Lombok generation did not process and then getters/setters were missing
  • after having added <annotationProcessorPaths> with mapstruct & Lombok I still get ClassNotFoundException: org.mapstruct.ap.spi.AstModifyingAnnotationProcessor

even with :

<compilerArguments>
	<javaAgentClass>lombok.launch.Agent</javaAgentClass>
	<classpath>C:\Users\....\.m2\repository\org\mapstruct\mapstruct-processor\1.3.0.Final/mapstruct-processor-1.3.0.Final</classpath>
</compilerArguments>

and :
<compilerArgument>-J-Xbootclasspath/a:C:\Users\....\.m2\repository\org\mapstruct\mapstruct-processor\1.3.0.Final/mapstruct-processor-1.3.0.Final</compilerArgument>

together in the plugin configuration.

@eric-milles
Copy link
Member

In my example, forking is set in the properties element: <maven.compiler.fork>true</maven.compiler.fork>

Annotation processor paths are optional; if not supplied the classpath is scanned. I tried with anno proc paths, but it did not help the class loading. You should not need to list lombok in the proc paths since the agent class is set explicitly.

I would not suggest ever setting classpath compiler arg explicitly. You can add dependencies within the compiler's plugin element. Adding to the bootclasspath is what puts a jar in the compiler's classpath, which should be what dependencies within the compiler's plugin element go to.

But I think there is a bug in ecj for apt classloading: https://youtrack.jetbrains.com/issue/IDEA-189760

I can try and debug when I get more time to confirm that the class loader is being closed and that's why it can't find processor classes.

@eric-milles
Copy link
Member

I can confirm that lombok and mapstruct can be used individually -- may have been known but wanted to have it on record. There are samples for both here: https://github.com/groovy/groovy-eclipse/tree/master/extras/groovy-eclipse-compiler-tests/src/it

The combination of lombok and mapstruct is not working properly in ecj (basis of groovy-eclipse-compiler). I think this is because the java agent class is set and that throws off the default discovery process.

I can offer a couple of suggestions for you:

  1. Use groovy for your entity and dto objects. That will generate the getters, setters, equals/hashCode, toString, etc. And use mapstruct for the mapping between DTO and entity classes. Thus you can drop lombok.
  2. Define one pass of the compiler for your java code as you would normally do for lombok and mapstruct. Define a second compiler pass that uses groovy-eclipse-compiler and the -proc:none argument to disable APT processing. This way, you can use lombok and mapstruct freely in your java sources. Depending on how you set this up, you may need to disable warnings on the first pass. And your java sources may not be able to depend on your groovy sources -- not bad if you use Groovy for tests. Is groovy-eclipse project compatible with checker-framework? #799 has an example POM with 2 compiler phases defined.

@eric-milles
Copy link
Member

This discussion may be relevant as well: projectlombok/lombok#1359

@fvanhille
Copy link
Author

Thank you for the information,
Since I set Groovy in my project for tests only I separated the configurations in 2 phases as you suggested and it works like a charm.

@rbastiaansen732
Copy link

rbastiaansen732 commented Oct 1, 2019

I am running into the same issue. I hope in the future there will be support for lombok and mapstruct at the same time without any workarounds.

I think I will try to move my code with dependencies on lombok and groovy-eclipse into a separate internal library where my main project will depend upon.

Thanks for the good work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants