如何使用@oneToMany映射对象包含其他对象

时间:2018-02-22 09:49:26

标签: java dozer mapstruct

给定如下定义的Source类:

class Person{
    private String name;
    private int age;
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "peroson")
    List<Phone> phones
    // getters and setters
}

和Phone类定义如下:

class Phone{
        private Long id;
        private String phoneNumber;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "person")
        private Person person;
        // getters and setters
    }

和DTO对象:

class PersonDTO{
        private String name;
        private int age;
        List<PhoneDTO> phones
        // getters and setters
    }

class PhoneDTO{
            private Long id;
            private String phoneNumber;
            private PersonDTO person;
            // getters and setters
        }

我有一个界面:

@Mapper(uses={PersonMapper.class})
interface PhoneMapper{
    PhoneDTO toDto(Phone source);
    Phone toEntity(PhoneDTO source);
}

 @Mapper(uses={PhoneMapper.class})
    interface PersonMapper{
        PersonDTO toDto(Person source);
        Person toEntity(PersonDTO source);
    }

当我使用PeronMapperPhoneMapper时会有递归调用,因为PersonMapper使用PhoneMapperPersonMapper使用PhoneMapper

如何解决?

1 个答案:

答案 0 :(得分:0)

有许多方法可以避免递归。

第一个选项:

避免在你的一个地图制作者中明确忽略

第二个选项:

使用@Context并编写自己的记忆。 mapstruct示例repo中有一个示例mapstruct-mapping-with-cycles

我们的想法是拥有@Context

public class CycleAvoidingMappingContext {
    private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();

    @BeforeMapping
    public <T> T getMappedInstance(Object source, @TargetType Class<T> targetType) {
        return (T) knownInstances.get( source );
    }

    @BeforeMapping
    public void storeMappedInstance(Object source, @MappingTarget Object target) {
        knownInstances.put( source, target );
    }
}

然后将此上下文的实例传递给您的映射器:

@Mapper(uses={PersonMapper.class})
interface PhoneMapper{
    PhoneDTO toDto(Phone source, @Context CycleAvoidingContext context);
    Phone toEntity(PhoneDTO source, @Context CycleAvoidingContext context);
}

@Mapper(uses={PhoneMapper.class})
interface PersonMapper{
    PersonDTO toDto(Person source, @Context CycleAvoidingContext context);
    Person toEntity(PersonDTO source, @Context CycleAvoidingContext context);
}

当然,CycleAvoidingMappingContext可以包含更多指定的来源,而不仅仅是Object。例如,您可以为PersonPersonDTO添加一个。由您决定如何实现它。