All Downloads are FREE. Search and download functionalities are using the official Maven repository.

name.remal.asm.AsmUtils Maven / Gradle / Ivy

package name.remal.asm;

import static name.remal.ArrayUtils.arrayToString;
import static name.remal.annotation.AnnotationUtils.getAttributes;
import static org.objectweb.asm.Type.getDescriptor;
import static org.objectweb.asm.Type.getType;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;

public class AsmUtils {

    public static final int ASM_API;

    static {
        try {
            ClassWriter classWriter = new ClassWriter(0);
            Field apiField = ClassVisitor.class.getDeclaredField("api");
            apiField.setAccessible(true);
            ASM_API = apiField.getInt(classWriter);

        } catch (@NotNull NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @NotNull
    @SuppressFBWarnings("CLI_CONSTANT_LIST_INDEX")
    public static Object fromJavaToBytecodeAnnotationValue(@NotNull Object value) {
        if (value instanceof Byte) {
            return value;

        } else if (value instanceof Boolean) {
            return value;

        } else if (value instanceof Character) {
            return value;

        } else if (value instanceof Short) {
            return value;

        } else if (value instanceof Integer) {
            return value;

        } else if (value instanceof Long) {
            return value;

        } else if (value instanceof Float) {
            return value;

        } else if (value instanceof Double) {
            return value;

        } else if (value instanceof String) {
            return value;

        } else if (value instanceof Type) {
            return value;

        } else if (value instanceof Class) {
            return getType((Class) value);

        } else if (value instanceof String[]) {
            String[] typedValue = (String[]) value;
            if (2 != typedValue.length || null == typedValue[0] || null == typedValue[1]) throw new IllegalArgumentException("Unsupported enum value: " + arrayToString((Object[]) typedValue));
            return value;

        } else if (value instanceof Enum) {
            Enum typedValue = (Enum) value;
            return new String[]{getDescriptor(typedValue.getDeclaringClass()), typedValue.name()};

        } else if (value instanceof AnnotationNode) {
            return value;

        } else if (value instanceof Annotation) {
            Annotation typedValue = (Annotation) value;
            AnnotationNode annotationNode = new AnnotationNode(getDescriptor(typedValue.annotationType()));
            annotationNode.values = new ArrayList<>();
            getAttributes(typedValue).forEach((fieldName, fieldValue) -> {
                annotationNode.values.add(fieldName);
                annotationNode.values.add(fromJavaToBytecodeAnnotationValue(fieldValue));
            });
            return annotationNode;

        } else if (value instanceof List) {
            List typedValue = (List) value;
            List resultList = new ArrayList<>(typedValue.size());
            for (Object element : typedValue) {
                if (element instanceof List) throw new IllegalArgumentException("Unsupported annotation value: " + arrayToString(value));
                resultList.add(fromJavaToBytecodeAnnotationValue(element));
            }
            return resultList;

        } else {
            throw new IllegalArgumentException("Unsupported annotation value: " + value.getClass() + ": " + arrayToString(value));
        }
    }

}