Fixing MapStruct and Lombok Integration Issues in IntelliJ IDEA (2025 Guide)

If you have used MapStruct and Lombok, you might have faced an issue where classes annotated with Lombok annotations are not recognized by MapStruct. As a result, MapStruct fails to generate field mappings during compilation.

Let’s first explore this issue with the help of some code. I’ll be using IntelliJ IDEA for this example.

First, add the Lombok and MapStruct dependencies to your build.gradle file.

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.5.6'
	id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.abc.xyz'
version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(21)
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.mapstruct:mapstruct:1.6.3'
	annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.3'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'

	implementation 'org.springframework.boot:spring-boot-starter-web'

	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
	useJUnitPlatform()
}


Now let’s create the User entity and the UserRequestDTO POJO.

@Entity
@Table(name = "tb_user")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(unique = true, nullable = false)
    private String name;
    private String firstName;
    private String lastName;
    @Column(unique = true, nullable = false)
    private String email;
}
@Data
public class UserRequestDTO{
    private String name;
    private String firstName;
    private String lastName;
    private String email;
}


Now let’s create a mapper that will help convert UserRequestDTO to a User entity.

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface UserMapper {
    User map(UserRequestDTO userRequestDTO);
}

When we build our application using the gradle clean buildcommand and check the generated mapper class, it looks like the following.

( If you’re not sure where to find it, look for thebuildfolder in your project directory — it is created automatically once the build completes. You can navigate to: build > classes > java > [path of the package where your mapper is located] )

@Component
public class UserMapperImpl implements UserMapper {
    public UserMapperImpl() {
    }

    public User map(UserRequestDTO userRequestDTO) {
        if (userRequestDTO == null) {
            return null;
        } else {
            User user = new User();
            return user;
        }
    }
}

Here, you can clearly see that there is no field mapping with the User entity — it only creates a new instance of it. This indicates that there’s likely a configuration issue between Lombok and MapStruct.

Let’s explore further to identify the cause.

First, let’s check whether Lombok is generating the getters and setters in the compiled class files.

In my case, since I’m using the @Data annotation, I can see that the generated class includes getter, setter, equals, and hashCode methods. This means Lombok is working correctly.

If these methods are missing, then it’s an issue with Lombok’s annotation processing — possibly because annotation processing is not enabled in your IDE settings.

In my case, annotation processing was already enabled, yet I was still facing the issue.

We also verified that MapStruct successfully generated the mapper class; however, it failed to detect the fields. This means MapStruct itself is also working fine.

So, what’s actually causing the problem?

Let’s try adding manual getters and setters to the User entity and UserRequestDTO POJO, then rebuild the application.

This time, in the generated mapper file, we can see that the field mappings are present, as shown below.

@Component
public class UserMapperImpl implements UserMapper {
    public UserMapperImpl() {
    }

    public User map(UserRequestDTO userRequestDTO) {
        if (userRequestDTO == null) {
            return null;
        } else {
            User user = new User();
            user.setName(userRequestDTO.getName());
            user.setFirstName(userRequestDTO.getFirstName());
            user.setLastName(userRequestDTO.getLastName());
            user.setEmail(userRequestDTO.getEmail());
            return user;
        }
    }
}

This means that during MapStruct’s processing, the getter and setter methods generated by Lombok were not yet available.

Now, let’s add one more dependency to resolve this issue: annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'

After adding it, your build.gradle file will look like the following:

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.5.6'
	id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.abc.xyz'
version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(21)
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.mapstruct:mapstruct:1.6.3'
	annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.3'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	
		annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'

	implementation 'org.springframework.boot:spring-boot-starter-web'

	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
	useJUnitPlatform()
}


Remove the manually added getters and setters from the User entity and UserRequestDTO POJO, and rely solely on Lombok annotations such as @Data or @Getter/@Setter.

@Data
public class UserRequestDTO{
    private String name;
    private String firstName;
    private String lastName;
    private String email;
}
@Entity
@Table(name = "tb_user")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(unique = true, nullable = false)
    private String name;
    private String firstName;
    private String lastName;
    @Column(unique = true, nullable = false)
    private String email;
}

After this, build the project using gradle clean build and check the generated mapper class file.

This resolves the issue, and you should now see the field mappings present in the generated mapper class.

@Component
public class UserMapperImpl implements UserMapper {
    public UserMapperImpl() {
    }

    public User map(UserRequestDTO userRequestDTO) {
        if (userRequestDTO == null) {
            return null;
        } else {
            User user = new User();
            user.setName(userRequestDTO.getName());
            user.setFirstName(userRequestDTO.getFirstName());
            user.setLastName(userRequestDTO.getLastName());
            user.setEmail(userRequestDTO.getEmail());
            return user;
        }
    }
}

If you have any questions, please leave them in the comments, and I’ll try my best to answer them.

Comments

Post a Comment