Мы решили эту проблему, используя ASM (среду обработки и анализа байт-кода), чтобы прочитать Mapping
-аннотацию и предоставить ее. в метамодели:
Пример (также доступен на 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
можно получить информацию о сопоставлении следующим образом:
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")
возвращает сопоставленное поле, если BusinessModel
(zip
).
AnnotationParser
— это анализатор аннотаций общего назначения, который предоставляет список MethodAnnotationInfo
.
MapStructParser
использует модель AnnotationParser
для построения MapStructMappingInfo
путем сбора Mapping
-Аннотации.
Полный работоспособный и протестированный пример доступен здесь:
https://github.com/TobseF/mapstruct-metadata-example
Теоретически также возможно подключиться к процессу обработки аннотаций MapStruct и сгенерировать Java-классы MetaModel (ModelElementProcessor
). Но я не смог заставить его работать. Добавление дополнительных обработчиков аннотаций — непростая задача, а отладка обработки аннотаций во время компиляции класса более чем обременительна. Для нашей цели достаточно ASM и простого отображения.
person
Tobse
schedule
01.07.2020