Mapstruct: 1.3.0.final. When a mapperImpl uses a builder beforemapping and aftermapping do not appear in the code.

Created on 24 May 2019  路  2Comments  路  Source: mapstruct/mapstruct

We want to upgrade from 1.2.0.final to 1.3.0.final. We have 33 mappers in total, the generated code is checked into Git. Hence this makes it very easy to check the diff between 1.2.0 and 1.3.0 generated code. We have 5 mappers which use @AfterMapping. Three of them cause unit-tests for the generated mappers to fail. Did some digging and the failing MapperImp files are those which do use our manually created builders. It turns out that in the generated MapperImpl files calls for beforemapping and aftermapping do not exist. They do exist in the generated 1.2.0 files - which can't handle our builders.

I can reproduce the error with a very small mapper for which I've created a github gist. In file TelephoneBuilder I've disabled the build method and the generated code has beforemapping and aftermapping - included in the gist. By enabling the build method and generating code again you will notice that the builder is being used AND the beforemapping and aftermapping do disappear.

I've tried to disable the builders as I've read in the reference guide. We have a multi-project Gradle setup. In the project where the mappers are used I've created the following file: ./src/main/java/META-INF/services/org.mapstruct.ap.spi.BuilderProvider. Contents: org.mapstruct.ap.spi.NoOpBuilderProvider. removed src/main/generatedJava and created the mappers again. No difference, the builders are still being used. Did I place the file in the wrong place......

I've also tried "13.3. Custom Builder Provider" approach. In the generated NoOpBuilderProvider file BuilderProvider and BuilderInfo Eclipse complains with "BuilderProvider cannot be resolved to a type". The build.gradle file for the subproject contains:
ext.libraries = [
//mapstruct_jdk8: "org.mapstruct:mapstruct-jdk8:'1.3.0.Final'", // JDK for 1.2.0.final
mapstruct_jdk8: "org.mapstruct:mapstruct:'1.3.0.Final'",
mapstruct_processor: "org.mapstruct:mapstruct-processor:'1.3.0.Final'",
]
dependencies{
compileOnly libraries.mapstruct_jdk8
annotationProcessor libraries.mapstruct_processor
}. _See also https://github.com/mapstruct/mapstruct-examples/issues/66 for our Gradle 5 complete setup._

I hope you can use my example code to figure out what is going on. Perhaps its the way we create our builders or its a shortcoming in mapstruct.

Most helpful comment

Thanks for the reply and your suggestions.

Decided to upgrade from 1.2.0.final to 1.3.0.final on our develop branch, which has gradle 4.10.2. The setup for this is totally different, a hybrid form of the old and new setup found on your website. No idea why its setup in this way but it works. See this Github gist should you be interested in it.

For Gradle 5 we were forced to use annotationProcessor to get things working. With Gradle 4.10.2 and mapstruct 1.3.0.final I'm getting of course the same failing unit tests. Tried again both methods to disable using the builders, both to no avail. Also getting the same errors wrt NoOpBuilderProvider.

It looks as if something else is in play and not necessarily the annotationProcessor causing the problem (not being able to disable the builders) for us. Very curious if/how others have gotten disabling the builders to work.

The dev team has decided to stay for now with 1.20.final. Almost holiday so will check in a 2-3 weeks to see if any progress has been made and perhaps an RC for 1.4.0 has been released. Hoping the code supplied can help you further.

All 2 comments

Thanks for the detailed report @bessels. It really helps to analyse the error.

I think the reason why you have the error is due to #1454 (if builders are used then the @AfterMapping and @BeforeMapping on the type being build won't be called).

One way to solve this would be with the help of the #1811 PR. One other option is the implementation of #1661 and for us to add an annotation processor option to disable builder support.

I think that the reason why your usage of NoOpBuilderProvider is not working is due to the fact that your file is in your sources. However, Gradle puts the processor on the annotationProcessor path which means that the file won't be picked up. You can try to create a different module and put it with scope annotationProcessor and it would work (I think). There are some other similar issues that have the similar problem with Maven.

Thanks for the reply and your suggestions.

Decided to upgrade from 1.2.0.final to 1.3.0.final on our develop branch, which has gradle 4.10.2. The setup for this is totally different, a hybrid form of the old and new setup found on your website. No idea why its setup in this way but it works. See this Github gist should you be interested in it.

For Gradle 5 we were forced to use annotationProcessor to get things working. With Gradle 4.10.2 and mapstruct 1.3.0.final I'm getting of course the same failing unit tests. Tried again both methods to disable using the builders, both to no avail. Also getting the same errors wrt NoOpBuilderProvider.

It looks as if something else is in play and not necessarily the annotationProcessor causing the problem (not being able to disable the builders) for us. Very curious if/how others have gotten disabling the builders to work.

The dev team has decided to stay for now with 1.20.final. Almost holiday so will check in a 2-3 weeks to see if any progress has been made and perhaps an RC for 1.4.0 has been released. Hoping the code supplied can help you further.

Was this page helpful?
0 / 5 - 0 ratings