gpt4 book ai didi

java - ModelMapper:使用带有自定义映射的 TypeMap 时,如何使转换器在映射器级别注册

转载 作者:行者123 更新时间:2023-12-04 01:15:10 24 4
gpt4 key购买 nike

我使用 ModelMapper 将模型转换为 DTO。我有一堆空值的默认转换器,它们已在映射器级别注册,如下所示:

        modelMapper.addConverter(new Converter<String, String>() {
@Override
public String convert(MappingContext<String, String> context) {
if (context.getSource() == null) {
return "global null converter was here";
}
return context.getSource();
}
});

当属性名称在转换的两端相同时,这对于简单映射可以很好地工作。转换器用于按预期处理空值。

现在,如果我需要通过在类型映射上使用 .map(getter, setter) 对不同的属性名称进行更复杂的转换,则不再调用全局转换器。我不希望在配置类型映射时丢弃全局转换器。

我该如何解决?

下面是使用 ModelMapper 2.3.8(今天的最新版本)的示例代码(为代码简洁而使用 lombok):

@Data @AllArgsConstructor @NoArgsConstructor class A { String a; String b;}

@Data @AllArgsConstructor @NoArgsConstructor class B { String a; String b; }

@Data @AllArgsConstructor @NoArgsConstructor class C { String x; String y;}

public class MapperTestCase {


public static void main(String[] args) throws IOException {

A a = new A("aaa", "bbb");

ModelMapper modelMapper = new ModelMapper();
final TypeMap<A, B> AtoBTypeMap = modelMapper.createTypeMap(A.class, B.class);
B b = AtoBTypeMap.map(a);
System.out.println("conversion with no converter A -> B: " + a + " -> " + b);

a = new A(null, null);
b = AtoBTypeMap.map(a);
System.out.println("conversion with no converter A -> B: " + a + " -> " + b);

// Add a global/fallback converter that should convert all null String values.
modelMapper.addConverter(new Converter<String, String>() {
@Override
public String convert(MappingContext<String, String> context) {
if (context.getSource() == null) {
return "global null converter was here";
}
return context.getSource();
}
});

final TypeMap<B, A> BtoATypeMap = modelMapper.typeMap(B.class, A.class);
a = BtoATypeMap.map(b);
System.out.println("conversion with global converter B -> A: " + b + " -> " + a);

// add a local converter for the B to C type mape only
BtoATypeMap.addMappings(mapper -> mapper.using(ctx -> {
if (ctx.getSource() == null) {
return "local converter was here";
} else return ctx.getSource();
}).map(B::getA, (w, x) -> w.setA(String.valueOf(x))));

// in this conversion both converter (global and local) should be used
a = BtoATypeMap.map(b);
System.out.println("conversion with global and local converter B -> A: " + b + " -> " + a);

// a new typeMap that will transform a B into a C, mapping B::a to C::x and B::b to C::y
final TypeMap<B, C> BtoCTypeMap = modelMapper.typeMap(B.class, C.class);

// a local converter for this type map
BtoCTypeMap.addMappings(mapper -> mapper.using(ctx -> {
if (ctx.getSource() == null) {
return "local converter was here";
} else return ctx.getSource();
}).map(B::getA, (w, x) -> w.setX(String.valueOf(x))));

BtoCTypeMap.addMapping(B::getB, C::setY);
// first a conversion with a B instance without null values, works as expected
b = new B("some", "data");
C c = BtoCTypeMap.map(b);
System.out.println("conversion with global and local converter B -> C: " + b + " -> " + c);

// now a conversion with a B instance wirth null values, the local converer will be used, but not the global one defined at the mapper level. Why ?
b = new B();
c = BtoCTypeMap.map(b);
System.out.println("conversion with global and local converter B -> C: " + b + " -> " + c);
}
}

输出是:

conversion with no converter A -> B: A(a=aaa, b=bbb) -> B(a=aaa, b=bbb)
conversion with no converter A -> B: A(a=null, b=null) -> B(a=null, b=null)
conversion with global converter B -> A: B(a=null, b=null) -> A(a=global null converter was here, b=global null converter was here)
conversion with global and local converter B -> A: B(a=null, b=null) -> A(a=local converter was here, b=global null converter was here)
conversion with global and local converter B -> C: B(a=some, b=data) -> C(x=some, y=data)
conversion with global and local converter B -> C: B(a=null, b=null) -> C(x=local converter was here, y=null)

最后一行的预期输出是 C(x=local converter was here, y=global null converter was here)

最佳答案

如果你想创建通用的 propertyConverter,你可以尝试这样的东西

        Converter<String, String> stringPropertyConverter = new Converter<String, String>() {
@Override
public String convert(MappingContext<String, String> context) {
if (context.getSource() == null) {
return "global null converter was here";
}
return context.getSource();
}
};

ModelMapper modelMapper = new ModelMapper() {
@Override
public <S, D> TypeMap<S, D> typeMap(Class<S> sourceType, Class<D> destinationType) {
TypeMap<S, D> typeMap = super.typeMap(sourceType, destinationType);
typeMap.setPropertyConverter(stringPropertyConverter);
return typeMap;
}

};

在映射过程中使用的顺序转换器通常会出现问题。首先 modelMapper 为您的类定义转换器,下一步它会为类的字段搜索合适的转换器。在第一种情况下,您的转换器已按顺序放置

"TypeMap[String -> String]"
"TypeMap[B -> A]"
"TypeMap[A -> B]"

第二种情况

"TypeMap[B -> C]"
"TypeMap[String -> String]"
"TypeMap[B -> A]"
"TypeMap[A -> B]"

转换器 B 到 C 适合您类(class)中任何领域的转换器。

关于java - ModelMapper:使用带有自定义映射的 TypeMap 时,如何使转换器在映射器级别注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63593503/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com