使用 mapstruct 的值对象的通用映射
Generic mapping of Value Objects with mapstruct
尝试在我的业务模型中使用值对象时,我遇到了以下代码的问题:
@Mapper
public abstract class TestMapstruct {
public ValueObjectA mapA(String value){
return new ValueObjectA(value);
}
public abstract BusinessObject map(DTO dto);
@Value
public static class ValueObjectA {
private String a;
}
@Value
public static class ValueObjectB {
private String b;
}
@Data
public static class BusinessObject {
private ValueObjectA a;
private ValueObjectB b;
}
@Data
public static class DTO {
private String a;
private String b;
}
}
缺少映射(字符串 -> ValueObjectB)会导致以下编译错误消息:
Can't map property "java.lang.String b" to "test.ValueObjectB b". Consider to declare/implement a mapping method: "test.ValueObjectB map(java.lang.String value)".
我完全理解这一点,但我宁愿不为我的每个 ValueObjects(一个项目中可能有几十个)声明一个方法。
是否有通用的方法来声明 (String -> ValueObject) 映射方法?
如果所有方法之间没有通用接口,则没有通用的方法来执行此操作。
但是,如果您有一个通用接口,那么这是可能的。例如:
public interface ValueObject<T> {
T getValue();
void setValue(T value);
}
那么你需要一个辅助映射器:
public interface ValueObjectMapper {
static <V extends ValueObject<T>, T> T mapToValue(V valueObject) {
return valueObject == null ? null : valueObject.getValue();
}
static <V extends ValueObject<T>, T> V mapFromValueObject(T value, @TargetType Class<V> valueObjectClass) {
if (value == null) {
return null;
}
try {
V valueObject = valueObjectClass.getDeclaredConstructor().newInstance();
valueObject.setValue(value);
return valueObject;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
编辑:添加具有不可变值对象的示例。
如果您希望您的值对象是不可变的,那么您可以执行以下操作:
public interface ValueObject<T> {
T getValue();
}
public interface ValueObjectMapper {
static <V extends ValueObject<T>, T> T mapToValue(V valueObject) {
return valueObject == null ? null : valueObject.getValue();
}
static <V extends ValueObject<T>, T> V mapFromValueObject(T value, @TargetType Class<V> valueObjectClass) {
if (value == null) {
return null;
}
try {
V valueObject = valueObjectClass.getDeclaredConstructor(value.getClass()).newInstance(value);
return valueObject;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
注意:要完成这项工作,您必须确保所有 ValueObjects 都有一个具有该值的构造函数。
尝试在我的业务模型中使用值对象时,我遇到了以下代码的问题:
@Mapper
public abstract class TestMapstruct {
public ValueObjectA mapA(String value){
return new ValueObjectA(value);
}
public abstract BusinessObject map(DTO dto);
@Value
public static class ValueObjectA {
private String a;
}
@Value
public static class ValueObjectB {
private String b;
}
@Data
public static class BusinessObject {
private ValueObjectA a;
private ValueObjectB b;
}
@Data
public static class DTO {
private String a;
private String b;
}
}
缺少映射(字符串 -> ValueObjectB)会导致以下编译错误消息:
Can't map property "java.lang.String b" to "test.ValueObjectB b". Consider to declare/implement a mapping method: "test.ValueObjectB map(java.lang.String value)".
我完全理解这一点,但我宁愿不为我的每个 ValueObjects(一个项目中可能有几十个)声明一个方法。
是否有通用的方法来声明 (String -> ValueObject) 映射方法?
如果所有方法之间没有通用接口,则没有通用的方法来执行此操作。
但是,如果您有一个通用接口,那么这是可能的。例如:
public interface ValueObject<T> {
T getValue();
void setValue(T value);
}
那么你需要一个辅助映射器:
public interface ValueObjectMapper {
static <V extends ValueObject<T>, T> T mapToValue(V valueObject) {
return valueObject == null ? null : valueObject.getValue();
}
static <V extends ValueObject<T>, T> V mapFromValueObject(T value, @TargetType Class<V> valueObjectClass) {
if (value == null) {
return null;
}
try {
V valueObject = valueObjectClass.getDeclaredConstructor().newInstance();
valueObject.setValue(value);
return valueObject;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
编辑:添加具有不可变值对象的示例。
如果您希望您的值对象是不可变的,那么您可以执行以下操作:
public interface ValueObject<T> {
T getValue();
}
public interface ValueObjectMapper {
static <V extends ValueObject<T>, T> T mapToValue(V valueObject) {
return valueObject == null ? null : valueObject.getValue();
}
static <V extends ValueObject<T>, T> V mapFromValueObject(T value, @TargetType Class<V> valueObjectClass) {
if (value == null) {
return null;
}
try {
V valueObject = valueObjectClass.getDeclaredConstructor(value.getClass()).newInstance(value);
return valueObject;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
注意:要完成这项工作,您必须确保所有 ValueObjects 都有一个具有该值的构造函数。