当前位置: 首页 > 知识库问答 >
问题:

ModelMapper:如何映射作为泛型传递的List?

盖博简
2023-03-14

我有一个抽象类:

public abstract class AbstractBeanDTO<T> extends AbstractBigDTO {
protected T value;

//getter setter 
}

扩展类具有泛型类型列表

public class ItemsBeanDTO extends AbstractBeanDTO<List<String>> {
}

我试图将模型类映射到也具有相同结构的DTO。

AbstractBeanDTO<?> dto =  (AbstractBeanDTO<?>) modelMapper.map(modelBean, ItemsBeanDTO.class);

我的modelMapper配置为与strict匹配。它能够转换其他泛型类型,如Long、Integer、String,但不能转换List。

我得到以下错误:

org.modelmapper.MappingException: ModelMapper mapping errors:

1) Failed to instantiate instance of destination java.util.List. Ensure that java.util.List has a non-private no-argument constructor.
Caused by: java.lang.NoSuchMethodException: java.util.List.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at org.modelmapper.internal.MappingEngineImpl.instantiate(MappingEngineImpl.java:333)
    at org.modelmapper.internal.MappingEngineImpl.createDestination(MappingEngineImpl.java:348)
    at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:141)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:115)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:59)
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31)
    at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110)
    at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242)
    at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188)
    at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:115)
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:72)
    at org.modelmapper.ModelMapper.mapInternal(ModelMapper.java:573)
    at org.modelmapper.ModelMapper.map(ModelMapper.java:406)

我试图使用TypeMap明确地映射它,但它是相同的。

modelMapper.createTypeMap(ItemsBean.class, ItemsBeanDTO.class).addMappings(mapper -> {
            mapper.map(src -> src.getValue(), (dest, value) -> dest.setValue((List<String>) value));
        });

唯一有效的方法是将变量显式声明为List。(但我不想这么做)

我正在使用ModelMapper和Java8的2.3.5版本。谁能帮我一下这是怎么回事?

我试着使用typeMap和typeToken,如下所示,

Type listType = new TypeToken<ItemsBeanDTO>() {
        }.getType();

modelMapper.createTypeMap(ItemsBean.class, ItemsBeanDTO.class).addMappings(mapper -> {
        mapper.map(src -> src.getValue(), (dest, value) -> dest.setValue(modelMapper.map(value, listType)));
});

在这种情况下,我得到以下错误:

java.lang.IllegalArgumentException: source cannot be null
    at org.modelmapper.internal.util.Assert.notNull(Assert.java:53)
    at org.modelmapper.ModelMapper.map(ModelMapper.java:493)
    at com.lowteq.model.preop.controller.config.BeanModelMapperFactory.lambda$22(BeanModelMapperFactory.java:117)
    at org.modelmapper.internal.ReferenceMapExpressionImpl.map(ReferenceMapExpressionImpl.java:68)
    at org.modelmapper.internal.ConfigurableConditionExpressionImpl.map(ConfigurableConditionExpressionImpl.java:65)
    at com.lowteq.model.preop.controller.config.BeanModelMapperFactory.lambda$20(BeanModelMapperFactory.java:117)
    at org.modelmapper.internal.TypeMapImpl.addMappings(TypeMapImpl.java:266)

共有3个答案

薄龙光
2023-03-14

你可以用我的图书馆beanknife代替。它是一个注释处理器。这意味着它可以动态生成DTO类。您可以检查生成的类的源代码,没有更多的魔力。转换器方法嵌入到生成的类中。它们并不复杂,但很麻烦,因此需要自动化。您可以过滤从原始类继承的属性,甚至可以更改或向生成的类添加新属性。该库提供了一种仅通过注释转换特性的方法。例如,如果整数为空,则将其转换为零。您还可以编写自己的实现。

例如:

class Pojo1 {
    String a;
    Pojo b;
}

class Pojo2 {
    Pojo1 a;
    List<Pojo1> b;
    Map<List<Pojo1>>[] c;
}

// target Pojo1, and all properties will be included except 'b'
@ViewOf(value = Pojo1.class, includePattern = ".*", excludes={Pojo1Meta.b})
class ConfigureOfPojo2 {}

