本文介绍了如何在运行时提供MapStruct Mapping批注映射元数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在业务模型和我们的 ui-之间使用 MapStruct 型号.当UI客户端想要获取排序的数据时,它可以从 ui-model 中指定一个字段.我们的 MapStructParser 可以获取相应的 business-model 字段名称,并创建所需的Criteria对其进行排序.

We use MapStruct between a business-model and our ui-model.When a UI client wants to get sorted data, it can specify a field from the ui-model.Our MapStructParser can get the corresponding business-model field-name and create the needed Criteria to sort it.

示例:

public interface ModelMapping extends BridgeMapping<BusinessModel, UiModel> {
   @Mapping(source = "zip", target = "plz")
   UiModel modelToUiModel(BusinessModel model, @MappingTarget UiModel uiModel);
}

问题:
如何读取 @Mapping(source ="zip",target ="plz")批注并获取 source target 值? Mapping -Annotation具有 RetentionPolicy.CLASS ,因此无法通过反射对其进行访问.

The Problem:
How to read the @Mapping(source = "zip", target = "plz") annotation and get the source and target value?The Mapping-Annotation has RetentionPolicy.CLASS, so it's not possible to access it via reflections.

推荐答案

我们通过使用 ASM (字节码操作和分析框架)读取 Mapping -Annotation并将其提供给元模型:

We solved this problem by using ASM (bytecode manipulation and analysis framework)to read the Mapping-Annotation and provide it in a meta model:

示例(也在Github上可用)

public class AnnotationParser {
   public void parse(Class<?> mapper) {
      ClassInfoCollector classPrinter = new ClassInfoCollector(annotationInfos);
      ClassReader cr = new ClassReader(mapper.getCanonicalName());
      cr.accept(classPrinter, 0);
   }
}

public class ClassInfoCollector extends ClassVisitor {

   private final List<MethodAnnotationInfo> mapStructParser;

   public ClassInfoCollector(List<MethodAnnotationInfo> mapStructParser) {
      super(ASMversion);
      this.mapStructParser = mapStructParser;
   }

   @Override
   public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
      super.visit(version, access, name, signature, superName, interfaces);
   }

   @Override
   public MethodVisitor visitMethod(int access, String methodName, String descriptor, String signature, String[] exceptions) {
      return new MethodInfoCollector(methodName,  mapStructParser);
   }

}

public class ClassInfoCollector extends ClassVisitor {

   private final List<MethodAnnotationInfo> mapStructParser;

   public ClassInfoCollector(List<MethodAnnotationInfo> mapStructParser) {
      super(ASMversion);
      this.mapStructParser = mapStructParser;
   }

   @Override
   public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
      super.visit(version, access, name, signature, superName, interfaces);
   }

   @Override
   public MethodVisitor visitMethod(int access, String methodName, String descriptor, String signature, String[] exceptions) {
      return new MethodInfoCollector(methodName,  mapStructParser);
   }

}

class MethodInfoCollector extends MethodVisitor {

    private final String methodName;
    private final List<MethodAnnotationInfo> mapStructParser;

   public MethodInfoCollector(String method, List<MethodAnnotationInfo> mapStructParser) {
      super(ASMversion);
      this.methodName = method;
      this.mapStructParser = mapStructParser;
   }

   @Override
   public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
      return new MethodAnnotationInfoCollector(methodName, descriptor,  mapStructParser);
   }
}

class MethodAnnotationInfoCollector extends AnnotationVisitor {

   private final String method;
   private final String annotationType;
   private final List<MethodAnnotationInfo> mapStructParser;

   public MethodAnnotationInfoCollector(String method, String annotationType, List<MethodAnnotationInfo> mapStructParser) {
      super(ASMversion);
      this.method = method;
      this.annotationType = annotationType;
      this.mapStructParser = mapStructParser;
   }

   @Override
   public void visit(String name, Object value) {
      MethodAnnotationInfo annotationInfo = new MethodAnnotationInfo(method,  annotationType, name, value.toString());
      mapStructParser.add(annotationInfo);
      super.visit(name, value);
   }

}

使用此 AnnotationParser 可以通过以下方式获取映射信息:

Wit this AnnotationParser it's possible to get the mapping info in this way:

class BusinessModel{
   String zip;
}

class UiModel{
   String plz;
}

public interface ModelMapping extends BridgeMapping<BusinessModel, UiModel> {
   @Mapping(source = "zip", target = "plz")
   UiModel modelToUiModel(BusinessModel model, @MappingTarget UiModel uiModel);
}

@Test
public testMappingInfo(){
   MapStructParser mappingInfo = new MapStructParser();
   mappingInfo.parseMappingInterface(ModelMapping.class);
   assertEquals("zip", mappingInfo.mapToTargetField("plz"));
}

mappingInfo.mapToTargetField("plz")返回if BusinessModel ( zip )的映射字段. AnnotationParser 是通用注释解析器,它提供 MethodAnnotationInfo 的列表.
MapStructParser 使用 AnnotationParser 模型通过收集 Mapping -Annotations来构建 MapStructMappingInfo .

The mappingInfo.mapToTargetField("plz") returns the mapped field of if the BusinessModel (zip).
The AnnotationParser is a general purpose annotation parser which provide a list of MethodAnnotationInfo.
The MapStructParser uses the AnnotationParser model to build a MapStructMappingInfo by collecting the Mapping-Annotations.

完整的可运行且经过测试的示例可在以下位置找到:
https://github.com/TobseF/mapstruct-metadata-example

The full runnable and tested example is available in here:
https://github.com/TobseF/mapstruct-metadata-example

这篇关于如何在运行时提供MapStruct Mapping批注映射元数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 14:11
查看更多