Orika:从字符串映射到一些对象的列表
Orika: Map from String to a List of SomeObjects
考虑以下情况:
public class A {
private String stringA;
public String getStringA() {
return stringA;
}
public void setStringA(String stringA) {
this.stringA = stringA;
}
}
public class B {
List<SomeObject> someObjects;
public List<SomeObject> getSomeObjects() {
if (someObjects == null) {
someObjects = new ArrayList<SomeObject>();
}
return someObjects;
}
}
public class SomeObject {
private String stringSomeObject;
public String getStringSomeObject() {
return stringSomeObject;
}
public void setStringSomeObject(String stringSomeObject) {
this.stringSomeObject = stringSomeObject;
}
}
我想从 A
映射到 B
。在映射这些时,stringA
需要映射到 SomeObject
中的 stringSomeObject
。我试图为此编写一个 Orika-Mapper:
public class MyMapper extends ConfigurableMapper {
@Override
protected void configure(MapperFactory factory) {
ConverterFactory converterFactory = factory.getConverterFactory();
converterFactory.registerConverter(new StringToSomeObjectConverter());
factory.classMap(A.class, B.class) //
.field("stringA", "someObjects") //
.byDefault() //
.register();
}
}
它将 class A
映射到 B
并且每当它遇到从 String
到 List<SomeObject>
的转换时它调用自定义转换器:
public class StringToSomeObjectConverter extends CustomConverter<String, List<SomeObject>> {
private static final String BORROWER_PARTY_TYP_CODE = "147";
@Override
public List<SomeObject> convert(String source, Type<? extends List<SomeObject>> destinationType) {
SomeObject someObject = new SomeObject();
someObject.setStringSomeObject(source);
return Arrays.asList(someObject);
}
}
我写了一个单元测试来确保它有效:
@Test
public void testMap() throws Exception {
A a = new A();
a.setStringA("a");
B outcome = new MyMapper().map(a, B.class);
assertThat(outcome.getSomeObjects.size(), is(1));
}
遗憾的是这个测试失败了:
java.lang.AssertionError:
Expected: is <1>
but: was <0>
似乎转换器从未执行过,所以我尝试调试它。事实上:调试器永远不会到达转换器。难道我做错了什么?这好像是。我知道还有更多方法可以使用,例如:mapAToB 例如...
好的,我找到了一个解决方案...不!这不是解决方案,只是一种解决方法。我也将 stringA
定义为 List<String>
,并定义了一个扩展 CustomConverter<String, LoanContrReqERPCrteReqLoanContrBrrwrPty>
的转换器。
因为这感觉有点"hacky",我还是对一个不错的解决方案感兴趣。 (虽然我只是认为这个解决方案可能没问题:现在两个对象的数据结构比以前更平等。问题是,对象 B
来自外部服务,我无法修改它。 )
您的映射不起作用,因为您没有 someObjects
的 setter。
当 Orika 尝试为映射器生成代码时,它会检查 classMap
中的所有 fieldMaps
是否 sourceProperty
是可读的并且 destinationProperty
是可分配的。如果此检查通过,生成器将字段转换放入生成的映射器中。如果检查失败,Orika 将跳过此字段转换。
您可以使用几个选项来解决问题:
您可以为 class 中的 someObjects
字段添加 setter B
:
public static class B {
List<SomeObject> someObjects;
public List<SomeObject> getSomeObjects() {
if (someObjects == null) {
someObjects = new ArrayList<SomeObject>();
}
return someObjects;
}
public void setSomeObjects(List<SomeObject> someObjects) {
this.someObjects = someObjects;
}
}
使用自定义映射器而不是转换器:
factory.classMap(A.class, B.class)
.customize(
new CustomMapper<A, B>() {
@Override
public void mapAtoB(A a, B b, MappingContext context) {
SomeObject someObject = new SomeObject();
someObject.setStringSomeObject(a.getStringA());
b.getSomeObjects().add(someObject);
}
}
)
.byDefault()
.register();
Orika 将在解析字段映射后调用 customMapper。
生成的映射器将如下所示:
b.setOtherField(a.getOtherField());
if (customMapper != null) {
customMapper.map(source, destination); <-- Your mapper invocation
}
对字段使用以下语法:
factory.classMap(A.class, B.class)
.field("stringA", "someObjects[0].stringSomeObject")
.byDefault()
.register();
生成的映射器如下所示:
if (source.getStringA() != null) {
if (((((java.util.List) destination.getSomeObjects()).size() <= 0 || ((List) destination.getSomeObjects()).get(0) == null))) {
((java.util.List) destination.getSomeObjects()).add(0, ((BoundMapperFacade) usedMapperFacades[0]).newObject(((String) source.getStringA()), mappingContext));
}
}
if (!(((java.lang.String) source.getStringA()) == null)) {
(((java.util.List) destination.getSomeObjects()).get(0)).setStringSomeObject(source.getStringA());
} else if (!(((java.util.List) destination.getSomeObjects()) == null) && !((((java.util.List) destination.getSomeObjects()).size() <= 0 || ((List) destination.getSomeObjects()).get(0) == null))) {
( ((java.util.List) destination.getSomeObjects()).get(0)).setStringSomeObject(null);
}
Orika 中还有一个错误,使用语法 .field("stringA", "elements{stringB}")
(Incorrect mapper code generated for mapping from a single property to property of collection element). Bug closed at 31 Dec 2016 here: Fix for bug
从单个 属性 映射到 属性 集合
考虑以下情况:
public class A {
private String stringA;
public String getStringA() {
return stringA;
}
public void setStringA(String stringA) {
this.stringA = stringA;
}
}
public class B {
List<SomeObject> someObjects;
public List<SomeObject> getSomeObjects() {
if (someObjects == null) {
someObjects = new ArrayList<SomeObject>();
}
return someObjects;
}
}
public class SomeObject {
private String stringSomeObject;
public String getStringSomeObject() {
return stringSomeObject;
}
public void setStringSomeObject(String stringSomeObject) {
this.stringSomeObject = stringSomeObject;
}
}
我想从 A
映射到 B
。在映射这些时,stringA
需要映射到 SomeObject
中的 stringSomeObject
。我试图为此编写一个 Orika-Mapper:
public class MyMapper extends ConfigurableMapper {
@Override
protected void configure(MapperFactory factory) {
ConverterFactory converterFactory = factory.getConverterFactory();
converterFactory.registerConverter(new StringToSomeObjectConverter());
factory.classMap(A.class, B.class) //
.field("stringA", "someObjects") //
.byDefault() //
.register();
}
}
它将 class A
映射到 B
并且每当它遇到从 String
到 List<SomeObject>
的转换时它调用自定义转换器:
public class StringToSomeObjectConverter extends CustomConverter<String, List<SomeObject>> {
private static final String BORROWER_PARTY_TYP_CODE = "147";
@Override
public List<SomeObject> convert(String source, Type<? extends List<SomeObject>> destinationType) {
SomeObject someObject = new SomeObject();
someObject.setStringSomeObject(source);
return Arrays.asList(someObject);
}
}
我写了一个单元测试来确保它有效:
@Test
public void testMap() throws Exception {
A a = new A();
a.setStringA("a");
B outcome = new MyMapper().map(a, B.class);
assertThat(outcome.getSomeObjects.size(), is(1));
}
遗憾的是这个测试失败了:
java.lang.AssertionError:
Expected: is <1>
but: was <0>
似乎转换器从未执行过,所以我尝试调试它。事实上:调试器永远不会到达转换器。难道我做错了什么?这好像是。我知道还有更多方法可以使用,例如:mapAToB 例如...
好的,我找到了一个解决方案...不!这不是解决方案,只是一种解决方法。我也将 stringA
定义为 List<String>
,并定义了一个扩展 CustomConverter<String, LoanContrReqERPCrteReqLoanContrBrrwrPty>
的转换器。
因为这感觉有点"hacky",我还是对一个不错的解决方案感兴趣。 (虽然我只是认为这个解决方案可能没问题:现在两个对象的数据结构比以前更平等。问题是,对象 B
来自外部服务,我无法修改它。 )
您的映射不起作用,因为您没有 someObjects
的 setter。
当 Orika 尝试为映射器生成代码时,它会检查 classMap
中的所有 fieldMaps
是否 sourceProperty
是可读的并且 destinationProperty
是可分配的。如果此检查通过,生成器将字段转换放入生成的映射器中。如果检查失败,Orika 将跳过此字段转换。
您可以使用几个选项来解决问题:
您可以为 class 中的
someObjects
字段添加 setterB
:public static class B { List<SomeObject> someObjects; public List<SomeObject> getSomeObjects() { if (someObjects == null) { someObjects = new ArrayList<SomeObject>(); } return someObjects; } public void setSomeObjects(List<SomeObject> someObjects) { this.someObjects = someObjects; } }
使用自定义映射器而不是转换器:
factory.classMap(A.class, B.class) .customize( new CustomMapper<A, B>() { @Override public void mapAtoB(A a, B b, MappingContext context) { SomeObject someObject = new SomeObject(); someObject.setStringSomeObject(a.getStringA()); b.getSomeObjects().add(someObject); } } ) .byDefault() .register();
Orika 将在解析字段映射后调用 customMapper。
生成的映射器将如下所示:
b.setOtherField(a.getOtherField());
if (customMapper != null) {
customMapper.map(source, destination); <-- Your mapper invocation
}
对字段使用以下语法:
factory.classMap(A.class, B.class) .field("stringA", "someObjects[0].stringSomeObject") .byDefault() .register();
生成的映射器如下所示:
if (source.getStringA() != null) {
if (((((java.util.List) destination.getSomeObjects()).size() <= 0 || ((List) destination.getSomeObjects()).get(0) == null))) {
((java.util.List) destination.getSomeObjects()).add(0, ((BoundMapperFacade) usedMapperFacades[0]).newObject(((String) source.getStringA()), mappingContext));
}
}
if (!(((java.lang.String) source.getStringA()) == null)) {
(((java.util.List) destination.getSomeObjects()).get(0)).setStringSomeObject(source.getStringA());
} else if (!(((java.util.List) destination.getSomeObjects()) == null) && !((((java.util.List) destination.getSomeObjects()).size() <= 0 || ((List) destination.getSomeObjects()).get(0) == null))) {
( ((java.util.List) destination.getSomeObjects()).get(0)).setStringSomeObject(null);
}
Orika 中还有一个错误,使用语法 .field("stringA", "elements{stringB}")
(Incorrect mapper code generated for mapping from a single property to property of collection element). Bug closed at 31 Dec 2016 here: Fix for bug