简体   繁体   English

Mapstruct 双向映射

[英]Mapstruct bidirectional mapping

I have the following example in which i have a separate domain layer and a separate persistence layer.我有以下示例,其中我有一个单独的域层和一个单独的持久层。 I am using Mapstruct for mapping and I get StackOverflow when mapping from domain to entity or from entity to domain because of the bidirectional reference that always gets called on -> infinite loop scenario.我使用 Mapstruct 进行映射,当从域映射到实体或从实体映射到域时,我得到 StackOverflow,因为双向引用总是被调用 -> 无限循环场景。 How can I use Mapstruct for this scenario?如何在这种情况下使用 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;
}

class for mapping is pretty basic映射类非常基础

@Mapper
interface UserMapper {

UserEntity mapToEntity(User user);

User mapToDomain(UserEntity userEntity);
}

Check out the Mapstruct mapping with cycles example.查看带有循环示例的Mapstruct 映射

A solution to your problem is also demonstrated in the documentation for Context annotation .您的问题的解决方案也在Context annotation 的文档中进行了演示。

Example例子

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

Reference参考

Mapper:映射器:

@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);
}

where CycleAvoidingMappingContext keeps track of the already mapped objects and reuses them avoiding the stack overflow:其中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 usage (mapping single object):映射器用法(映射单个对象):

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

You can also add a default method on your mapper:您还可以在映射器上添加默认方法:

@Mapper
public interface UserMapper {

    // (...)

    default UserEntity mapToEntity(User user) {
        return mapToEntity(user, new CycleAvoidingMappingContext());
    }

    // (...)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM