【问题标题】:Mapstruct bidirectional mappingMapstruct 双向映射
【发布时间】:2020-05-10 16:55:54
【问题描述】:

我有以下示例,其中我有一个单独的域层和一个单独的持久层。我正在使用 Mapstruct 进行映射,并且在从域映射到实体或从实体映射到域时得到 StackOverflow,因为总是在 -> 无限循环场景中调用双向引用。在这种情况下如何使用 Mapstruct?

class User {
  private UserProfile userProfile;
}

class UserProfile {
 private User user;
}

@Entity
class UserEntity {
  @OneToOne
  @PrimaryKeyJoinColumn
  private UserProfileEntity userProfile;
}

@Entity
class UserProfileEntity {
  @OneToOne(mappedBy = "userProfile")
  private UserEntity userEntity;
}

映射类非常基础

@Mapper
interface UserMapper {

UserEntity mapToEntity(User user);

User mapToDomain(UserEntity userEntity);
}

【问题讨论】:

    标签: java mapstruct


    【解决方案1】:

    查看Mapstruct mapping with cycles 示例。

    还演示了您的问题的解决方案in the documentation for Context annotation

    示例

    一个完整的例子:https://github.com/jannis-baratheon/stackoverflow--mapstruct-mapping-graph-with-cycles

    参考

    映射器:

    @Mapper
    public interface UserMapper {
    
        @Mapping(target = "userProfileEntity", source = "userProfile")
        UserEntity mapToEntity(User user,
                               @Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
    
        @InheritInverseConfiguration
        User mapToDomain(UserEntity userEntity,
                         @Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
    
        @Mapping(target = "userEntity", source = "user")
        UserProfileEntity mapToEntity(UserProfile userProfile,
                                      @Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
    
        @InheritInverseConfiguration
        UserProfile mapToDomain(UserProfileEntity userProfileEntity,
                                @Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
    }
    

    CycleAvoidingMappingContext 跟踪已映射的对象并重复使用它们以避免堆栈溢出:

    public class CycleAvoidingMappingContext {
        private final Map<Object, Object> knownInstances = new IdentityHashMap<>();
    
        @BeforeMapping
        public <T> T getMappedInstance(Object source,
                                       @TargetType Class<T> targetType) {
            return targetType.cast(knownInstances.get(source));
        }
    
        @BeforeMapping
        public void storeMappedInstance(Object source,
                                        @MappingTarget Object target) {
            knownInstances.put(source, target);
        }
    }
    

    Mapper 用法(映射单个对象):

    UserEntity mappedUserEntity = mapper.mapToEntity(user, new CycleAvoidingMappingContext());
    

    您还可以在映射器上添加默认方法:

    @Mapper
    public interface UserMapper {
    
        // (...)
    
        default UserEntity mapToEntity(User user) {
            return mapToEntity(user, new CycleAvoidingMappingContext());
        }
    
        // (...)
    }
    

    【讨论】:

    • 我喜欢参考return mapToEntity(user, new CycleAvoidingMappingContext());的默认方法。然而,这导致了ambiguous 错误消息。我必须添加一个@Qualifier,就像here 描述的那样。我在所有新的默认方法中添加了@DoIgnore。之后一切正常。
    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 2016-04-19
    • 2020-08-02
    • 2023-03-29
    • 2021-11-22
    • 2015-11-12
    • 2021-08-03
    • 2020-04-07
    相关资源
    最近更新 更多