123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- package org.aspectj.apache.bcel.generic;
-
- /* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2001 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" and
- * "Apache BCEL" must not be used to endorse or promote products
- * derived from this software without prior written permission. For
- * written permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * "Apache BCEL", nor may "Apache" appear in their name, without
- * prior written permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
-
- import java.io.ByteArrayOutputStream;
- import java.io.DataOutputStream;
- import java.lang.reflect.Modifier;
- import java.security.MessageDigest;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.List;
-
- import org.aspectj.apache.bcel.Constants;
- import org.aspectj.apache.bcel.classfile.Attribute;
- import org.aspectj.apache.bcel.classfile.ConstantPool;
- import org.aspectj.apache.bcel.classfile.Field;
- import org.aspectj.apache.bcel.classfile.JavaClass;
- import org.aspectj.apache.bcel.classfile.Method;
- import org.aspectj.apache.bcel.classfile.Modifiers;
- import org.aspectj.apache.bcel.classfile.SourceFile;
- import org.aspectj.apache.bcel.classfile.Utility;
- import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
- import org.aspectj.apache.bcel.classfile.annotation.RuntimeInvisAnnos;
- import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisAnnos;
-
- /**
- * Template class for building up a java class. May be initialized with an existing java class.
- *
- * @see JavaClass
- * @version $Id: ClassGen.java,v 1.15 2009/09/15 19:40:14 aclement Exp $
- * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
- *
- * Upgraded, Andy Clement 9th Mar 06 - calculates SUID
- */
- public class ClassGen extends Modifiers implements Cloneable {
-
- private String classname;
- private String superclassname;
- private String filename;
- private int classnameIndex = -1;
- private int superclassnameIndex = -1;
- private int major = Constants.MAJOR_1_1;
- private int minor = Constants.MINOR_1_1;
- private ConstantPool cpool;
- private List<Field> fieldsList = new ArrayList<>();
- private List<Method> methodsList = new ArrayList<>();
- private List<Attribute> attributesList = new ArrayList<>();
- private List<String> interfaceList = new ArrayList<>();
- private List<AnnotationGen> annotationsList = new ArrayList<>();
-
- public ClassGen(String classname, String superclassname, String filename, int modifiers, String[] interfacenames,
- ConstantPool cpool) {
- this.classname = classname;
- this.superclassname = superclassname;
- this.filename = filename;
- this.modifiers = modifiers;
- this.cpool = cpool;
- if (filename != null) {
- addAttribute(new SourceFile(cpool.addUtf8("SourceFile"), 2, cpool.addUtf8(filename), cpool));
- }
- this.classnameIndex = cpool.addClass(classname);
- this.superclassnameIndex = cpool.addClass(superclassname);
- if (interfacenames != null) {
- for (String interfacename : interfacenames) {
- addInterface(interfacename);
- }
- }
- }
-
- public ClassGen(String classname, String superclassname, String filename, int modifiers, String[] interfacenames) {
- this(classname, superclassname, filename, modifiers, interfacenames, new ConstantPool());
- }
-
- public ClassGen(JavaClass clazz) {
- classnameIndex = clazz.getClassNameIndex();
- superclassnameIndex = clazz.getSuperclassNameIndex();
- classname = clazz.getClassName();
- superclassname = clazz.getSuperclassName();
- filename = clazz.getSourceFileName();
- modifiers = clazz.getModifiers();
- cpool = clazz.getConstantPool().copy();
- major = clazz.getMajor();
- minor = clazz.getMinor();
-
- Method[] methods = clazz.getMethods();
- Field[] fields = clazz.getFields();
- String[] interfaces = clazz.getInterfaceNames();
-
- for (String anInterface : interfaces) {
- addInterface(anInterface);
- }
-
- // OPTIMIZE Could make unpacking lazy, done on first reference
- Attribute[] attributes = clazz.getAttributes();
- for (Attribute attr : attributes) {
- if (attr instanceof RuntimeVisAnnos) {
- RuntimeVisAnnos rva = (RuntimeVisAnnos) attr;
- List<AnnotationGen> annos = rva.getAnnotations();
- for (AnnotationGen a : annos) {
- annotationsList.add(new AnnotationGen(a, cpool, false));
- }
- } else if (attr instanceof RuntimeInvisAnnos) {
- RuntimeInvisAnnos ria = (RuntimeInvisAnnos) attr;
- List<AnnotationGen> annos = ria.getAnnotations();
- for (AnnotationGen anno : annos) {
- annotationsList.add(new AnnotationGen(anno, cpool, false));
- }
- } else {
- attributesList.add(attr);
- }
- }
-
- for (Method method : methods) {
- addMethod(method);
- }
-
- for (Field field : fields) {
- addField(field);
- }
- }
-
- /**
- * @return build and return a JavaClass
- */
- public JavaClass getJavaClass() {
- int[] interfaces = getInterfaces();
- Field[] fields = getFields();
- Method[] methods = getMethods();
-
- Collection<Attribute> attributes = null;
- if (annotationsList.size() == 0) {
- attributes = attributesList;
- } else {
- // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations'
- attributes = new ArrayList<>();
- attributes.addAll(Utility.getAnnotationAttributes(cpool, annotationsList));
- attributes.addAll(attributesList);
- }
-
- // Must be last since the above calls may still add something to it
- ConstantPool cp = this.cpool.getFinalConstantPool();
-
- return new JavaClass(classnameIndex, superclassnameIndex, filename, major, minor, modifiers, cp, interfaces, fields,
- methods, attributes.toArray(new Attribute[attributes.size()]));// OPTIMIZE avoid toArray()?
- }
-
- public void addInterface(String name) {
- interfaceList.add(name);
- }
-
- public void removeInterface(String name) {
- interfaceList.remove(name);
- }
-
- public int getMajor() {
- return major;
- }
-
- public void setMajor(int major) {
- this.major = major;
- }
-
- public void setMinor(int minor) {
- this.minor = minor;
- }
-
- public int getMinor() {
- return minor;
- }
-
- public void addAttribute(Attribute a) {
- attributesList.add(a);
- }
-
- public void addAnnotation(AnnotationGen a) {
- annotationsList.add(a);
- }
-
- public void addMethod(Method m) {
- methodsList.add(m);
- }
-
- /**
- * Convenience method.
- *
- * Add an empty constructor to this class that does nothing but calling super().
- *
- * @param access rights for constructor
- */
- public void addEmptyConstructor(int access_flags) {
- InstructionList il = new InstructionList();
- il.append(InstructionConstants.THIS); // Push `this'
- il.append(new InvokeInstruction(Constants.INVOKESPECIAL, cpool.addMethodref(superclassname, "<init>", "()V")));
- il.append(InstructionConstants.RETURN);
-
- MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>", classname, il, cpool);
- mg.setMaxStack(1);
- mg.setMaxLocals();
- addMethod(mg.getMethod());
- }
-
- /**
- * Add a field to this class.
- *
- * @param f field to add
- */
- public void addField(Field f) {
- fieldsList.add(f);
- }
-
- public boolean containsField(Field f) {
- return fieldsList.contains(f);
- }
-
- /**
- * @return field object with given name, or null if not found
- */
- public Field findsField(String name) {
- for (Field field : fieldsList) {
- if (field.getName().equals(name)) {
- return field;
- }
- }
- return null;
- }
-
- /**
- * @return method object with given name and signature, or null if not found
- */
- public Method containsMethod(String name, String signature) {
- for (Method method : methodsList) {
- if (method.getName().equals(name) && method.getSignature().equals(signature)) {
- return method;
- }
- }
- return null;
- }
-
- public void removeAttribute(Attribute a) {
- attributesList.remove(a);
- }
-
- public void removeAnnotation(AnnotationGen a) {
- annotationsList.remove(a);
- }
-
- public void removeMethod(Method m) {
- methodsList.remove(m);
- }
-
- /**
- * Replace given method with new one. If the old one does not exist add the new_ method to the class anyway.
- */
- public void replaceMethod(Method old, Method new_) {
- if (new_ == null)
- throw new ClassGenException("Replacement method must not be null");
-
- int i = methodsList.indexOf(old);
-
- if (i < 0)
- methodsList.add(new_);
- else
- methodsList.set(i, new_);
- }
-
- /**
- * Replace given field with new one. If the old one does not exist add the new_ field to the class anyway.
- */
- public void replaceField(Field old, Field new_) {
- if (new_ == null)
- throw new ClassGenException("Replacement method must not be null");
-
- int i = fieldsList.indexOf(old);
-
- if (i < 0)
- fieldsList.add(new_);
- else
- fieldsList.set(i, new_);
- }
-
- public void removeField(Field f) {
- fieldsList.remove(f);
- }
-
- public String getClassName() {
- return classname;
- }
-
- public String getSuperclassName() {
- return superclassname;
- }
-
- public String getFileName() {
- return filename;
- }
-
- public void setClassName(String name) {
- classname = name.replace('/', '.');
- classnameIndex = cpool.addClass(name);
- }
-
- public void setSuperclassName(String name) {
- superclassname = name.replace('/', '.');
- superclassnameIndex = cpool.addClass(name);
- }
-
- public Method[] getMethods() {
- Method[] methods = new Method[methodsList.size()];
- methodsList.toArray(methods);
- return methods;
- }
-
- public void setMethods(Method[] methods) {
- methodsList.clear();
- for (Method method : methods) addMethod(method);
- }
-
- public void setFields(Field[] fs) {
- fieldsList.clear();
- for (Field f : fs) addField(f);
- }
-
- public void setMethodAt(Method method, int pos) {
- methodsList.set(pos, method);
- }
-
- public Method getMethodAt(int pos) {
- return methodsList.get(pos);
- }
-
- public String[] getInterfaceNames() {
- int size = interfaceList.size();
- String[] interfaces = new String[size];
-
- interfaceList.toArray(interfaces);
- return interfaces;
- }
-
- public int[] getInterfaces() {
- int size = interfaceList.size();
- int[] interfaces = new int[size];
-
- for (int i = 0; i < size; i++)
- interfaces[i] = cpool.addClass(interfaceList.get(i));
-
- return interfaces;
- }
-
- public Field[] getFields() {
- Field[] fields = new Field[fieldsList.size()];
- fieldsList.toArray(fields);
- return fields;
- }
-
- public Collection<Attribute> getAttributes() {
- return attributesList;
- }
-
- // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here?
- public AnnotationGen[] getAnnotations() {
- AnnotationGen[] annotations = new AnnotationGen[annotationsList.size()];
- annotationsList.toArray(annotations);
- return annotations;
- }
-
- public ConstantPool getConstantPool() {
- return cpool;
- }
-
- public void setConstantPool(ConstantPool constant_pool) {
- cpool = constant_pool;
- }
-
- public void setClassNameIndex(int class_name_index) {
- this.classnameIndex = class_name_index;
- classname = cpool.getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.');
- }
-
- public void setSuperclassNameIndex(int superclass_name_index) {
- this.superclassnameIndex = superclass_name_index;
- superclassname = cpool.getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.');
- }
-
- public int getSuperclassNameIndex() {
- return superclassnameIndex;
- }
-
- public int getClassNameIndex() {
- return classnameIndex;
- }
-
- @Override
- public Object clone() {
- try {
- return super.clone();
- } catch (CloneNotSupportedException e) {
- System.err.println(e);
- return null;
- }
- }
-
- public final boolean isAnnotation() {
- return (modifiers & Constants.ACC_ANNOTATION) != 0;
- }
-
- public final boolean isEnum() {
- return (modifiers & Constants.ACC_ENUM) != 0;
- }
-
- /**
- * Calculate the SerialVersionUID for a class.
- */
- public long getSUID() {
- try {
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(baos);
-
- // 1. classname
- dos.writeUTF(getClassName());
-
- // 2. classmodifiers: ACC_PUBLIC, ACC_FINAL, ACC_INTERFACE, and ACC_ABSTRACT
- int classmods = 0;
- classmods |= (isPublic() ? Constants.ACC_PUBLIC : 0);
- classmods |= (isFinal() ? Constants.ACC_FINAL : 0);
- classmods |= (isInterface() ? Constants.ACC_INTERFACE : 0);
-
- if (isAbstract()) {
- // if an interface then abstract is only set if it has methods
- if (isInterface()) {
- if (methodsList.size() > 0)
- classmods |= Constants.ACC_ABSTRACT;
- } else {
- classmods |= Constants.ACC_ABSTRACT;
- }
- }
-
- dos.writeInt(classmods);
-
- // 3. ordered list of interfaces
- String[] names = getInterfaceNames();
- if (names != null) {
- Arrays.sort(names);
- for (String name : names) dos.writeUTF(name);
- }
-
- // 4. ordered list of fields (ignoring private static and private transient fields):
- // (relevant modifiers are ACC_PUBLIC, ACC_PRIVATE,
- // ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE,
- // ACC_TRANSIENT)
- List<Field> relevantFields = new ArrayList<>();
- for (Field field : fieldsList) {
- if (!(field.isPrivate() && field.isStatic()) && !(field.isPrivate() && field.isTransient())) {
- relevantFields.add(field);
- }
- }
- Collections.sort(relevantFields, new FieldComparator());
- int relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | Constants.ACC_STATIC
- | Constants.ACC_FINAL | Constants.ACC_VOLATILE | Constants.ACC_TRANSIENT;
- for (Field f : relevantFields) {
- dos.writeUTF(f.getName());
- dos.writeInt(relevantFlags & f.getModifiers());
- dos.writeUTF(f.getType().getSignature());
- }
-
- // some up front method processing: discover clinit, init and ordinary methods of interest:
- List<Method> relevantMethods = new ArrayList<>();
- List<Method> relevantCtors = new ArrayList<>();
- boolean hasClinit = false;
- for (Method m : methodsList) {
- boolean couldBeInitializer = m.getName().charAt(0) == '<';
- if (couldBeInitializer && m.getName().equals("<clinit>")) {
- hasClinit = true;
- } else if (couldBeInitializer && m.getName().equals("<init>")) {
- if (!m.isPrivate())
- relevantCtors.add(m);
- } else {
- if (!m.isPrivate())
- relevantMethods.add(m);
- }
- }
- Collections.sort(relevantCtors, new ConstructorComparator());
- Collections.sort(relevantMethods, new MethodComparator());
-
- // 5. If a class initializer exists, write out the following:
- // 1. The name of the method, <clinit>.
- // 2. The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer.
- // 3. The descriptor of the method, ()V.
- if (hasClinit) {
- dos.writeUTF("<clinit>");
- dos.writeInt(Modifier.STATIC);
- dos.writeUTF("()V");
- }
-
- // for methods and constructors:
- // ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED,
- // ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT
- relevantFlags = Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED | Constants.ACC_STATIC
- | Constants.ACC_FINAL | Constants.ACC_SYNCHRONIZED | Constants.ACC_NATIVE | Constants.ACC_ABSTRACT
- | Constants.ACC_STRICT;
-
- // 6. sorted non-private constructors
- for (Method ctor : relevantCtors) {
- dos.writeUTF(ctor.getName()); // <init>
- dos.writeInt(relevantFlags & ctor.getModifiers());
- dos.writeUTF(ctor.getSignature().replace('/', '.'));
- }
-
- // 7. sorted non-private methods
- for (Method m : relevantMethods) {
- dos.writeUTF(m.getName());
- dos.writeInt(relevantFlags & m.getModifiers());
- dos.writeUTF(m.getSignature().replace('/', '.'));
- }
- dos.flush();
- dos.close();
- byte[] bs = baos.toByteArray();
- MessageDigest md = MessageDigest.getInstance("SHA");
- byte[] result = md.digest(bs);
-
- long suid = 0L;
- int pos = result.length > 8 ? 7 : result.length - 1; // use the bytes we have
- while (pos >= 0) {
- suid = suid << 8 | ((long) result[pos--] & 0xff);
- }
-
- // if it was definetly 8 everytime...
- // long suid = ((long)(sha[0]&0xff) | (long)(sha[1]&0xff) << 8 |
- // (long)(sha[2]&0xff) << 16 | (long)(sha[3]&0xff) << 24 |
- // (long)(sha[4]&0xff) << 32 | (long)(sha[5]&0xff) << 40 |
- // (long)(sha[6]&0xff) << 48 | (long)(sha[7]&0xff) << 56);
- return suid;
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException("Unable to calculate suid for " + getClassName() + ": " + e.toString());
- }
- }
-
- private static class FieldComparator implements Comparator<Field> {
- public int compare(Field f0, Field f1) {
- return f0.getName().compareTo(f1.getName());
- }
- }
-
- private static class ConstructorComparator implements Comparator<Method> {
- public int compare(Method m0, Method m1) {
- // can ignore the name...
- return (m0).getSignature().compareTo(m1.getSignature());
- }
- }
-
- private static class MethodComparator implements Comparator<Method> {
- public int compare(Method m0, Method m1) {
- int result = m0.getName().compareTo(m1.getName());
- if (result == 0) {
- result = m0.getSignature().compareTo(m1.getSignature());
- }
- return result;
- }
- }
-
- public boolean hasAttribute(String attributeName) {
- for (Attribute attr : attributesList) {
- if (attr.getName().equals(attributeName)) {
- return true;
- }
- }
- return false;
- }
-
- public Attribute getAttribute(String attributeName) {
- for (Attribute attr : attributesList) {
- if (attr.getName().equals(attributeName)) {
- return attr;
- }
- }
- return null;
- }
- }
|