alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.modules.javacore.parser;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.*;
import org.netbeans.modules.classfile.*;
import org.netbeans.modules.javacore.jmiimpl.javamodel.FeatureImpl;
import org.netbeans.modules.javacore.jmiimpl.javamodel.JavaClassImpl;
import org.openide.filesystems.FileObject;

public final class ClassFileInfoUtil {
    private static final String NAME_CLASS_INIT = "".intern(); // NOI18N
    private static final String NAME_INIT = "".intern(); // NOI18N
    
    public static ClassInfo createClassInfo(FileObject folder, String partName, int mods) {
        FileObject file = null;
        try {
            file = folder.getFileObject(partName.replace('.', '$'), "class"); // NOI18N
        } catch (Exception e) {
        }
        if (file == null) {
            throw new RuntimeException("File object for " + partName + " not found"); // NOI18N
        }
        return createClassInfo (folder, file, mods);
    }
    
    public static ClassInfo createClassInfo(FileObject folder, FileObject file, int mods) {
        ClassFile clsFile;
        
        try {
            InputStream is=file.getInputStream();
            try {
                clsFile = new ClassFile(is, true);
            } finally {
                is.close();
            }
        } catch (Exception ex) {
            throw new RuntimeException("Inconsistent storage: class file for " + file.getNameExt() + " not created"); // NOI18N
        }
        
        String name = clsFile.getName().getExternalName();
        if (mods < 0) {
            mods = (clsFile.getAccess() & ~Access.SYNCHRONIZED) | (clsFile.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
        }
        boolean isInterface = (mods & Access.INTERFACE) > 0;
        String typeSignature = clsFile.getTypeSignature();
        boolean isGeneric = typeSignature != null;
        TypeParamInfo[] tpi = null;
        NameRef[] interfaces;
        NameRef superName;

        if (isGeneric) {
            char[] sigChars = typeSignature.toCharArray();
            int[] pos = new int[] {0};
            tpi = parseTypeParams(sigChars, pos);
            superName = (NameRef)sigToTypeRef(sigChars, pos);
            ArrayList list = new ArrayList(6);
            while (pos[0] < sigChars.length) {
                list.add(sigToTypeRef(sigChars, pos));
            }
            interfaces = new NameRef[list.size()];
            list.toArray(interfaces);
        } else {
            ClassName className = clsFile.getSuperClass();
            superName = null;
            if (className != null) {
                superName = new NameRef(className.getExternalName(), null, null);
            }

            Collection coll = clsFile.getInterfaces();
            int size = coll.size();
            interfaces = new NameRef[size];
            Iterator iter = coll.iterator();            
            for (int x = 0; iter.hasNext(); x++) {
                interfaces[x] = new NameRef(((ClassName) iter.next()).getExternalName(), null, null);
            }
        }
        
        boolean isAnnotation = clsFile.isAnnotation();
        int methodCount = clsFile.getMethodCount();
        int fieldCount = clsFile.getVariableCount();
        Collection innerClasses = clsFile.getInnerClasses();
        ClassName clsName = clsFile.getName();
        List featuresList = new ArrayList (innerClasses.size() + methodCount + fieldCount);
        for (Iterator it = innerClasses.iterator(); it.hasNext();) {
            InnerClass innerClass = (InnerClass) it.next();
            ClassName outerName = innerClass.getOuterClassName();
            if (clsName.equals(outerName)) {                                
                String fn = innerClass.getName().getSimpleName();
                
                int index = fn.lastIndexOf ('.') + 1;
                if ((index > 0) && (fn.length() > index) && Character.isDigit(fn.charAt (index))) {
                    continue;
                }
        
                fn = fn.replace('.', '$');
                FileObject fo = folder.getFileObject(fn, "class"); // NOI18N
                if (fo != null) {
                    featuresList.add(createClassInfo(folder, fo, -1));
                }
            }
        }

        Iterator iter = clsFile.getMethods().iterator();
        for (int x = 0; x < methodCount; x++) {
            Method method = (Method) iter.next();
            if (!method.isSynthetic()) {
                if (isAnnotation) {
                    featuresList.add(createAttributeInfo(method));
                } else {
                    featuresList.add(createMethodInfo(name, method));
                }
            }
        }
        List enumConstants = new LinkedList();
        iter = clsFile.getVariables().iterator();
        for (int x = 0 ; x < fieldCount; x++) {
            Variable variable = (Variable) iter.next();
            if (!variable.isSynthetic()) {
                if (variable.isEnumConstant()) {
                    enumConstants.add(variable);
                } else {
                    featuresList.add(createFieldInfo (variable));
                }
            }
        }
        FeatureInfo[] features = new FeatureInfo[featuresList.size()];
        featuresList.toArray(features);
        AnnotationInfo[] annos = createAnnotations(clsFile.getAnnotations());
        
        if (clsFile.isEnum()) {
            ElementInfo[] constants = new ElementInfo[enumConstants.size()];
            Iterator it = enumConstants.iterator();
            for (int x = 0; it.hasNext(); x++) {
                Variable c = (Variable)it.next();
                constants[x] = new FeatureInfo(null, FeatureInfo.ENUM_CONSTANT_TYPE, (String)c.getName(), 0, null);
            }
            return new EnumInfo(
                null, EnumInfo.ENUM_TYPE, name, mods, features, interfaces, constants, annos
            );
        } else if (isAnnotation) {
            return new AnnotationTypeInfo(null, AnnotationTypeInfo.ANNOTATIONTYPE_TYPE, name, mods,
                features, annos
            );
        } else {
            return new ClassInfo(null,
                isInterface ? ClassInfo.INTERFACE_TYPE : ClassInfo.CLASS_TYPE,
                name, mods, features, superName, interfaces, tpi, annos
            );
        }
    }
    
    public static FeatureInfo createMethodInfo (String className, Method method) {        
        String name = method.getName();
        int mods = method.getAccess() | (method.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
        AnnotationInfo[] annos = createAnnotations(method.getAnnotations());
        if (NAME_CLASS_INIT.equals(name)) {
            int infoType = (mods & Access.STATIC) > 0 ? FeatureInfo.STATIC_INITIALIZER_TYPE :
                FeatureInfo.INSTANCE_INITIALIZER_TYPE;
            return new FeatureInfo (null, infoType, name, mods, annos);
        }
        
        char[] sig = method.getDescriptor().toCharArray();
        String typeSignature = method.getTypeSignature();
        char[] typeSig = typeSignature == null ? null : typeSignature.toCharArray();
        int[] pos = new int[] {1};
        ParameterInfo[] params;
        TypeParamInfo[] tpi = null;

        if (typeSignature == null) {
            params = createParamsInfo(method, sig, pos);
        } else {
            pos[0] = 0;
            tpi = parseTypeParams(typeSig, pos);
            List list = getParamTypes(typeSig, pos);
            Iterator paramsIter = method.getParameters().iterator();
            Iterator iter = list.iterator();
            params = new ParameterInfo[list.size()];
            for (int x = 0; iter.hasNext(); x++) {
                TypeRef type = (TypeRef)iter.next();
                boolean isVarArgs = !iter.hasNext() && method.isVarArgs();
                String paramName = paramsIter.hasNext() ? ((Parameter)paramsIter.next()).getName() : "";
                params[x] = new ParameterInfo (null, ParameterInfo.PARAMETER_TYPE, paramName, false, type, isVarArgs);
            }
        }
        
        TypeRef type;
        int infoType;
        if (NAME_INIT.equals(name)) {
            infoType = MethodInfo.CONSTRUCTOR_TYPE;
            type = new NameRef(className, null, null);
            if (typeSignature == null) {
                sigToTypeRef(sig, pos);
            } else {
                pos[0]++;
                sigToTypeRef(typeSig, pos);
            }
        } else {
            infoType = MethodInfo.METHOD_TYPE;
            if (typeSignature == null) {
                type = sigToTypeRef(sig, pos);
            } else {
                pos[0]++;
                type = sigToTypeRef(typeSig, pos);
            }
        }
        
        TypeParamRef[] excNames;
        if (typeSignature == null) {
            CPClassInfo[] exceptions = method.getExceptionClasses();
            excNames = new TypeParamRef[exceptions.length];
            for (int x = 0; x < exceptions.length; x++) {
                excNames[x] = new NameRef(exceptions[x].getClassName().getExternalName(), null, null);
            }
        } else {
            ArrayList list = new ArrayList();
            while (pos[0] < typeSig.length) {
                if (typeSig[pos[0]] == '^')
                    pos[0]++; 
                list.add(sigToTypeRef(typeSig, pos));
            }
            excNames = new TypeParamRef[list.size()];
            list.toArray(excNames);
        }
        
        return new MethodInfo (null, infoType, name, mods, type, params, excNames, tpi, annos);
    }

    public static FieldInfo createFieldInfo(Variable field) {
        int mods = field.getAccess() | (field.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
        String name = field.getName();
        AnnotationInfo[] annos = createAnnotations(field.getAnnotations());
        String typeSignature = field.getTypeSignature();
        char[] signature = typeSignature != null ? typeSignature.toCharArray() : field.getDescriptor().toCharArray();
        int[] pos = new int[] {0};
        TypeRef type = sigToTypeRef(signature, pos);
        return new FieldInfo (null, FieldInfo.FIELD_TYPE, name, mods, type, FieldInfo.SINGLE_FIELD_INDEX, annos);
    }
    
    public static AttributeInfo createAttributeInfo(Method method) {
        int mods = method.getAccess() | (method.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
        String name = method.getName();
        AnnotationInfo[] annos = createAnnotations(method.getAnnotations());
        String desc = method.getDescriptor();
        int index = desc.indexOf(')');
        TypeRef type = sigToTypeRef(desc.substring(index + 1).toCharArray(), new int[] {0});
        ElementValue defValue = method.getAnnotationDefault();
        AnnotationValueInfo defaultValueInfo = defValue == null ? null : new AnnotationValueInfo(
            null, getElementValueType(defValue), name, resolveElementValue(defValue)
        );
        return new AttributeInfo(null, AttributeInfo.ATTRIBUTE_TYPE, name, mods, type, defaultValueInfo, annos);
    }
    
    public static AnnotationInfo[] createAnnotations(Collection annos) {
        if (annos == null || annos.size() == 0) {
            return ElementInfo.EMPTY_ANNOTATIONS;
        }
        AnnotationInfo[] result = new AnnotationInfo[annos.size()];
        Iterator iter = annos.iterator();
        for (int x = 0; iter.hasNext(); x++) {
            result[x] = annotationToInfo((Annotation)iter.next());
        }
        return result;
    }
    
    public static AnnotationInfo annotationToInfo(Annotation anno) {
        String name = anno.getType().getExternalName();
        AnnotationComponent[] comps = anno.getComponents();
        AnnotationValueInfo[] values = new AnnotationValueInfo[comps.length];
        for (int x = 0; x < comps.length; x++) {
            values[x] = annotationComponentToInfo(comps[x]);
        }
        return new AnnotationInfo(null, AnnotationInfo.ANNOTATION_TYPE, name, values);
    }
    
    public static AnnotationValueInfo annotationComponentToInfo(AnnotationComponent comp) {
        int infoType = getElementValueType(comp.getValue());
        return new AnnotationValueInfo(null, infoType, comp.getName(), resolveElementValue(comp.getValue()));
    }
    
    public static int getElementValueType(ElementValue elemValue) {
        int infoType;
        if (elemValue instanceof ArrayElementValue) {
            infoType = AnnotationValueInfo.ANNOTATIONVALUE_ARRAY;
        } else if (elemValue instanceof PrimitiveElementValue) {
            infoType = AnnotationValueInfo.ANNOTATIONVALUE_STRING;
        } else if (elemValue instanceof ClassElementValue) {
            infoType = AnnotationValueInfo.ANNOTATIONVALUE_STRING;
        } else if (elemValue instanceof EnumElementValue) {
            infoType = AnnotationValueInfo.ANNOTATIONVALUE_STRING; // [PENDING]
        } else { // NestedElementValue
            infoType = AnnotationValueInfo.ANNOTATIONVALUE_ANNOTATION;
        }
        return infoType;
    }
    
    public static Object resolveElementValue(ElementValue elem) {
        if (elem instanceof ArrayElementValue) {
            ElementValue[] arrayValues = ((ArrayElementValue)elem).getValues();
            Object[] value = new Object[arrayValues.length];
            for (int x = 0; x < arrayValues.length; x++) {
                value[x] = resolveElementValue(arrayValues[x]);
            }
            return value;
        }
        if (elem instanceof PrimitiveElementValue) {
            return ((PrimitiveElementValue)elem).getValue().getValue().toString();
        }
        if (elem instanceof ClassElementValue) {
            return ((ClassElementValue)elem).getClassName().getExternalName();
        }
        if (elem instanceof EnumElementValue) {
            return ((EnumElementValue)elem).getEnumName(); // [PENDING]
        }
        return annotationToInfo(((NestedElementValue)elem).getNestedValue());
    }
        
    public static NameRef sigToNameRef(char[] signature, int[] i, NameRef parent) {
        StringBuffer name = new StringBuffer();
        for (; signature[i[0]] != ';' && signature[i[0]] != '<'; i[0]++) {
            char ch = signature[i[0]];
            if (ch=='/' || ch=='$') { 
                ch='.';
            }
            if (name.length() > 0 || ch != '.')
                name.append(ch);
        }
        
        if (signature[i[0]] == ';')
            return new NameRef(name.toString(), parent, null);
        
        i[0]++;
        ArrayList typeParams = new ArrayList(5);
        while(signature[i[0]] != '>') {
            char ch = signature[i[0]];
            if (ch == '*') {
                typeParams.add(new WildCardRef(false, null));
                i[0]++;
            } else if (ch == '+' || ch == '-') {
                i[0]++;
                TypeParamRef tr = (TypeParamRef) sigToTypeRef(signature, i);
                typeParams.add(new WildCardRef(ch == '-', tr));
            } else {
                typeParams.add(sigToTypeRef(signature, i));
            }
        }
        i[0]++;
        TypeRef[] typeRefs = new TypeRef[typeParams.size()];
        typeParams.toArray(typeRefs);
        return new NameRef(name.toString(), parent, typeRefs);
    }
    
    public static TypeRef sigToTypeRef(char[] signature, int[] i) {
        char c = (char) signature[i[0]];
        switch (c) {
            case 'B':
                i[0]++;
                return PrimitiveTypeRef.BYTE;
            case 'C':
                i[0]++;
                return PrimitiveTypeRef.CHAR;
            case 'D':
                i[0]++;
                return PrimitiveTypeRef.DOUBLE;
            case 'F':
                i[0]++;
                return PrimitiveTypeRef.FLOAT;
            case 'I':
                i[0]++;
                return PrimitiveTypeRef.INT;
            case 'J':
                i[0]++;
                return PrimitiveTypeRef.LONG;
            case 'T':
                i[0]++;
                int pos;
                StringBuffer buf = new StringBuffer(40);
                for (pos = i[0]; (pos < signature.length) && (signature[pos] != ';'); pos++) {
                    char ch = signature[pos];
                    if (ch=='/' || ch=='$') ch='.'; 
                    buf.append(ch);
                }
                i[0] = pos + 1;     
                return new TypeParamRef(buf.toString());
            case 'L':
                i[0]++;
                NameRef nameRef = null;
                while (signature[i[0]] != ';') {
                    nameRef = sigToNameRef(signature, i, nameRef);
                }
                i[0]++;
                return nameRef;
            case 'S':
                i[0]++;
                return PrimitiveTypeRef.SHORT;
            case 'V':
                i[0]++;
                return PrimitiveTypeRef.VOID;
            case 'Z':
                i[0]++;
                return PrimitiveTypeRef.BOOLEAN;
            case '[':
                int dimCount = 0;
                while (signature[i[0]] == '[') {
                    dimCount++;
                    i[0]++;
                }
                return new ArrayRef((PrimitiveTypeRef)sigToTypeRef(signature, i), dimCount);
            case ')':
                i[0]++;
                return null;
            default:
                throw new IllegalArgumentException("Unknown signature: " + new String(signature) + ' ' + i[0]); // NOI18N
        }
    }
    
    public static TypeParamInfo[] parseTypeParams(char[] sig, int[] i) {
        Iterator iter;
        List infos = new ArrayList();
        if (sig[0] == '<') {
            i[0] = 1;
            while (sig[i[0]] != '>') {
                // identifier
                StringBuffer id = new StringBuffer();
                while (sig[i[0]] != ':') {
                    id.append(sig[i[0]]);
                    i[0]++;
                } // while
                if (sig[i[0] + 1] == ':') {
                    i[0]++;
                }
                ArrayList bounds = new ArrayList();
                while (sig[i[0]] == ':') {
                    i[0]++;
                    bounds.add(sigToTypeRef(sig, i));
                } // while
                NameRef[] bds = new NameRef[bounds.size()];
                iter = bounds.iterator();
                for (int x = 0; iter.hasNext(); x++) {
                    bds[x] = (NameRef) iter.next();
                }
                infos.add(new TypeParamInfo(null, TypeParamInfo.TYPEPARAM_TYPE, id.toString(), bds));
            } // while
            i[0]++;
        } // if
        TypeParamInfo[] tpi = new TypeParamInfo[infos.size()];
        iter = infos.iterator();
        for (int x = 0; iter.hasNext(); x++) {
            tpi[x] = (TypeParamInfo)iter.next();
        }
        return tpi;
    }
    
    public static List getParamTypes (char[] signature, int[] pos) {
        List params = new LinkedList();
        pos[0]++;
        while (signature[pos[0]] != ')') {
            params.add(sigToTypeRef(signature, pos));
        }
        return params;
    }

    public static ParameterInfo[] createParamsInfo (Method method, char[] signature, int[] pos) {
        List params = new ArrayList();
        Iterator paramsIter = method.getParameters().iterator();
        while (true) {
            TypeRef parType = sigToTypeRef(signature, pos);
            if (parType != null) {
                String paramName = paramsIter.hasNext() ? ((Parameter)paramsIter.next()).getName() : "";
                ParameterInfo info = new ParameterInfo (null, ParameterInfo.PARAMETER_TYPE,
                    paramName, false, parType, false);
                params.add(info);
            } 
            else
                break;
        }
        ParameterInfo[] parInfos = (ParameterInfo[]) params.toArray(new ParameterInfo[params.size()]);
        if (method.isVarArgs()) {
            // [PENDING]
            parInfos[parInfos.length - 1] = new ParameterInfo(
                null, ParameterInfo.PARAMETER_TYPE, parInfos[parInfos.length - 1].name,
                false, parInfos[parInfos.length - 1].type, true
            );
        }
        return parInfos;
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.