有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Mapstruct:如何使用相同的映射器将A扩展单值<T>映射到T,将A扩展单值<T>映射到B扩展单值<T>?

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

让我用一个简单的例子来说明这个问题。(为了可读性,省略了抛出)

我们有一个单一的价值对象:

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>{

}

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

可能的映射:

  • 字符串->;名字
  • 名字->;串
  • 名字->;另一个扩展了单值对象

在当前解决方案中,以下映射是可能的:

  • 字符串->;名字
  • 名字->;串

当前单值映射器

@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->;另一个扩展了单值对象映射,我提出了以下不起作用的解决方案:

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)映射而不是这个映射(我真的不想使用限定符,因为这样我需要限定im映射的每个字段)
  • 例如,如果我们也为UUID单值添加一个映射方法,Mapstruct会认为映射方法不明确

工作此调用由mapstruct在将字符串映射到值时生成:

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

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

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

有没有办法通过mapstruct和java泛型实现这一点

我使用的是Mapstruct 1.3.0-final版


共 (1) 个答案

  1. # 1 楼答案

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

    @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();
        }
    
    }