1

Why isn't my MapStruct mapper populating my entity objects correctly?

I believe I'm doing everything correctly, but for some reason, the mapping doesn't seem to work. Here are the details of my setup:

  • Mapper Interface:

    @Mapper(
        componentModel = "spring",
        unmappedTargetPolicy = ReportingPolicy.IGNORE,
        unmappedSourcePolicy = ReportingPolicy.IGNORE
    )
    public interface UserTaskMapper {
        UserTask toEntity(UserTaskRequest userTaskRequest);
        UserTaskResponse toResponse(UserTask userTask);
    }
    
  • Entity Class:

    @Entity
    @Getter
    @Setter
    @RequiredArgsConstructor
    @Table(name = "user_tasks")
    public class UserTask {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @ManyToOne
        @JoinColumn(name = "user_id", nullable = false)
        private User user;
    
        @ManyToOne
        @JoinColumn(name = "task_id", nullable = false)
        private Task task;
    
        private Boolean isCompleted;
        private String projectUrl;
        private LocalDateTime submittedAt;
    }
    
  • Request DTO:

    @Getter
    @Setter
    public class UserTaskRequest {
        private Long taskId;
        private Set<Long> userIds;
        private Boolean isCompleted = false;
        private String projectUrl;
    }
    
  • Response DTO:

    @Getter
    @Setter
    public class UserTaskResponse {
        private Long id;
        private Long userId;
        private TaskResponse task;
        private Boolean isCompleted;
        private String projectUrl;
        private LocalDateTime submittedAt;
    }
    
  • Generated Mapper Implementation:

    @Generated(
        value = "org.mapstruct.ap.MappingProcessor",
        date = "2025-05-03T19:59:56+0400",
        comments = "version: 1.6.3, compiler: IncrementalProcessingEnvironment from gradle-language-java-8.13.jar, environment: Java 17.0.14 (Amazon.com Inc.)"
    )
    @Component
    public class UserTaskMapperImpl implements UserTaskMapper {
    
        @Override
        public UserTask toEntity(UserTaskRequest userTaskRequest) {
            if (userTaskRequest == null) {
                return null;
            }
            UserTask userTask = new UserTask();
            return userTask;
        }
    
        @Override
        public UserTaskResponse toResponse(UserTask userTask) {
            if (userTask == null) {
                return null;
            }
            UserTaskResponse userTaskResponse = new UserTaskResponse();
            return userTaskResponse;
        }
    }
    

Here, the generated mapper is just returning empty objects without mapping any fields.

I've tried several fixes:

  1. Cleaning and rebuilding the project multiple times.
  2. Updating dependencies—I changed:
    implementation 'org.mapstruct:mapstruct:1.6.3'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.6.3'
    
    from version 1.5.5.Final. But this didn't resolve the issue.

Despite these efforts, the mapping still isn't working correctly. How can I fix this?

1 Answer 1

2

I think your issue is with the annotation processor flow. Both MapStruct and Lombok work on the annotated source code. MapStruct behaves nicely, and only generates new classes. Lombok doesn't generate new classes but instead modifies the existing class. That's something that annotation processors actually shouldn't do. The problem you're running into is that MapStruct doesn't see the changes made by Lombok. There is a way around this though, all documented at https://www.baeldung.com/java-mapstruct-lombok.

When you've fixed that you should have some more mappings, like for isCompleted and projectUrl. You need to help MapStruct with the mapping of taskId to task and userIds (why is this multiple?) to user (single). MapStruct has some documentation about that, see https://mapstruct.org/documentation/stable/reference/html/#passing-target-type. You may need to make use of some qualified mappings if MapStruct doesn't like the generic Long types.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the review! I've gone through all the documentation but still couldn't solve it. I'll use a builder for manual mapping and keep the mappers inactive for now. I'll investigate further to understand the issue and will update this question accordingly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.