// target Pojo2, and all properties will be included
@ViewOf(value = Pojo2.class, includePattern = ".*")
class ConfigureOfPojo2 {
    // convert b to dto version. 
    // Pojo1View is the generated dto class of Pojo1.
    // Of course, you can change it. But here use the default name for simpify.
    // If you want change the type or value of a existing property,
    // You should use @OverrideViewProperty.
    // Convert to dto version is internal supported.
    // For more complex case, you may need to use a method to define how the property should be deal with.
    @OverrideViewProperty(Pojo2Meta.b)
    private List<Pojo1View> b;

    // Convert c to dto version
    // BeanKnife support convert list, set, map, array of object to its dto version, only if they has the same shape.
    @OverrideViewProperty(Pojo2Meta.c)
    private Map<List<Pojo1View>>[] c;
}

会产生

// meta class, you can use it to reference the property name in a safe way.
class Pojo1Meta {
    public final String a = "a";
    public final String b = "b";
}

// generated DTO class. The actual one will be more complicate, there are many other method.
class Pojo1View {
    private String a;
    public Pojo1View read(Pojo1 source) { ... }
    ... getters and setters ...
}

class Pojo2Meta {
    public final String a = "a";
    public final String b = "b";
    public final String c = "c";
}

class Pojo2View {
    private String a;
    private List<Pojo1View> b;
    private Map<List<Pojo1View>>[] c;
    public Pojo2View read(Pojo2 source) { ... }
    ... getters and setters ...
}

这里有更多的例子

壤驷乐邦
2023-03-14

最后我找到了这个问题的解决方案。您可以使用typeMap跳过设置列表的setter方法,并使用setProvider手动设置列表。

TypeMap<ItemsBean, ItemsBeanDTO> typeMap = modelMapper.createTypeMap(ItemsBean.class,
                ItemsBeanDTO.class);

        typeMap.addMappings(mapper -> mapper.skip(ItemsBeanDTO::set));

        typeMap.setProvider(request -> {
            ItemsBean source = ItemsBean.class.cast(request.getSource());
            ItemsBeanDTO destination = new ItemsBeanDTO();
            destination.set(source.get());
            return destination;
        });
冀胤运
2023-03-14

ModelMapper需要一个具体类,因此您需要首选List的实现,包括ArrayListLinkedList等。

 类似资料:
  • 我想将泛型类型<code>Y</code>的对象映射到另一个泛型类型为<code>X</code>的对象。在mapstruct中有这样的功能吗?或者我必须为通用映射编写自定义映射器吗?当我编译上面的代码时,会出现编译错误。

  • 我与ModelMapper框架有麻烦。请解释为什么我看到以下行为。 我在build.gradle有以下依赖性 和一个类客户: 我还有一个地图绘制工具: 还有一个测试 在fred()中,方法输出是非红色的“Customer{name=fred,age=40}”(“Customer{name=null,age=40}”)。你能解释一下为什么吗?为什么我在第一个方法中看不到输出“George”?

  • 我有一个父类和子类,其各自的DTO如下 当我试图将父映射到父映射到父映射到父映射时,我得到了堆栈溢出错误。 请帮我解决这个问题。

  • 我正在尝试使用ModelMapper映射对象树。 我创建了一个例子来说明我的问题: 类包含多个属性 类包含类型为Sub的对象和(至少)另一个属性 类目标包含一个简单的属性列表 源属性和目标属性的类型不同 代码: 我正在寻找一种配置单个ModelMapper实例的方法,以便满足以下约束: modelMapper能够将Sub类型的对象转换为目标对象 不幸的是,行<代码>映射(source.sub,de

  • 我需要验证一个Map值是否为null,因为我经常使用集合,愿意实现验证Map值的通用方法,所以尝试了这个 有没有人能帮助我更深入地理解这个逻辑。

  • 我写了以下方法 我如何将不同的枚举类型传递给第二个参数?我知道我不能创建枚举的实例,但初始化枚举意味着我将传递一个值,而不是整个初始化的枚举,如下所示...其他枚举也将传递给相同的方法以实现组合细节