
org.openl.util.generation.InterfaceTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.openl.rules.project Show documentation
Show all versions of org.openl.rules.project Show documentation
Classes and utilities to work with OpenL Rules Project
package org.openl.util.generation;
import org.objectweb.asm.*;
import org.openl.rules.runtime.InterfaceGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Map.Entry;
/**
* This class is similar to {@link ClassReader} from ASM framework. But it can
* be used only for interface generation.
*
* {@link InterfaceTransformer} uses base class that will be transformed,
* classname for new class and {@link ClassVisitor} that will handle class
* creation.
*
* {@link InterfaceTransformer} reads methods with
* signatures,constants,annotations and passes them to {@link ClassVisitor}.
*
* @author PUdalau
*/
public class InterfaceTransformer {
private final Logger log = LoggerFactory.getLogger(InterfaceTransformer.class);
private Class> interfaceToTransform;
private String className;
private boolean processParamAnnotation;
/**
* @param interfaceToTransform Base class for generations.
* @param className Name for new class(java notation: with .(dot) as the
* delimiter).
*/
public InterfaceTransformer(Class> interfaceToTransform, String className) {
this.interfaceToTransform = interfaceToTransform;
this.className = className;
this.processParamAnnotation = true;
}
public InterfaceTransformer(Class> interfaceToTransform, String className, boolean processParamAnnotation) {
this.interfaceToTransform = interfaceToTransform;
this.className = className;
this.processParamAnnotation = processParamAnnotation;
}
/**
* Reads class and passes class generation instructions to
* classVisitor
. Similar to
* org.objectweb.asm.ClassReader.accept(...)
*
* @param classVisitor Visitor to consume writing instructions.
*/
public void accept(ClassVisitor classVisitor) {
classVisitor.visit(Opcodes.V1_5,
InterfaceGenerator.PUBLIC_ABSTRACT_INTERFACE,
className.replace('.', '/'),
null,
InterfaceGenerator.JAVA_LANG_OBJECT,
null);
for (Annotation annotation : interfaceToTransform.getAnnotations()) {
AnnotationVisitor av = classVisitor.visitAnnotation(Type.getDescriptor(annotation.annotationType()), true);
processAnnotation(annotation, av);
}
for (Field field : interfaceToTransform.getFields()) {
if (isConstantField(field)) {
try {
FieldVisitor fieldVisitor = classVisitor.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL,
field.getName(),
Type.getDescriptor(field.getType()),
null,
field.get(null));
if (fieldVisitor != null) {
for (Annotation annotation : field.getAnnotations()) {
AnnotationVisitor av = fieldVisitor.visitAnnotation(Type.getDescriptor(annotation.annotationType()),
true);
processAnnotation(annotation, av);
}
}
} catch (Exception e) {
log.error("Failed to process field '{}'.", field.getName(), e);
}
}
}
for (Method method : interfaceToTransform.getMethods()) {
String ruleName = method.getName();
MethodVisitor methodVisitor = classVisitor.visitMethod(InterfaceGenerator.PUBLIC_ABSTRACT,
ruleName,
Type.getMethodDescriptor(method),
null,
null);
if (methodVisitor != null) {
for (Annotation annotation : method.getAnnotations()) {
AnnotationVisitor av = methodVisitor.visitAnnotation(Type.getDescriptor(annotation.annotationType()),
true);
processAnnotation(annotation, av);
}
if (processParamAnnotation){
if (method.getParameterAnnotations().length > 0) {
int index = 0;
for (Annotation[] annotatons : method.getParameterAnnotations()) {
for (int j = 0; j < annotatons.length; j++) {
AnnotationVisitor av = methodVisitor.visitParameterAnnotation(index,
Type.getDescriptor(annotatons[j].annotationType()),
true);
processAnnotation(annotatons[j], av);
}
index++;
}
}
}
}
}
}
private static boolean isConstantField(Field field) {
int modifiers = field.getModifiers();
return Modifier.isFinal(modifiers) && Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers);
}
public static void processAnnotation(Annotation annotation, AnnotationVisitor av) {
Map annotationAttributes = AnnotationUtils.getAnnotationAttributes(annotation);
if (av != null) {
for (Entry annotationAttribute : annotationAttributes.entrySet()) {
Object attributeValue = annotationAttribute.getValue();
Class extends Object> attributeType = attributeValue.getClass();
if (attributeType.isArray()) {
AnnotationVisitor arrayVisitor = av.visitArray(annotationAttribute.getKey());
Object[] array = (Object[]) attributeValue;
for (int i = 0; i < array.length; i++) {
visitNonArrayAnnotationAttribute(arrayVisitor, null, array[i]);
}
arrayVisitor.visitEnd();
} else {
visitNonArrayAnnotationAttribute(av, annotationAttribute.getKey(), annotationAttribute.getValue());
}
}
av.visitEnd();
}
}
private static void visitNonArrayAnnotationAttribute(AnnotationVisitor av, String attributeName, Object attributeValue) {
Class extends Object> attributeType = attributeValue.getClass();
if (attributeValue instanceof Class) {
av.visit(attributeName, Type.getType((Class>) attributeValue));
} else if (attributeType.isEnum()) {
av.visitEnum(attributeName, Type.getDescriptor(attributeType), attributeValue.toString());
} else {
av.visit(attributeName, attributeValue);
}
}
/**
* @return Base class for generations.
*/
public Class> getInterfaceToTransform() {
return interfaceToTransform;
}
/**
* @return The name for new generated class.
*/
public String getClassName() {
return className;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy