ca.weblite.asm.TypeUtil.java Source code

Java tutorial

Introduction

Here is the source code for ca.weblite.asm.TypeUtil.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package ca.weblite.asm;

import ca.weblite.asm.ClassFinder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.lang.model.element.Modifier;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;

/**
 *
 * @author shannah
 */
public class TypeUtil {
    static Map<String, String> primitiveDescriptors;

    /**
     * Map of primitive type descriptors.
     * @return 
     */
    public static Map<String, String> primitiveDescriptors() {
        if (primitiveDescriptors == null) {
            primitiveDescriptors = new HashMap<String, String>();
            String[] d = new String[] { "void", "V", "boolean", "Z", "char", "C", "byte", "B", "short", "S", "int",
                    "I", "float", "F", "long", "J", "double", "D" };
            for (int i = 0; i < d.length; i += 2) {
                primitiveDescriptors.put(d[i], d[i + 1]);
            }
        }
        return primitiveDescriptors;
    }

    public static boolean isPrimitiveType(String type) {
        return primitiveDescriptors().containsKey(type) || primitiveDescriptors.values().contains(type);
    }

    /**
     * Gets the descriptor for a primitive type.
     * @param type The type.  E.g. "int"
     * @return The descriptor for the type.  E.g. "I"
     */
    public static String getPrimitiveDescriptor(String type) {
        if (primitiveDescriptors.values().contains(type)) {
            return type;
        }
        return primitiveDescriptors().get(type);
    }

    public static String getMethodSignature(ClassFinder scope, String returnType, String... argTypes) {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        for (String argType : argTypes) {
            sb.append(getTypeSignature(argType, scope));
        }
        sb.append(")");
        sb.append(getTypeSignature(returnType, scope));
        return sb.toString();
    }

    public static String getClassSignature(ClassFinder scope, Collection<String> typeParameters, String superType,
            String... interfaces) {

        ClassFinder newScope = new ClassFinder(null, scope);

        StringBuilder sb = new StringBuilder();
        if (typeParameters != null && !typeParameters.isEmpty()) {
            sb.append("<");
            for (String param : typeParameters) {
                String[] parts = param.split(" extends ");
                String boundType = "java.lang.Object";
                if (parts.length > 1) {
                    boundType = parts[1].trim().split(" ")[0];
                }
                parts[0] = parts[0].trim();
                sb.append(parts[0]).append(":").append(getTypeSignature(boundType, scope));
                newScope.addTypeParameter(parts[0], boundType);

            }
            sb.append(">");
        }
        sb.append(getTypeSignature(superType, newScope));
        if (interfaces != null && interfaces.length > 0) {
            for (String iface : interfaces) {
                sb.append(getTypeSignature(iface, newScope));
            }
        }

        return sb.toString();
    }

    public static String getTypeSignature(String type, ClassFinder scope) {
        return getTypeSignature(type, scope, false);
    }

