问题描述
我们在业务模型和我们的 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并将其提供给元模型:
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批注映射元数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!