/******************************************************************************* * Copyright (c) 2006-2014 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.emftext.language.java.resource; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.bcel5_2_0.classfile.Attribute; import org.apache.bcel5_2_0.classfile.ClassParser; import org.apache.bcel5_2_0.classfile.JavaClass; import org.apache.bcel5_2_0.classfile.Signature; import org.apache.bcel5_2_0.classfile.Utility; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.emftext.language.java.JavaClasspath; import org.emftext.language.java.annotations.AnnotationsFactory; import org.emftext.language.java.arrays.ArraysFactory; import org.emftext.language.java.classifiers.Annotation; import org.emftext.language.java.classifiers.Class; import org.emftext.language.java.classifiers.Classifier; import org.emftext.language.java.classifiers.ClassifiersFactory; import org.emftext.language.java.classifiers.ConcreteClassifier; import org.emftext.language.java.classifiers.Enumeration; import org.emftext.language.java.classifiers.Interface; import org.emftext.language.java.containers.CompilationUnit; import org.emftext.language.java.containers.ContainersFactory; import org.emftext.language.java.generics.GenericsFactory; import org.emftext.language.java.generics.QualifiedTypeArgument; import org.emftext.language.java.generics.TypeArgument; import org.emftext.language.java.generics.TypeParameter; import org.emftext.language.java.generics.TypeParametrizable; import org.emftext.language.java.generics.UnknownTypeArgument; import org.emftext.language.java.members.Constructor; import org.emftext.language.java.members.EnumConstant; import org.emftext.language.java.members.Field; import org.emftext.language.java.members.Member; import org.emftext.language.java.members.MembersFactory; import org.emftext.language.java.members.Method; import org.emftext.language.java.modifiers.AnnotableAndModifiable; import org.emftext.language.java.modifiers.ModifiersFactory; import org.emftext.language.java.parameters.Parameter; import org.emftext.language.java.parameters.ParametersFactory; import org.emftext.language.java.types.ClassifierReference; import org.emftext.language.java.types.TypeReference; import org.emftext.language.java.types.TypedElement; import org.emftext.language.java.types.TypesFactory; /** * This class constructs a Java EMF-model from a class file using the Byte Code * Engineering Library (BCEL). */ public class ClassFileModelLoader { protected JavaClasspath javaClasspath = null; protected ClassifiersFactory qualifiersFactory = ClassifiersFactory.eINSTANCE; protected MembersFactory membersFactory = MembersFactory.eINSTANCE; protected TypesFactory typesFactory = TypesFactory.eINSTANCE; protected ParametersFactory parametersFactory = ParametersFactory.eINSTANCE; protected AnnotationsFactory annotationsFactory = AnnotationsFactory.eINSTANCE; public ClassFileModelLoader(JavaClasspath javaClasspath) { super(); this.javaClasspath = javaClasspath; } public CompilationUnit parse(InputStream inputStream, String classFileName) throws IOException { try { ClassParser classParser = new ClassParser(inputStream, classFileName); JavaClass myClass = classParser.parse(); ConcreteClassifier classifier = constructClassifier(myClass); CompilationUnit cu = ContainersFactory.eINSTANCE.createCompilationUnit(); cu.setName(classFileName); List<String> namespace1 = Arrays.asList(myClass.getClassName().split("\\.")); List<String> namespace2 = Arrays.asList(namespace1.get(namespace1.size() - 1).split("\\$")); cu.getNamespaces().addAll(namespace1.subList(0, namespace1.size() - 1)); if (myClass.getClassName().endsWith("$")) { //empty class name cu.getNamespaces().addAll(namespace2.subList(0, namespace2.size())); } else { cu.getNamespaces().addAll(namespace2.subList(0, namespace2.size() - 1)); } cu.getClassifiers().add(classifier); return cu; } catch (Exception e) { e.printStackTrace(); throw new IOException(e.getMessage(), e); } } protected ConcreteClassifier constructClassifier(JavaClass clazz) { ConcreteClassifier emfClassifier = null; if (clazz.isEnum()) { //check first, because enum is also class emfClassifier = qualifiersFactory.createEnumeration(); } else if (clazz.isAnnotation()) { emfClassifier = qualifiersFactory.createAnnotation(); } else if (clazz.isClass()) { emfClassifier = qualifiersFactory.createClass(); } else if (clazz.isInterface()) { emfClassifier = qualifiersFactory.createInterface(); } else { assert(false); return null; } String className = clazz.getClassName(); int idx = clazz.getClassName().lastIndexOf("$"); if (idx >= 0) { className = className.substring(idx + 1); } else { idx = clazz.getClassName().lastIndexOf("."); if (idx >= 0) { className = className.substring(idx + 1); } } emfClassifier.setName(className); for (Attribute a : clazz.getAttributes()) { String signature = a.toString(); if(signature.startsWith("Signature(")) { EList<TypeParameter> tpList = constructTypeParameters(signature); emfClassifier.getTypeParameters().addAll(tpList); } } String typeArgumentSig = ""; for (Attribute a : clazz.getAttributes()) { String s = a.toString(); s = s.replaceAll("\\[", ""); if (s.startsWith("Signature(L")) { typeArgumentSig = s.substring(s.indexOf("(") + 1, s.indexOf(")")); } if (s.startsWith("Signature(<")) { typeArgumentSig = s.substring(s.indexOf(";>L") + 2, s.indexOf(")")); } } //super class if (clazz.isClass() && !clazz.isEnum()) { org.emftext.language.java.classifiers.Class emfClass = (Class) emfClassifier; if (clazz.getSuperclassName() != null) { emfClass.setExtends(createReferenceToClassifier(clazz.getSuperclassName())); typeArgumentSig = constructTypeArguments(typeArgumentSig, (ClassifierReference)emfClass.getExtends(), null, emfClassifier); } } else { //cut away the Object signature which is there also for interfaces typeArgumentSig = constructTypeArguments(typeArgumentSig, null, null, emfClassifier); } //interfaces for (String ifName : clazz.getInterfaceNames()) { TypeReference typeArg = createReferenceToClassifier(ifName); typeArgumentSig = constructTypeArguments(typeArgumentSig, (ClassifierReference)typeArg, null, emfClassifier); if (clazz.isEnum()) { //check first, because enum is also class ((Enumeration)emfClassifier).getImplements().add(typeArg); } else if (clazz.isAnnotation()) { // } else if (clazz.isClass()) { ((Class)emfClassifier).getImplements().add(typeArg); } else if (clazz.isInterface()) { ((Interface)emfClassifier).getExtends().add(typeArg); } } for (org.apache.bcel5_2_0.classfile.Field field : clazz.getFields()) { if (field.isEnum() && emfClassifier instanceof Enumeration) { ((Enumeration)emfClassifier).getConstants().add(constructEnumConstant(field)); } else { emfClassifier.getMembers().add(constructField(field, emfClassifier)); } } for (org.apache.bcel5_2_0.classfile.Method method : clazz.getMethods()) { if (!method.isSynthetic()) { Member emfMember = constructMethod(method, emfClassifier, false); //If the last parameter has an array type it could also be a variable length parameter. //The java compiler compiles variable length arguments down to array arguments. //Then the arguments are wrapped into an array. As far as I know, there is no //way to tell the difference from byte code. Therefore we create two versions //of the method: one with array argument and one with variable length if (emfMember instanceof Method && !((Method)emfMember).getParameters().isEmpty() && !((Method)emfMember).getParameters().get( ((Method)emfMember).getParameters().size()-1).getArrayDimensionsBefore().isEmpty()) { Member emfMethod2 = constructMethod(method, emfClassifier, true); emfClassifier.getMembers().add(emfMethod2); } else { emfClassifier.getMembers().add(emfMember); } } } constructModifiers(emfClassifier, clazz); return emfClassifier; } protected Member constructMethod(org.apache.bcel5_2_0.classfile.Method method, ConcreteClassifier emfClassifier, boolean withVariableLength) { Method emfMethod = null; if (emfClassifier instanceof Annotation) { emfMethod = annotationsFactory.createAnnotationAttribute(); } else if(emfClassifier instanceof Interface) { emfMethod = membersFactory.createInterfaceMethod(); } else { emfMethod = membersFactory.createClassMethod(); } emfMethod.setName(method.getName()); String signature = method.getReturnType().getSignature(); String plainSignature = ""; for (Attribute a : method.getAttributes()) { if (a instanceof Signature) { String s = a.toString(); // TODO can we replace this with replace("[", "")? s = s.replaceAll("\\[", ""); plainSignature = s; break; } } ((TypeParametrizable) emfMethod).getTypeParameters().addAll(constructTypeParameters(plainSignature)); TypeReference typeRef = createReferenceToType(signature); TypeReference typeParamRef = constructReturnTypeParameterReference(plainSignature, emfMethod, emfClassifier); if (typeParamRef != null) { ((TypeParameter)((ClassifierReference)typeParamRef).getTarget()).getExtendTypes().add(typeRef); typeRef = typeParamRef; } emfMethod.setTypeReference(typeRef); int arrayDimension = getArrayDimension(signature); for(int i = 0; i < arrayDimension; i++) { emfMethod.getArrayDimensionsBefore().add( ArraysFactory.eINSTANCE.createArrayDimension()); } List<String> parameterNames = extractParameterNames(method); for(int i = 0; i < method.getArgumentTypes().length; i++) { org.apache.bcel5_2_0.generic.Type argType = method.getArgumentTypes()[i]; String paramName; if (parameterNames.size() > i) { paramName = parameterNames.get(i); } else { paramName = "arg" + i; } if (i == method.getArgumentTypes().length - 1 && withVariableLength) { emfMethod.getParameters().add( constructVariableLengthParameter(argType, paramName)); } else { emfMethod.getParameters().add( constructParameter(argType, paramName)); } } EList<TypeReference> tpList = constructMethodTypeParameterReferences(plainSignature, (Method) emfMethod, emfClassifier); for(int i = 0; i<tpList.size(); i++) { TypeReference typeParameterReference = tpList.get(i); if(typeParameterReference != null) { TypeReference typeReference = emfMethod.getParameters().get(i).getTypeReference(); if(typeReference instanceof ClassifierReference) { //replace with parameter there is one ((TypeParameter)((ClassifierReference)typeParameterReference).getTarget()).getExtendTypes().add(typeReference); emfMethod.getParameters().get(i).setTypeReference(typeParameterReference); } } } if(!"".equals(plainSignature) && !(emfClassifier instanceof Enumeration)) { if(typeRef instanceof ClassifierReference) { String returnSignature = plainSignature.substring(0, plainSignature.lastIndexOf(")")); returnSignature = returnSignature.substring(returnSignature.lastIndexOf(")") + 1); constructTypeArguments(returnSignature, (ClassifierReference) typeRef, (TypeParametrizable) emfMethod, emfClassifier); } String argumentSignature = plainSignature.substring(plainSignature.lastIndexOf("(") + 1, plainSignature.indexOf(")")); for(Parameter parameter : emfMethod.getParameters()) { TypeReference parameterTypeRef = parameter.getTypeReference(); if(parameterTypeRef instanceof ClassifierReference) { argumentSignature = constructTypeArguments(argumentSignature, (ClassifierReference) parameterTypeRef, emfMethod, emfClassifier); } else { argumentSignature = constructTypeArguments(argumentSignature, null, emfMethod, emfClassifier); } } } if (emfMethod.getName().equals("<init>")) { Constructor constructor = MembersFactory.eINSTANCE.createConstructor(); constructor.getTypeParameters().addAll(emfMethod.getTypeParameters()); constructor.getParameters().addAll(emfMethod.getParameters()); constructor.setName(emfClassifier.getName()); return constructor; } constructModifiers(emfMethod, method); return (Member) emfMethod; } protected Parameter constructParameter(org.apache.bcel5_2_0.generic.Type attrType, String paramName) { Parameter emfParameter = parametersFactory.createOrdinaryParameter(); String signature = attrType.getSignature(); TypeReference emfTypeReference = createReferenceToType(signature); emfParameter.setTypeReference(emfTypeReference); emfParameter.setName(paramName); int arrayDimension = getArrayDimension(signature); for(int i = 0; i < arrayDimension; i++) { emfParameter.getArrayDimensionsBefore().add( ArraysFactory.eINSTANCE.createArrayDimension()); } return emfParameter; } protected Parameter constructVariableLengthParameter(org.apache.bcel5_2_0.generic.Type attrType, String paramName) { Parameter emfParameter = parametersFactory.createVariableLengthParameter(); String signature = attrType.getSignature(); TypeReference emfTypeReference = createReferenceToType(signature); emfParameter.setTypeReference(emfTypeReference); emfParameter.setName(paramName); int arrayDimension = getArrayDimension(signature) - 1; for(int i = 0; i < arrayDimension; i++) { emfParameter.getArrayDimensionsBefore().add( ArraysFactory.eINSTANCE.createArrayDimension()); } return emfParameter; } protected Field constructField(org.apache.bcel5_2_0.classfile.Field field, ConcreteClassifier emfClassifier) { Field emfField = membersFactory.createField(); emfField.setName(field.getName()); String signature = field.getType().getSignature(); String plainSignature = ""; for(Attribute a : field.getAttributes()){ String s = a.toString(); if(s.startsWith("Signature(")) { s = s.replaceAll("\\[", ""); plainSignature = s.substring(s.indexOf("(") + 1, s.lastIndexOf(")")); break; } } TypeReference typeRef = createReferenceToType(signature); TypeReference typeParamRef = constructReturnTypeParameterReference(plainSignature, emfField, emfClassifier); if(typeParamRef != null) { ((TypeParameter)((ClassifierReference)typeParamRef).getTarget()).getExtendTypes().add(typeRef); typeRef = typeParamRef; } emfField.setTypeReference(typeRef); int arrayDimension = getArrayDimension(signature); for(int i = 0; i < arrayDimension; i++) { emfField.getArrayDimensionsBefore().add( ArraysFactory.eINSTANCE.createArrayDimension()); } if(!"".equals(plainSignature) && typeRef instanceof ClassifierReference) { constructTypeArguments(plainSignature, (ClassifierReference) typeRef, null, emfClassifier); } constructModifiers(emfField, field); return emfField; } protected void constructModifiers(AnnotableAndModifiable emfMember, org.apache.bcel5_2_0.classfile.AccessFlags member) { ModifiersFactory f = ModifiersFactory.eINSTANCE; if (member.isAbstract()) { emfMember.getAnnotationsAndModifiers().add(f.createAbstract()); } if (member.isFinal()) { emfMember.getAnnotationsAndModifiers().add(f.createFinal()); } if (member.isNative()) { emfMember.getAnnotationsAndModifiers().add(f.createNative()); } if (member.isPrivate()) { emfMember.getAnnotationsAndModifiers().add(f.createPrivate()); } if (member.isProtected()) { emfMember.getAnnotationsAndModifiers().add(f.createProtected()); } if (member.isPublic()) { emfMember.getAnnotationsAndModifiers().add(f.createPublic()); } if (member.isStatic()) { emfMember.getAnnotationsAndModifiers().add(f.createStatic()); } if (member.isStrictfp()) { emfMember.getAnnotationsAndModifiers().add(f.createStrictfp()); } if (member.isSynchronized()) { emfMember.getAnnotationsAndModifiers().add(f.createSynchronized()); } if (member.isTransient()) { emfMember.getAnnotationsAndModifiers().add(f.createTransient()); } if (member.isVolatile()) { emfMember.getAnnotationsAndModifiers().add(f.createVolatile()); } if(!member.isPrivate()) { if (emfMember instanceof ConcreteClassifier) { emfMember.getAnnotationsAndModifiers().add(f.createStatic()); } } } protected EnumConstant constructEnumConstant( org.apache.bcel5_2_0.classfile.Field field) { EnumConstant enumConstant = membersFactory.createEnumConstant(); enumConstant.setName(field.getName()); return enumConstant; } protected ClassifierReference constructTypeParameterReference(String name, TypeParametrizable method, ConcreteClassifier emfClassifier) { TypeParameter typeParameter = null; if (method != null) { for(TypeParameter cand : method.getTypeParameters()) { if(cand.getName().equals(name)) { typeParameter = cand; } } } if (typeParameter == null) { for(TypeParameter cand : emfClassifier.getTypeParameters()) { if(cand.getName().equals(name)) { typeParameter = cand; } } } //TODO #767: implement here if(typeParameter == null) { return null; } ClassifierReference classifierReference = TypesFactory.eINSTANCE.createClassifierReference(); classifierReference.setTarget(typeParameter); return classifierReference; } protected ClassifierReference constructReturnTypeParameterReference(String signature, TypedElement element, ConcreteClassifier emfClassifier) { int idx = signature.indexOf(")T"); if(idx != -1) { signature = signature.substring(idx + 2); } else { idx = signature.indexOf("T"); if (idx != 0) { return null; } signature = signature.substring(1); } idx = signature.indexOf(";"); if(idx == -1) { return null; } String name = signature.substring(0,idx); TypeParameter typeParameter = null; if (element instanceof TypeParametrizable) { //methods for(TypeParameter cand : ((TypeParametrizable)element).getTypeParameters()) { if(cand.getName().equals(name)) { typeParameter = cand; } } } if (typeParameter == null) { for(TypeParameter cand : emfClassifier.getTypeParameters()) { if(cand.getName().equals(name)) { typeParameter = cand; } } } if(typeParameter == null) { return null; } ClassifierReference classifierReference = TypesFactory.eINSTANCE.createClassifierReference(); classifierReference.setTarget(typeParameter); return classifierReference; } protected EList<TypeReference> constructMethodTypeParameterReferences(String signature, Method method, ConcreteClassifier emfClassifier) { EList<TypeReference> result = new BasicEList<TypeReference>(); int idx1 = signature.indexOf("(("); if (idx1 == -1) { idx1 = signature.indexOf(">("); } int idx2 = signature.indexOf(")"); if(idx1 == -1 || idx2 == -1) { return result; } signature = signature.substring(idx1 + 2, idx2); //cut away all the inner type arguments while(signature.contains("<")) { int idx = signature.indexOf("<"); String start = signature.substring(0, idx); String end = signature.substring(idx + 1); int bracketCount = 1; while (bracketCount > 0) { if(end.startsWith("<")) { bracketCount++; } if(end.startsWith(">")) { bracketCount--; } end = end.substring(1,end.length()); } signature = start + end; } while(signature.contains(";")) { int idx = signature.indexOf(";"); if (signature.startsWith("T")) { String name = signature.substring(1,idx); TypeParameter typeParameter = null; for(TypeParameter cand : method.getTypeParameters()) { if(cand.getName().equals(name)) { typeParameter = cand; } } if (typeParameter == null) { for(TypeParameter cand : emfClassifier.getTypeParameters()) { if(cand.getName().equals(name)) { typeParameter = cand; } } } if(typeParameter == null) { return result; } ClassifierReference classifierReference = TypesFactory.eINSTANCE.createClassifierReference(); classifierReference.setTarget(typeParameter); result.add(classifierReference); } else { result.add(null); } signature = signature.substring(signature.indexOf(";") + 1); } return result; } protected EList<TypeParameter> constructTypeParameters(String signature) { EList<TypeParameter> result = new BasicEList<TypeParameter>(); if(signature.contains("((") || !signature.contains("<")) { //method without parameter return result; } signature = signature.substring(signature.indexOf("<") + 1); int endIdx = signature.indexOf(">("); if (endIdx > 0) { signature = signature.substring(0,endIdx); } while(signature.contains(":")) { int idx = signature.indexOf(":"); String name = signature.substring(0,idx); if (!name.equals("")) { TypeParameter typeParameter = GenericsFactory.eINSTANCE.createTypeParameter(); typeParameter.setName(name); result.add(typeParameter); } signature = signature.substring(idx + 1); int sepIdx = signature.indexOf(";"); int colonIdx = signature.indexOf(":"); while(sepIdx < colonIdx && sepIdx > 0) { signature = signature.substring(sepIdx + 1); sepIdx = signature.indexOf(";"); colonIdx = signature.indexOf(":"); } } return result; } protected TypeReference createReferenceToType(String signature) { TypeReference emfTypeReference = null; while (signature.startsWith("[")) { signature = signature.substring(1); } switch (signature.charAt(0)) { case 'B': emfTypeReference = TypesFactory.eINSTANCE.createByte(); break; case 'C': emfTypeReference = TypesFactory.eINSTANCE.createChar(); break; case 'D': emfTypeReference = TypesFactory.eINSTANCE.createDouble(); break; case 'F': emfTypeReference = TypesFactory.eINSTANCE.createFloat(); break; case 'I': emfTypeReference = TypesFactory.eINSTANCE.createInt(); break; case 'J': emfTypeReference = TypesFactory.eINSTANCE.createLong(); break; case 'L': { // Full class name String fullClassName = Utility.signatureToString(signature,false); emfTypeReference = createReferenceToClassifier(fullClassName); break; } case 'S': emfTypeReference = TypesFactory.eINSTANCE.createShort(); break; case 'Z': emfTypeReference = TypesFactory.eINSTANCE.createBoolean(); break; case 'V': emfTypeReference = TypesFactory.eINSTANCE.createVoid(); break; } return emfTypeReference; } protected String constructTypeArguments(String s, ClassifierReference typeRef, TypeParametrizable method, ConcreteClassifier emfClassifier) { if ("".equals(s) || s == null) { return ""; } char[] charArray = s.toCharArray(); int bracketCount = 0; int begin = 0, end = 0; if(charArray[0] != 'L' && charArray[0] != 'T' && charArray[0] != '+' && charArray[0] != '-') { return s.substring(1); } for(int i = 0; i < charArray.length; i++) { char next = charArray[i]; if(next == ';' && bracketCount == 0) { return s.substring(i + 1); } if(next == '<') { if (bracketCount == 0) { begin = i + 1; if(charArray[begin] == '+' || charArray[begin] == '-') { begin = begin + 1; } } bracketCount++; } if(next == '>') { bracketCount--; if (bracketCount == 0) { end = i - 1; int internalBracketCount = 0; int internalBegin = begin, internalEnd = end; for(int j = begin; j < end + 1; j++) { int followUpArgumentIdx = -1; char internalNext = charArray[j]; if(internalNext == '<') { internalBracketCount++; followUpArgumentIdx = j; } if(internalNext == '>') { internalBracketCount--; } if((internalNext == ';') && internalBracketCount == 0) { internalEnd = j; if(charArray[internalBegin] == '*' || charArray[internalBegin] == '?') { UnknownTypeArgument typeArgument = GenericsFactory.eINSTANCE.createUnknownTypeArgument(); if (typeRef != null) { typeRef.getTypeArguments().add(typeArgument); } } else { String fullName = s.substring(internalBegin + 1, internalEnd); if(followUpArgumentIdx != -1) { fullName = s.substring(internalBegin + 1, followUpArgumentIdx); } ClassifierReference argumentType; if(charArray[internalBegin] == 'T') { argumentType = constructTypeParameterReference( fullName, method, emfClassifier); } else { //strip type arguments int idx = fullName.indexOf("<"); if (idx >= 0) { fullName = fullName.substring(0, idx); } argumentType = (ClassifierReference) createReferenceToClassifier(fullName); } if (typeRef != null) { TypeArgument typeArgument = null; if (argumentType == null) { typeArgument = GenericsFactory.eINSTANCE.createUnknownTypeArgument(); } else { typeArgument = GenericsFactory.eINSTANCE.createQualifiedTypeArgument(); ((QualifiedTypeArgument) typeArgument).setTypeReference(argumentType); } typeRef.getTypeArguments().add(typeArgument); } //recursive call; constructTypeArguments(s.substring(internalBegin, internalEnd), argumentType, method, emfClassifier); } internalBegin = j + 1; if(charArray[internalBegin] == '+' || charArray[internalBegin] == '-') { internalBegin++; } } } } } } return ""; } protected TypeReference createReferenceToClassifier(String fullClassifierName) { fullClassifierName = fullClassifierName.replaceAll("/", "."); Classifier classifier = (Classifier) javaClasspath.getClassifier(fullClassifierName); ClassifierReference classifierReference = TypesFactory.eINSTANCE.createClassifierReference(); classifierReference.setTarget(classifier); return classifierReference; } protected int getArrayDimension(String signature) { int arrayDimension = 0; while (signature.startsWith("[")) { signature = signature.substring(1); arrayDimension++; } return arrayDimension; } protected List<String> extractParameterNames(final org.apache.bcel5_2_0.classfile.Method method) { final List<String> names = new ArrayList<String>(); if (method.getLocalVariableTable() == null) { return names; } final int start = method.isStatic() ? 0 : 1; final int stop = method.isStatic() ? method.getArgumentTypes().length : method.getArgumentTypes().length + 1; final org.apache.bcel5_2_0.classfile.LocalVariable[] variables = method .getLocalVariableTable().getLocalVariableTable(); if (variables != null) { for (int i = start; i < stop && i < variables.length; i++) { names.add(variables[i].getName()); } } return names; } }