Mapstruct:如何映射A extends SingleValue 到T和A扩展SingleValue 到B扩展SingleValue 使用相同的映射器?

问题描述 投票:0回答:1

我已经盯着这个问题很长一段时间了,一直无法找到答案。我正在尝试使用mapstruct来映射具有通用SingleValue对象实现的字段的对象。

让我用简化的例子说明问题。 (为了便于阅读,省略了抛出)

我们有一个Single Value对象:

public abstract class SingleValue<T extends Serializable> implements Serializable {
    private T value;

    public SingleValue(T value) {
        this.value = value;
    }
}

具体的单值类看起来像这样

public class FirstName extends SingleValue<String>{

}

并将用于可能相互映射的不同对象

应该可能的映射:

  • String - > FirstName
  • FirstName - > String
  • FirstName - >另一个扩展SingleValue对象

使用当前解决方案可以进行以下映射:

  • String - > FirstName
  • FirstName - > String

当前单值映射器

@Mapper
public interface SingleValueMapper {
    SingleValueMapper INSTANCE = Mappers.getMapper(SingleValueMapper.class);
    default <Z extends Serializable, T extends SingleValue<Z>> T singleValue(Z obj, Class<Z> objClass, @TargetType Class<T> targetType) {
        if (obj == null) {
            return null;
        }
        return targetType.getConstructor(objClass).newInstance(obj);
    }

    default <T extends Serializable, Z extends SingleValue<T>> T getValue(Z singleValue) {
        if (singleValue == null) {
            return null;
        }
        return singleValue.getValue();
    }

    default <T extends SingleValue<String>> T singleValue(String obj, @TargetType Class<T> targetType) {
        return singleValue(obj, String.class, targetType);

    }
}

对于FirstName - >另一个扩展的SingleValue对象映射,我提出了以下解决方案:

default <T extends SingleValue<String>> T stringSingleValue(SingleValue<String> obj, @TargetType Class<T> targetType)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    return singleValue(obj.getValue(), String.class, targetType);
}

我上面提到的映射方法存在的问题:

  • 在自动选择中,Mapstruct会优先选择getValue(Z singleValue)映射(我真的不想使用限定符,因为那时我需要限定我映射的每个字段)
  • 如果我们例如还为UUID单值添加一个映射方法,则Mapstruct将看到映射方法不明确

当将String映射到A扩展SingleValue时,此调用由mapstruct生成:

A a = singleValueMapper.singleValue( client.getCompanyName(), A.class )

这个调用不是由mapstruct选择的,但我们可以在手动使用@Mapping作为表达式时使用它。但是我们希望mapstruct在映射A时将自动映射这些调用,将SingleValue扩展为B扩展SingleValue:

B b =singleValueMapper.stringSingleValue(command.getTitle(), B.class)

有没有办法用mapstruct和java泛型来解决这个问题?

我正在使用Mapstruct 1.3.0版本的版本。

java generics mapstruct
1个回答
0
投票

我需要一些地方来提供一些反馈。

@Mapper // Why is this annotated with @Mapper or even an interface (iso a regular class)? Are there more methods in here not shown that should be generated by MapStruct?
public interface SingleValueMapper {
    SingleValueMapper INSTANCE = Mappers.getMapper(SingleValueMapper.class);

    // How should MapStruct know how to populate these? It can only map a source to a target? It takes @TargetType as hint, but it cannot populate the second argument Class<Z> ojbClass. But is this required? Perhaps obj.getClass()? 
    default <Z extends Serializable, T extends SingleValue<Z>> T singleValue(Z obj, Class<Z> objClass, @TargetType Class<T> targetType) {
        if (obj == null) {
            return null;
        }
        return targetType.getConstructor(objClass).newInstance(obj);
    }

    default <T extends Serializable, Z extends SingleValue<T>> T getValue(Z singleValue) {
        if (singleValue == null) {
            return null;
        }
        return singleValue.getValue();
    }

    // seems to me like a duplicate of the above?
    default <T extends SingleValue<String>> T singleValue(String obj, @TargetType Class<T> targetType) {
        return singleValue(obj, String.class, targetType);

    }
}

所以有了上面的内容,我会像这样重写这个类:

public class SingleValueMapper {

    <Z extends Serializable, T extends SingleValue<Z>> T singleValue(Z obj,  @TargetType Class<T> targetType) {
        if (obj == null) {
            return null;
        }
        return targetType.getConstructor(obj.getClass()).newInstance(obj);
    }

    <T extends Serializable, Z extends SingleValue<T>> T getValue(Z singleValue) {
        if (singleValue == null) {
            return null;
        }
        return singleValue.getValue();
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.