【问题标题】:MapStruct: custom mapping function is applied to all fieldsMapStruct:自定义映射函数应用于所有字段
【发布时间】:2022-09-25 15:50:07
【问题描述】:

我有将int 映射到String 的自定义映射函数,但我只希望它应用于一种特殊情况。但是,它适用于所有 int 类型的源字段,而不仅仅是带有 java(...) 注释的源字段。

源类:

class Source {
    private int a;
    private int b;
    // getters etc...
}

目标类:

class Target {
    private String a;
    private String b;
    // getters etc...
}

映射器:

@Mapping(source=\"a\", target=\"a\") // should not be necessary, but to make it more explicit
@Mapping(target=\"b\", expression = \"java(modify(b))\")
public abstract Target sourceToTarget(Source source);

String modify(int value) {
    return \"prefix_\" + value;
}

我想要达到的目标:

target.setA(String.valueOf(a));
target.setB(modify(b));

但是,生成的代码会这样做:

target.setA(modify(a));
target.setB(modify(b));

删除表达式和 modify 时,MapStruct 将 String.valueOf 用于这两个值。 我用 MapStruct 1.4.2.FINAL 和 1.5.2.FINAL 都试过了。这两个类都使用了 Lombok,但是,这在过去不是问题。

这种行为是预期的吗?如果是,我还能如何使它工作?

  • @Named 限定符 modify() 与 @Mapping#qualifiedByName 配对应该可以解决您的问题。检查官方文档。

标签: java mapstruct


【解决方案1】:

您可以尝试两种方法:

--> @Mapping#expression 属性:

@Mapper(componentModel = "spring")
public interface ExampleMapper {

    @Mapping(target = "b", expression = "java(modify(source.getB()))")
    @Mapping(target = "a", expression = "java(String.valueOf(source.getA()))")
    Target sourceToTarget(Source source);

    default String modify(int value) {
        return "prefix_" + value;
    }
}

它生成了以下代码:

@Component
public class ExampleMapperImpl implements ExampleMapper {

    @Override
    public Target sourceToTarget(Source source) {
        if ( source == null ) {
            return null;
        }

        Target target = new Target();

        target.setB( modify(source.getB()) );
        target.setA( String.valueOf(source.getA()) );

        return target;
    }
}

--> 试试@Named:

@Mapper(componentModel = "spring")
public interface ExampleMapper {

    @Mapping(source = "a", target = "a")
    @Mapping(target = "b", qualifiedByName = "any-name")
    Target sourceToTarget(Source source);

    @Named("any-name")
    default String modify(int value) {
        return "prefix_" + value;
    }
}

笔记:我在modify(int value) 方法上使用了@Named,因此它不能被任何映射使用,除非通过qualifiedByName 提及。

它生成了以下代码:

@Component
public class ExampleMapperImpl implements ExampleMapper {

    @Override
    public Target sourceToTarget(Source source) {
        if ( source == null ) {
            return null;
        }

        Target target = new Target();

        target.setA( String.valueOf( source.getA() ) );

        target.setB( modify(source.getB()) );

        return target;
    }
}

【讨论】:

  • 谢谢,我试试这个。顺便说一句:我认为您忘记在代码示例中实际使用 qualifiedByName
  • @ceran 这不是必需的。没有它,它也会产生
  • 如果在@mapping 中同时使用qualifiedByName 和表达式,@ceran 编译器会报错。所以,你必须使用它们中的任何一个。
  • @ceran 我在 modify 方法上使用了@Named,因此它不能被任何映射使用,除非通过限定名称提及或通过表达式显式调用。阅读我的答案你会明白的。
  • 我的观点是,如果你使用qualifiedByName,首先就不需要表达了。根据我的理解,这就是它的全部意义所在。我会接受你的回答,但我认为最干净的方法是 @Mapping(target="b", qualifiedByName("any-name")) 有效。谢谢
猜你喜欢
  • 1970-01-01
  • 2018-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-09
  • 2021-11-19
  • 1970-01-01
相关资源
最近更新 更多