| /* |
| * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. |
| */ |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.sun.org.apache.bcel.internal.generic; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Objects; |
| |
| 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). |
| * |
| * @see Field |
| * @LastModified: Jan 2020 |
| */ |
| public class FieldGen extends FieldGenOrMethodGen { |
| |
| 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 Objects.equals(THIS.getName(), THAT.getName()) |
| && Objects.equals(THIS.getSignature(), 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 = Long.valueOf(l); |
| } |
| } |
| |
| |
| public void setInitValue( final int i ) { |
| checkType(Type.INT); |
| if (i != 0) { |
| value = Integer.valueOf(i); |
| } |
| } |
| |
| |
| public void setInitValue( final short s ) { |
| checkType(Type.SHORT); |
| if (s != 0) { |
| value = Integer.valueOf(s); |
| } |
| } |
| |
| |
| public void setInitValue( final char c ) { |
| checkType(Type.CHAR); |
| if (c != 0) { |
| value = Integer.valueOf(c); |
| } |
| } |
| |
| |
| public void setInitValue( final byte b ) { |
| checkType(Type.BYTE); |
| if (b != 0) { |
| value = Integer.valueOf(b); |
| } |
| } |
| |
| |
| public void setInitValue( final boolean b ) { |
| checkType(Type.BOOLEAN); |
| if (b) { |
| value = Integer.valueOf(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<FieldObserver> 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); |
| } |
| } |