如何使用ModelMapper基于源值而不是其类型创建条件转换器?

时间:2018-08-08 14:12:45

标签: java mapping modelmapper

我正在尝试使用ModelMapper将实体映射到DTO。当未加载@JoinColumn(延迟加载)时,就会出现问题。 ModelMapper尝试访问延迟加载实体的属性,然后引发LazyInitializationException。

我已经有解决此问题的策略,但是我找不到一个可以满足我需要的ModelMapper功能。

这是我需要做的: 对于每个未加载的实体,我将使用工厂创建一个新的目标对象。如果加载了对象,则必须应用默认映射。

下面的示例是一个ModelMapper功能,如果它不提供源代码(仅提供源代码类型)而不能完全满足我的需求,则可以:

public static class MyConverter implements ConditionalConverter<Object, Object> {

    private EntityManager em;

    public MyConverter(EntityManager em) {
        this.em = em;
    }

    @Override
    public MatchResult match(Class<?> sourceType, Class<?> destinationType) {
        Object source = null; // I need the source instead of its type.
        PersistenceUnitUtil persistenceUnitUtil = em.getEntityManagerFactory().getPersistenceUnitUtil();
        return persistenceUnitUtil.isLoaded(source) ? MatchResult.NONE : MatchResult.FULL;
    }

    @Override
    public Object convert(MappingContext<Object, Object> context) {
        return LazyEntityProxyFactory.factory(context.getSource(), context.getDestinationType()); // Creates the target object
    }
}

你们提供我需要的任何ModelMapper功能吗?还是黑客?

* Obs:我研究了ModelMapper的代码,并注意到调用ConditionalConverter.match时上下文已经存在,因此拥有源。如果ModelMapper还具有ConditionalContextConverter接口,该接口在match方法中传递上下文,该怎么办?只是一个主意。

1 个答案:

答案 0 :(得分:0)

我刚刚找到了我所需要的!秘密是从父实体检查属性。之后,我可以利用默认映射,并在需要时使用自己的工厂。

这是我的ConditionalConverter:

public static class MyConverter implements ConditionalConverter<Object, Object> {

    private EntityManager em;

    public MyConverter(EntityManager em) {
        this.em = em;
    }

    @Override
    public MatchResult match(Class<?> sourceType, Class<?> destinationType) {
        return MatchResult.FULL;
    }

    @Override
    public Object convert(MappingContext<Object, Object> context) {
        Object source = context.getSource();
        Object destination = context.getMappingEngine().createDestination(context);

        try {
            Field[] sourceFields = context.getSourceType().getDeclaredFields();
            Field[] destinationFields = context.getDestinationType().getDeclaredFields();
            for (Field sourceField : sourceFields) {
                sourceField.setAccessible(true);
                for (Field destinationField : destinationFields) {
                    destinationField.setAccessible(true);
                    if (sourceField.getName().equals(destinationField.getName())) {
                        Object sourceFieldValue = sourceField.get(source);

                        PersistenceUnitUtil persistenceUnitUtil = em.getEntityManagerFactory().getPersistenceUnitUtil();
                        if (persistenceUnitUtil.isLoaded(sourceFieldValue)) {
                            MappingContext<?, ?> myContext = context.create(sourceFieldValue, destinationField.getType());
                            Object destinationValue = context.getMappingEngine().map(myContext);
                            destinationField.set(destination, destinationValue);
                        } else {
                            // Here is your factory call;
                            destinationField.set(destination, SomeFactory.factory(sourceFieldValue, destinationField.getType()));
                        }
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return destination;
    }
}