使用 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 都有一个具有该值的构造函数。