Why the Order of annotationProcessor Matters
Gradle runs annotation processors in the same order they appear in yourbuild.gradle
file.
Consider this example:
dependencies {
annotationProcessor("org.mapstruct:mapstruct-processor:1.5.5.Final")
annotationProcessor("org.projectlombok:lombok:1.18.34")
}
What Happens When MapStruct Runs First?
- MapStruct runs first: It tries to generate mappers by accessing methods like
getId()
andgetUserName()
, but these methods are not yet available because Lombok hasn’t generated them. - Compilation Error: When MapStruct tries to create the mapper, it looks for methods like
getId()
andgetUserName()
. But since Lombok hasn’t generated them yet, MapStruct gets confused and can’t do its job.
When MapStruct runs before Lombok, you might encounter an error like this during compilation:
warning: Unmapped target properties: "id, userName".
UserDTO mapToUserDto(User user);
and generated class as:
public class UserMapperImpl implements UserMapper {
@Override
public UserDTO mapToUserDto(User user) {
if ( user == null ) {
return null;
}
// only initialization with null values
Long id = null;
String userName = null;
UserDTO userDTO = new UserDTO( id, userName );
return userDTO;
}
}
Lombok must finish building its parts (likegetters
andsetters
) before MapStruct can build the final product. If MapStruct starts too early, it won't have all the necessary pieces.
The Correct Order
To avoid this issue, you should declare your dependencies in the following order:
dependencies {
annotationProcessor("org.projectlombok:lombok:1.18.34")
annotationProcessor("org.mapstruct:mapstruct-processor:1.5.5.Final")
}
In this case:
- Lombok runs first, generating the necessary methods.
- MapStruct then uses the generated code to create mappers successfully.
And generated implementation is correct:
public class UserMapperImpl implements UserMapper {
@Override
public UserDTO mapToUserDto(User user) {
if ( user == null ) {
return null;
}
Long id = null;
String userName = null;
// Lombok-generated getters will be used here
id = user.getId();
userName = user.getUserName();
UserDTO userDTO = new UserDTO( id, userName );
return userDTO;
}
}