Cannot map nested @Data with MapStruct
Asked Answered
L

3

7

When trying to map nested Object using @Data and @Builder, mapStruct throw the following errors: "No read accessor found for property "profile" in target type."

@Mapper(componentModel = "spring")
public interface AuthMapper {

  // only for testing mapping is working
  @Mapping(target = "profile.organization", source = "organization")
  RequestCreateOktaUser toEntity(Integer organization);

  // only for testing mapping is working
  @Mapping(target = "profile.login", source = "request.profile.email")
  RequestCreateOktaUser toEntity(RequestMobilePreRegisterLocation.User request);
  
  // Throw error "No read accessor found for property "profile" in target type" at compile time
  @Mapping(target = "profile.organization", source = "organization")
  @Mapping(target = "profile.login", source = "request.profile.email")
  RequestCreateOktaUser toEntity(RequestMobilePreRegisterLocation.User request, Integer organization);

}

Model using Lombok simplified for simplicity

@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class RequestCreateOktaUser {

  private Profile profile;

  @Data
  @NoArgsConstructor
  @AllArgsConstructor(access = AccessLevel.PRIVATE)
  @Builder
  public static class Profile {
    private String login;
    private String email;
    private Integer organization;
  }

}
@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class RequestMobilePreRegisterUser {

  @Valid
  private User user;


  @Data
  @NoArgsConstructor
  @AllArgsConstructor(access = AccessLevel.PRIVATE)
  @Builder
  public static class User {

    @Valid
    private Profile profile;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    @Builder
    public static class Profile {

      @NotEmpty
      @Email
      private String email;

    }

}

The two first Mapping are working as expected, but when trying to combine the two the following errors is being thrown at compile time "No read accessor found for property "profile" in target type."

If someone could help me on this one I would really appreciate.

Thanks a lot,

Jonathan.

Lanai answered 9/10, 2020 at 21:37 Comment(0)
L
33

solution:

@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = true))
Lanai answered 9/10, 2020 at 22:17 Comment(1)
I've come across the very same issue when upgrading Lombok from 1.18.20 to 1.18.22. I've tried adding lombok-mapstruct-binding, changing the annotation-processor declarations order...nothing worked. I struggle to understand the issue itself. Why is it different for an inner class ? It works perfectly fine with simple classes with @data and @builder. I'd like to make it work with the builder annotation instead of ignoring it. Is there a way to configure the entity or the mapper that works ?Shoring
L
1

Instead of ignoring the builder, we can add another mapper, say ProfileMapper and then in the 'parent mapper' (e.g UserMapper) you can use mapper annotation like this

@Mapper(uses = {ProfileMapper.class})
interface UserMapper {
...
}
Lawrence answered 13/3, 2023 at 9:6 Comment(0)
A
-1

The best thing to do is avoiding nested mappings. You may have separate method for nested mappings. so you can have a method to convert nested types first. for example user to profile. Then you can use expression to let mapstruct know which method it uses for nested mapping (not sure even if it's needed)

And if you have something else to map to the Profile (like organization) which is not part of nested source, you can use @AfterMapping

Acreage answered 5/3, 2024 at 2:2 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.