Java 值对象与mapstruct的通用映射
尝试在我的业务模型中使用价值对象时,我遇到了以下代码的问题:Java 值对象与mapstruct的通用映射,java,mapstruct,value-objects,Java,Mapstruct,Value Objects,尝试在我的业务模型中使用价值对象时,我遇到了以下代码的问题: @Mapper public abstract class TestMapstruct { public ValueObjectA mapA(String value){ return new ValueObjectA(value); } public abstract BusinessObject map(DTO dto); @Value public static cl
@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)将导致以下编译错误消息:
无法将属性“java.lang.String b”映射到“test.ValueObjectB”。考虑声明/实现一个映射方法:“Test.ValueObjestBMAP(JavaLang.Stand value)”.<
我完全理解这一点,但我不想为我的每个ValueObject(在一个项目中可能有几十个)声明一个方法
是否有一种通用方法来声明(String->ValueObject)映射方法?如果所有方法之间没有通用接口,则没有通用方法来声明 但是,如果您有一个公共接口,那么它是可能的。例如:
public interface ValueObject<T> {
T getValue();
void setValue(T value);
}
公共接口ValueObject{
T getValue();
无效设定值(T值);
}
然后您需要一个助手映射器:
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);
}
}
}
公共接口ValueObjectMapper{
静态T映射值(V valueObject){
返回valueObject==null?null:valueObject.getValue();
}
静态V mapFromValueObject(T值,@TargetType类valueObjectClass){
如果(值==null){
返回null;
}
试一试{
V valueObject=valueObjectClass.getDeclaredConstructor().newInstance();
valueObject.setValue(值);
返回值对象;
}catch(实例化异常|非法访问异常|调用目标异常|无此方法异常){
抛出新的运行时异常(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);
}
}
}
公共接口ValueObject{
T getValue();
}
公共接口ValueObjectMapper{
静态T映射值(V valueObject){
返回valueObject==null?null:valueObject.getValue();
}
静态V mapFromValueObject(T值,@TargetType类valueObjectClass){
如果(值==null){
返回null;
}
试一试{
V valueObject=valueObjectClass.getDeclaredConstructor(value.getClass()).newInstance(value);
返回值对象;
}catch(实例化异常|非法访问异常|调用目标异常|无此方法异常){
抛出新的运行时异常(e);
}
}
}
注意:要做到这一点,您必须确保所有ValueObjects都有一个具有该值的构造函数。我不希望在我的ValueObjects中声明setter和使用参数化构造函数,但它工作起来很有魅力。注意:由于反射操作,缺少抛出声明。您还可以使其与不可变的ValueObject一起工作。我更新了我的答案,也有了这个。我还通过重新抛出
RuntimeException
添加了异常处理功能,效果非常好,我注意到Mapstruct能够处理MappingMethod抛出异常(catch+rethrow RuntimeException),是的,我们可以处理。它还可以很好地处理抛出的异常(如果您在接口上定义它们:)