【问题标题】:Mapstruct: Auto-increment a object variable in a list of objectsMapstruct:在对象列表中自动增加对象变量
【发布时间】:2017-05-28 00:49:35
【问题描述】:

我有一些这样的 POJO:

@Data
public class A {
    List<B> bList;
}

@Data
public class B {
    int id;
    int x;
}

@Data
public class C {
    List<D> dList;
}

@Data
public class D {
    int x;
}

现在我想使用 MapStruct 将 C 类映射到 A 类,这样 A 类中 bList 中的 id 值会自动递增。我正在使用 Mapstruct 1.1.0.Final。

为了将List&lt;D&gt; 映射到List&lt;B&gt;,我可以为class Bclass D 定义一个映射器,POJO 将被自动映射,但找不到一种方法可以将 POJO 与自动增量一起映射在一个领域。

我的 POJO 很大。 Map Struct 中有没有一种方法可以自动增加列表中的变量?

【问题讨论】:

  • 您能否提供更多信息。你想什么时候做一个自动增量?在cA 之间的映射之后还是在BD 之间的映射之后?
  • 感谢您的回复。理想情况下,应该是在将 D 映射到 B 时。我为此找到了两种解决方案:在抽象类中使用全局线程局部变量并编写像 java("getAndIncrement(counter)") 这样的表达式,其中 getAndIncrement 是一种获取和增加线程局部的方法变量(虽然不是一个好的解决方案,但由于我有巨大的 POJO,所以手动映射将是一项耗时的任务)。第二种解决方案:使用@AfterMapping 注释。 C 映射到 A 后,手动自动增加 B 列表中的 id 值。

标签: java mapping mapstruct


【解决方案1】:

1.1.0.Final 有 2 个选项,1.2.0.Beta2 有另外一个选项。

D 映射到B 时的第一个选项

您可以在DB 之间使用@AfterMapping,并在那里使用ThreadLocal

public class AutoIncrementorThreadLocal {

    @AfterMapping
    public /*static*/ void autoIncrementId(D source, @MappingTarget B target) {
        //here you use the ThreadLocal and do something like getAndIncrement
    }
}

在您的映射器中,您必须说您使用的是AutoIncrementorThreadLocal。方法也可以是静态的,MapStruct 也可以调用静态方法。

C 映射到A 时的第二个选项

public class AutoIncrementorBulk {

    @AfterMapping
    public /*static*/ void autoIncrementId(C source, @MappingTarget A target) {
        //here you iterate the list and increment the ids
    }
}

在您的映射器中,您必须说您使用的是AutoIncrementorBulk。方法也可以是静态的,MapStruct 也可以调用静态方法。

1.2.0.Beta2 的第三个选项

您可以使用新的@Context 并在上面添加@AfterMapping

public class AutoIncrementorContext {

    private int counter = 0;
    @AfterMapping
    public void autoIncrementId(D source, @MappingTarget B target) {
        //here you use your counter, because you are only using this instance during one mapping
    }
}

您的映射器需要如下所示:

@Mapper
public interface MyMapper {

    C map(A source, @Context AutoIncrementorContext context);

    D map(B source, @Context AutoIncrementorContext context);
}

当你要调用你的映射器时,你需要这样称呼它:

myMapper.map(a, new AutoIncrementorContext());

第一种和第三种方法相似,唯一的区别是您不必将ThreadLocal(s) 与第三种方法一起使用。

【讨论】:

  • 感谢您的回复。在第一个选项中,我们不能使用局部变量而不是线程局部变量,因为我们正在编写方法体吗?另外为了避免写正文,我们可以使用线程局部类级别变量并使用像java("getAndIncrement(counter)") 这样的表达式,其中getAndIncrement 方法增加计数器(线程局部变量)。
  • 根据我在您的问题中的理解,您希望A 中的List&lt;B&gt; 具有一些自动增量ID。将任何D映射到B时都会调用第一个选项方法,所以你不能真正使用局部变量,你会使用什么ID?您将始终有一个对象可以递增?
  • 第二部分。是的,您可以使用带有线程局部类级别变量的抽象类并像这样增加计数器。但是,我更喜欢避免使用表达式并使用@AfterMapping@Context。如果可能的话,我不喜欢使用ThreadLocal。如果您认为值得,我可以使用类变量 ThreadLocal 更新答案
猜你喜欢
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多