--- old/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java 2017-08-08 16:05:16.741575970 -0700 +++ new/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java 2017-08-08 16:05:16.657571764 -0700 @@ -17,260 +17,345 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.sun.org.apache.bcel.internal.generic; - -import com.sun.org.apache.bcel.internal.Constants; -import com.sun.org.apache.bcel.internal.classfile.*; import java.util.ArrayList; -import java.util.Iterator; +import java.util.List; + +import com.sun.org.apache.bcel.internal.Const; +import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; +import com.sun.org.apache.bcel.internal.classfile.Annotations; +import com.sun.org.apache.bcel.internal.classfile.Attribute; +import com.sun.org.apache.bcel.internal.classfile.Constant; +import com.sun.org.apache.bcel.internal.classfile.ConstantObject; +import com.sun.org.apache.bcel.internal.classfile.ConstantPool; +import com.sun.org.apache.bcel.internal.classfile.ConstantValue; +import com.sun.org.apache.bcel.internal.classfile.Field; +import com.sun.org.apache.bcel.internal.classfile.Utility; +import com.sun.org.apache.bcel.internal.util.BCELComparator; /** - * Template class for building up a field. The only extraordinary thing - * one can do is to add a constant value attribute to a field (which must of - * course be compatible with to the declared type). + * Template class for building up a field. The only extraordinary thing one can + * do is to add a constant value attribute to a field (which must of course be + * compatible with to the declared type). * - * @author M. Dahm + * @version $Id: FieldGen.java 1749603 2016-06-21 20:50:19Z ggregory $ * @see Field */ public class FieldGen extends FieldGenOrMethodGen { - private Object value = null; - /** - * Declare a field. If it is static (isStatic() == true) and has a - * basic type like int or String it may have an initial value - * associated with it as defined by setInitValue(). - * - * @param access_flags access qualifiers - * @param type field type - * @param name field name - * @param cp constant pool - */ - public FieldGen(int access_flags, Type type, String name, ConstantPoolGen cp) { - setAccessFlags(access_flags); - setType(type); - setName(name); - setConstantPool(cp); - } - - /** - * Instantiate from existing field. - * - * @param field Field object - * @param cp constant pool (must contain the same entries as the field's constant pool) - */ - public FieldGen(Field field, ConstantPoolGen cp) { - this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); - - Attribute[] attrs = field.getAttributes(); - - for(int i=0; i < attrs.length; i++) { - if(attrs[i] instanceof ConstantValue) - setValue(((ConstantValue)attrs[i]).getConstantValueIndex()); - else - addAttribute(attrs[i]); - } - } - - private void setValue(int index) { - ConstantPool cp = this.cp.getConstantPool(); - Constant c = cp.getConstant(index); - value = ((ConstantObject)c).getConstantValue(cp); - } - - /** - * Set (optional) initial value of field, otherwise it will be set to null/0/false - * by the JVM automatically. - */ - public void setInitValue(String str) { - checkType(new ObjectType("java.lang.String")); - - if(str != null) - value = str; - } - - public void setInitValue(long l) { - checkType(Type.LONG); - - if(l != 0L) - value = Long.valueOf(l); - } - - public void setInitValue(int i) { - checkType(Type.INT); - - if(i != 0) - value = Integer.valueOf(i); - } - - public void setInitValue(short s) { - checkType(Type.SHORT); - - if(s != 0) - value = Integer.valueOf(s); - } - - public void setInitValue(char c) { - checkType(Type.CHAR); - - if(c != 0) - value = Integer.valueOf(c); - } - - public void setInitValue(byte b) { - checkType(Type.BYTE); - - if(b != 0) - value = Integer.valueOf(b); - } - - public void setInitValue(boolean b) { - checkType(Type.BOOLEAN); - - if(b) - value = Integer.valueOf(1); - } - - public void setInitValue(float f) { - checkType(Type.FLOAT); - - if(f != 0.0) - value = Float.valueOf(f); - } - - public void setInitValue(double d) { - checkType(Type.DOUBLE); - - if(d != 0.0) - value = Double.valueOf(d); - } - - /** Remove any initial value. - */ - public void cancelInitValue() { - value = null; - } - - private void checkType(Type atype) { - if(type == null) - throw new ClassGenException("You haven't defined the type of the field yet"); - - if(!isFinal()) - throw new ClassGenException("Only final fields may have an initial value!"); - - if(!type.equals(atype)) - throw new ClassGenException("Types are not compatible: " + type + " vs. " + atype); - } - - /** - * Get field object after having set up all necessary values. - */ - public Field getField() { - String signature = getSignature(); - int name_index = cp.addUtf8(name); - int signature_index = cp.addUtf8(signature); - - if(value != null) { - checkType(type); - int index = addConstant(); - addAttribute(new ConstantValue(cp.addUtf8("ConstantValue"), - 2, index, cp.getConstantPool())); - } - - return new Field(access_flags, name_index, signature_index, getAttributes(), - cp.getConstantPool()); - } - - private int addConstant() { - switch(type.getType()) { - case Constants.T_INT: case Constants.T_CHAR: case Constants.T_BYTE: - case Constants.T_BOOLEAN: case Constants.T_SHORT: - return cp.addInteger(((Integer)value).intValue()); - - case Constants.T_FLOAT: - return cp.addFloat(((Float)value).floatValue()); - - case Constants.T_DOUBLE: - return cp.addDouble(((Double)value).doubleValue()); - - case Constants.T_LONG: - return cp.addLong(((Long)value).longValue()); - - case Constants.T_REFERENCE: - return cp.addString(((String)value)); - - default: - throw new RuntimeException("Oops: Unhandled : " + type.getType()); - } - } - - public String getSignature() { return type.getSignature(); } - - private ArrayList observers; - - /** Add observer for this object. - */ - public void addObserver(FieldObserver o) { - if(observers == null) - observers = new ArrayList(); - - observers.add(o); - } - - /** Remove observer for this object. - */ - public void removeObserver(FieldObserver o) { - if(observers != null) - observers.remove(o); - } - - /** Call notify() method on all observers. This method is not called - * automatically whenever the state has changed, but has to be - * called by the user after he has finished editing the object. - */ - public void update() { - if(observers != null) - for(Iterator e = observers.iterator(); e.hasNext(); ) - ((FieldObserver)e.next()).notify(this); - } - - public String getInitValue() { - if(value != null) { - return value.toString(); - } else - return null; - } - - /** - * Return string representation close to declaration format, - * `public static final short MAX = 100', e.g.. - * - * @return String representation of field - */ - public final String toString() { - String name, signature, access; // Short cuts to constant pool - - access = Utility.accessToString(access_flags); - access = access.equals("")? "" : (access + " "); - signature = type.toString(); - name = getName(); - - StringBuffer buf = new StringBuffer(access + signature + " " + name); - String value = getInitValue(); - - if(value != null) - buf.append(" = " + value); - - return buf.toString(); - } - - /** @return deep copy of this field - */ - public FieldGen copy(ConstantPoolGen cp) { - FieldGen fg = (FieldGen)clone(); - - fg.setConstantPool(cp); - return fg; - } + private Object value = null; + private static BCELComparator bcelComparator = new BCELComparator() { + + @Override + public boolean equals(final Object o1, final Object o2) { + final FieldGen THIS = (FieldGen) o1; + final FieldGen THAT = (FieldGen) o2; + return THIS.getName().equals(THAT.getName()) + && THIS.getSignature().equals(THAT.getSignature()); + } + + @Override + public int hashCode(final Object o) { + final FieldGen THIS = (FieldGen) o; + return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + } + }; + + /** + * Declare a field. If it is static (isStatic() == true) and has a basic + * type like int or String it may have an initial value associated with it + * as defined by setInitValue(). + * + * @param access_flags access qualifiers + * @param type field type + * @param name field name + * @param cp constant pool + */ + public FieldGen(final int access_flags, final Type type, final String name, final ConstantPoolGen cp) { + super(access_flags); + setType(type); + setName(name); + setConstantPool(cp); + } + + /** + * Instantiate from existing field. + * + * @param field Field object + * @param cp constant pool (must contain the same entries as the field's + * constant pool) + */ + public FieldGen(final Field field, final ConstantPoolGen cp) { + this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); + final Attribute[] attrs = field.getAttributes(); + for (final Attribute attr : attrs) { + if (attr instanceof ConstantValue) { + setValue(((ConstantValue) attr).getConstantValueIndex()); + } else if (attr instanceof Annotations) { + final Annotations runtimeAnnotations = (Annotations) attr; + final AnnotationEntry[] annotationEntries = runtimeAnnotations.getAnnotationEntries(); + for (final AnnotationEntry element : annotationEntries) { + addAnnotationEntry(new AnnotationEntryGen(element, cp, false)); + } + } else { + addAttribute(attr); + } + } + } + + private void setValue(final int index) { + final ConstantPool cp = super.getConstantPool().getConstantPool(); + final Constant c = cp.getConstant(index); + value = ((ConstantObject) c).getConstantValue(cp); + } + + /** + * Set (optional) initial value of field, otherwise it will be set to + * null/0/false by the JVM automatically. + */ + public void setInitValue(final String str) { + checkType(ObjectType.getInstance("java.lang.String")); + if (str != null) { + value = str; + } + } + + public void setInitValue(final long l) { + checkType(Type.LONG); + if (l != 0L) { + value = l; + } + } + + public void setInitValue(final int i) { + checkType(Type.INT); + if (i != 0) { + value = i; + } + } + + public void setInitValue(final short s) { + checkType(Type.SHORT); + if (s != 0) { + value = (int) s; + } + } + + public void setInitValue(final char c) { + checkType(Type.CHAR); + if (c != 0) { + value = (int) c; + } + } + + public void setInitValue(final byte b) { + checkType(Type.BYTE); + if (b != 0) { + value = (int) b; + } + } + + public void setInitValue(final boolean b) { + checkType(Type.BOOLEAN); + if (b) { + value = 1; + } + } + + public void setInitValue(final float f) { + checkType(Type.FLOAT); + if (f != 0.0) { + value = f; + } + } + + public void setInitValue(final double d) { + checkType(Type.DOUBLE); + if (d != 0.0) { + value = d; + } + } + + /** + * Remove any initial value. + */ + public void cancelInitValue() { + value = null; + } + + private void checkType(final Type atype) { + final Type superType = super.getType(); + if (superType == null) { + throw new ClassGenException("You haven't defined the type of the field yet"); + } + if (!isFinal()) { + throw new ClassGenException("Only final fields may have an initial value!"); + } + if (!superType.equals(atype)) { + throw new ClassGenException("Types are not compatible: " + superType + " vs. " + atype); + } + } + + /** + * Get field object after having set up all necessary values. + */ + public Field getField() { + final String signature = getSignature(); + final int name_index = super.getConstantPool().addUtf8(super.getName()); + final int signature_index = super.getConstantPool().addUtf8(signature); + if (value != null) { + checkType(super.getType()); + final int index = addConstant(); + addAttribute(new ConstantValue(super.getConstantPool().addUtf8("ConstantValue"), 2, index, + super.getConstantPool().getConstantPool())); // sic + } + addAnnotationsAsAttribute(super.getConstantPool()); + return new Field(super.getAccessFlags(), name_index, signature_index, getAttributes(), + super.getConstantPool().getConstantPool()); // sic + } + + private void addAnnotationsAsAttribute(final ConstantPoolGen cp) { + final Attribute[] attrs = AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries()); + for (final Attribute attr : attrs) { + addAttribute(attr); + } + } + + private int addConstant() { + switch (super.getType().getType()) { // sic + case Const.T_INT: + case Const.T_CHAR: + case Const.T_BYTE: + case Const.T_BOOLEAN: + case Const.T_SHORT: + return super.getConstantPool().addInteger(((Integer) value)); + case Const.T_FLOAT: + return super.getConstantPool().addFloat(((Float) value)); + case Const.T_DOUBLE: + return super.getConstantPool().addDouble(((Double) value)); + case Const.T_LONG: + return super.getConstantPool().addLong(((Long) value)); + case Const.T_REFERENCE: + return super.getConstantPool().addString((String) value); + default: + throw new RuntimeException("Oops: Unhandled : " + super.getType().getType()); // sic + } + } + + @Override + public String getSignature() { + return super.getType().getSignature(); + } + + private List observers; + + /** + * Add observer for this object. + */ + public void addObserver(final FieldObserver o) { + if (observers == null) { + observers = new ArrayList<>(); + } + observers.add(o); + } + + /** + * Remove observer for this object. + */ + public void removeObserver(final FieldObserver o) { + if (observers != null) { + observers.remove(o); + } + } + + /** + * Call notify() method on all observers. This method is not called + * automatically whenever the state has changed, but has to be called by the + * user after he has finished editing the object. + */ + public void update() { + if (observers != null) { + for (final FieldObserver observer : observers) { + observer.notify(this); + } + } + } + + public String getInitValue() { + if (value != null) { + return value.toString(); + } + return null; + } + + /** + * Return string representation close to declaration format, `public static + * final short MAX = 100', e.g.. + * + * @return String representation of field + */ + @Override + public final String toString() { + String name; + String signature; + String access; // Short cuts to constant pool + access = Utility.accessToString(super.getAccessFlags()); + access = access.isEmpty() ? "" : (access + " "); + signature = super.getType().toString(); + name = getName(); + final StringBuilder buf = new StringBuilder(32); // CHECKSTYLE IGNORE MagicNumber + buf.append(access).append(signature).append(" ").append(name); + final String value = getInitValue(); + if (value != null) { + buf.append(" = ").append(value); + } + return buf.toString(); + } + + /** + * @return deep copy of this field + */ + public FieldGen copy(final ConstantPoolGen cp) { + final FieldGen fg = (FieldGen) clone(); + fg.setConstantPool(cp); + return fg; + } + + /** + * @return Comparison strategy object + */ + public static BCELComparator getComparator() { + return bcelComparator; + } + + /** + * @param comparator Comparison strategy object + */ + public static void setComparator(final BCELComparator comparator) { + bcelComparator = comparator; + } + + /** + * Return value as defined by given BCELComparator strategy. By default two + * FieldGen objects are said to be equal when their names and signatures are + * equal. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object obj) { + return bcelComparator.equals(this, obj); + } + + /** + * Return value as defined by given BCELComparator strategy. By default + * return the hashcode of the field's name XOR signature. + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return bcelComparator.hashCode(this); + } }