    public static String getTypeSignature(String type, ClassFinder scope, boolean isGenericAlias) {

        if (isArrayType(type)) {
            int dim = getArrayTypeDimension(type);
            String elType = getArrayElementType(type);
            String elSig = getTypeSignature(elType, scope);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < dim; i++) {
                sb.append("[");
            }
            sb.append(elSig);
            return sb.toString();
        } else if (isPrimitiveType(type)) {
            return getDescriptor(type);
        } else {
            String fullType = type;
            String[] generics = null;

            int lePos = type.indexOf("<");
            if (lePos != -1) {
                type = type.substring(0, lePos);
                String genericsStr = fullType.substring(lePos + 1, fullType.lastIndexOf(">"));
                List<String> g = new ArrayList<>();
                char c;
                int pos = 0;
                int l1 = 0;
                int l2 = 0;
                char[] chars = genericsStr.toCharArray();
                int len = chars.length;
                int mark = 0;
                while (pos < len) {
                    c = chars[pos];
                    switch (c) {
                    case '<':
                        l1++;
                        break;
                    case '>':
                        l1--;
                        break;
                    case '[':
                        l2++;
                        break;
                    case ']':
                        l2--;
                        break;
                    case ',':
                        if (l1 == 0) {
                            g.add(genericsStr.substring(mark, pos).trim());
                            mark = pos + 1;
                        }
                    }

                    pos++;
                }

                g.add(genericsStr.substring(mark, pos).trim());
                generics = g.toArray(new String[0]);

            }
            StringBuilder sb = new StringBuilder();
            if (scope.isTypeParameter(type)) {
                sb.append("T").append(type);
            } else {
                ClassNode baseNode = scope.findStub(type);
                if (baseNode == null) {
                    throw new RuntimeException("Could not find class " + type);
                }

                sb.append("L").append(baseNode.name);
            }
            if (generics != null) {
                sb.append("<");
                for (String g : generics) {
                    //System.out.println("Looking for type signature of "+g);
                    //System.out.println("Type parameters in scope: "+scope.getTypeParameters());
                    sb.append(getTypeSignature(g, scope, true));
                }
                sb.append(">");
            }
            sb.append(";");
            return sb.toString();

        }

    }

    /**
     * Gets the descriptor for a specified internal type.
     * @param internalName The internal name of the type.  E.g. java/lang/Object
     * @return The descriptor.  E.g. Ljava/lang/Object;
     */
    public static String getDescriptor(String internalName) {
        if (isPrimitiveType(internalName)) {
            return getPrimitiveDescriptor(internalName);
        } else {
            return "L" + internalName + ";";
        }
    }

    /**
     * Returns a descriptor for array type with the given element internal name
     * @param internalName The internal name of the element type.  E.g. 
     * java/lang/Object
     * @param dimensions  The number of dimensions to make the array type.
     * @return The array descriptor.  E.g. [[Ljava/lang/Object;
     */
    public static String getArrayDescriptor(String internalName, int dimensions) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < dimensions; i++) {
            sb.append("[");
        }
        sb.append(getDescriptor(internalName));
        return sb.toString();
    }

    /**
     * Checks to see if a given type is an array type.
     * @param type  The type in dot notation.  E.g. java.lang.Object[]
     * @return True if type is array type.
     */
    public static boolean isArrayType(String type) {
        return type.endsWith("[]");
    }

    /**
     * Returns the number of dimensions in an array type.  E.g. Object[] =>1,
     * Object[][] => 2 etc...
     * @param type
     * @return 
     */
    public static int getArrayTypeDimension(String type) {
        String parts[] = type.replaceAll("<[^>]*>", "").split("\\[");
        return parts.length - 1;
    }

    /**
     * Converts an array type (e.g. Object[] to its element type e.g. Object)
     * @param type
     * @return 
     */
    public static String getArrayElementType(String type) {
        if (!isArrayType(type)) {
            return null;
        } else {
            int lePos = type.lastIndexOf(">");
            if (lePos < 0)
                lePos = 0;
            return type.substring(0, type.indexOf("[", lePos));
        }
    }

    /**
     * Gets the array type for a scalar type. 
     * @param elementType The element type in dot notation. E.g. 
     * java.lang.Object
     * @param dimension The dimension of the array to create.
     * @return Array type in dot notation. e.g. java.lang.Object[]
     */
    public static String getArrayType(String elementType, int dimension) {
        StringBuilder sb = new StringBuilder();
        sb.append(elementType);
        for (int i = 0; i < dimension; i++) {
            sb.append("[]");
        }
        return sb.toString();
    }

    /**
     * Converts modifier flags from Javac Tree into int flags usable in TypeMirror
     * @param mods
     * @return 
     */
    public static int getFlags(Set<Modifier> mods) {
        int flags = 0;
        for (Modifier m : mods) {
            switch (m) {
            case ABSTRACT:
                flags |= Opcodes.ACC_ABSTRACT;
                break;
            case FINAL:
                flags |= Opcodes.ACC_FINAL;
                break;
            case PRIVATE:
                flags |= Opcodes.ACC_PRIVATE;
                break;
            case PROTECTED:
                flags |= Opcodes.ACC_PROTECTED;
                break;
            case PUBLIC:

                flags |= Opcodes.ACC_PUBLIC;
                break;
            case STATIC:
                flags |= Opcodes.ACC_STATIC;
                break;

            }
        }

        return flags;
    }

}