1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.bcel.internal.generic; 22 23 24 import com.sun.org.apache.bcel.internal.Constants; 25 import com.sun.org.apache.bcel.internal.classfile.*; 26 import java.util.ArrayList; 27 import java.util.Iterator; 28 29 /** 30 * Template class for building up a field. The only extraordinary thing 31 * one can do is to add a constant value attribute to a field (which must of 32 * course be compatible with to the declared type). 33 * 34 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 35 * @see Field 36 */ 37 public class FieldGen extends FieldGenOrMethodGen { 38 private Object value = null; 39 40 /** 41 * Declare a field. If it is static (isStatic() == true) and has a 42 * basic type like int or String it may have an initial value 43 * associated with it as defined by setInitValue(). 44 * 45 * @param access_flags access qualifiers 46 * @param type field type 47 * @param name field name 48 * @param cp constant pool 49 */ 50 public FieldGen(int access_flags, Type type, String name, ConstantPoolGen cp) { 51 setAccessFlags(access_flags); 52 setType(type); 53 setName(name); 54 setConstantPool(cp); 55 } 56 57 /** 58 * Instantiate from existing field. 59 * 60 * @param field Field object 61 * @param cp constant pool (must contain the same entries as the field's constant pool) 62 */ 63 public FieldGen(Field field, ConstantPoolGen cp) { 64 this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); 65 66 Attribute[] attrs = field.getAttributes(); 67 68 for(int i=0; i < attrs.length; i++) { 69 if(attrs[i] instanceof ConstantValue) 70 setValue(((ConstantValue)attrs[i]).getConstantValueIndex()); 71 else 72 addAttribute(attrs[i]); 73 } 74 } 75 76 private void setValue(int index) { 77 ConstantPool cp = this.cp.getConstantPool(); 78 Constant c = cp.getConstant(index); 79 value = ((ConstantObject)c).getConstantValue(cp); 80 } 81 82 /** 83 * Set (optional) initial value of field, otherwise it will be set to null/0/false 84 * by the JVM automatically. 85 */ 86 public void setInitValue(String str) { 87 checkType(new ObjectType("java.lang.String")); 88 89 if(str != null) 90 value = str; 91 } 92 93 public void setInitValue(long l) { 94 checkType(Type.LONG); 95 96 if(l != 0L) 97 value = Long.valueOf(l); 98 } 99 100 public void setInitValue(int i) { 101 checkType(Type.INT); 102 103 if(i != 0) 104 value = Integer.valueOf(i); 105 } 106 107 public void setInitValue(short s) { 108 checkType(Type.SHORT); 109 110 if(s != 0) 111 value = Integer.valueOf(s); 112 } 113 114 public void setInitValue(char c) { 115 checkType(Type.CHAR); 116 117 if(c != 0) 118 value = Integer.valueOf(c); 119 } 120 121 public void setInitValue(byte b) { 122 checkType(Type.BYTE); 123 124 if(b != 0) 125 value = Integer.valueOf(b); 126 } 127 128 public void setInitValue(boolean b) { 129 checkType(Type.BOOLEAN); 130 131 if(b) 132 value = Integer.valueOf(1); 133 } 134 135 public void setInitValue(float f) { 136 checkType(Type.FLOAT); 137 138 if(f != 0.0) 139 value = Float.valueOf(f); 140 } 141 142 public void setInitValue(double d) { 143 checkType(Type.DOUBLE); 144 145 if(d != 0.0) 146 value = Double.valueOf(d); 147 } 148 149 /** Remove any initial value. 150 */ 151 public void cancelInitValue() { 152 value = null; 153 } 154 155 private void checkType(Type atype) { 156 if(type == null) 157 throw new ClassGenException("You haven't defined the type of the field yet"); 158 159 if(!isFinal()) 160 throw new ClassGenException("Only final fields may have an initial value!"); 161 162 if(!type.equals(atype)) 163 throw new ClassGenException("Types are not compatible: " + type + " vs. " + atype); 164 } 165 166 /** 167 * Get field object after having set up all necessary values. 168 */ 169 public Field getField() { 170 String signature = getSignature(); 171 int name_index = cp.addUtf8(name); 172 int signature_index = cp.addUtf8(signature); 173 174 if(value != null) { 175 checkType(type); 176 int index = addConstant(); 177 addAttribute(new ConstantValue(cp.addUtf8("ConstantValue"), 178 2, index, cp.getConstantPool())); 179 } 180 181 return new Field(access_flags, name_index, signature_index, getAttributes(), 182 cp.getConstantPool()); 183 } 184 185 private int addConstant() { 186 switch(type.getType()) { 187 case Constants.T_INT: case Constants.T_CHAR: case Constants.T_BYTE: 188 case Constants.T_BOOLEAN: case Constants.T_SHORT: 189 return cp.addInteger(((Integer)value).intValue()); 190 191 case Constants.T_FLOAT: 192 return cp.addFloat(((Float)value).floatValue()); 193 194 case Constants.T_DOUBLE: 195 return cp.addDouble(((Double)value).doubleValue()); 196 197 case Constants.T_LONG: 198 return cp.addLong(((Long)value).longValue()); 199 200 case Constants.T_REFERENCE: 201 return cp.addString(((String)value)); 202 203 default: 204 throw new RuntimeException("Oops: Unhandled : " + type.getType()); 205 } 206 } 207 208 public String getSignature() { return type.getSignature(); } 209 210 private ArrayList observers; 211 212 /** Add observer for this object. 213 */ 214 public void addObserver(FieldObserver o) { 215 if(observers == null) 216 observers = new ArrayList(); 217 218 observers.add(o); 219 } 220 221 /** Remove observer for this object. 222 */ 223 public void removeObserver(FieldObserver o) { 224 if(observers != null) 225 observers.remove(o); 226 } 227 228 /** Call notify() method on all observers. This method is not called 229 * automatically whenever the state has changed, but has to be 230 * called by the user after he has finished editing the object. 231 */ 232 public void update() { 233 if(observers != null) 234 for(Iterator e = observers.iterator(); e.hasNext(); ) 235 ((FieldObserver)e.next()).notify(this); 236 } 237 238 public String getInitValue() { 239 if(value != null) { 240 return value.toString(); 241 } else 242 return null; 243 } 244 245 /** 246 * Return string representation close to declaration format, 247 * `public static final short MAX = 100', e.g.. 248 * 249 * @return String representation of field 250 */ 251 public final String toString() { 252 String name, signature, access; // Short cuts to constant pool 253 254 access = Utility.accessToString(access_flags); 255 access = access.equals("")? "" : (access + " "); 256 signature = type.toString(); 257 name = getName(); 258 259 StringBuffer buf = new StringBuffer(access + signature + " " + name); 260 String value = getInitValue(); 261 262 if(value != null) 263 buf.append(" = " + value); 264 265 return buf.toString(); 266 } 267 268 /** @return deep copy of this field 269 */ 270 public FieldGen copy(ConstantPoolGen cp) { 271 FieldGen fg = (FieldGen)clone(); 272 273 fg.setConstantPool(cp); 274 return fg; 275 } 276 } | 1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 package com.sun.org.apache.bcel.internal.generic; 21 22 import java.util.ArrayList; 23 import java.util.List; 24 25 import com.sun.org.apache.bcel.internal.Const; 26 import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; 27 import com.sun.org.apache.bcel.internal.classfile.Annotations; 28 import com.sun.org.apache.bcel.internal.classfile.Attribute; 29 import com.sun.org.apache.bcel.internal.classfile.Constant; 30 import com.sun.org.apache.bcel.internal.classfile.ConstantObject; 31 import com.sun.org.apache.bcel.internal.classfile.ConstantPool; 32 import com.sun.org.apache.bcel.internal.classfile.ConstantValue; 33 import com.sun.org.apache.bcel.internal.classfile.Field; 34 import com.sun.org.apache.bcel.internal.classfile.Utility; 35 import com.sun.org.apache.bcel.internal.util.BCELComparator; 36 37 /** 38 * Template class for building up a field. The only extraordinary thing one can 39 * do is to add a constant value attribute to a field (which must of course be 40 * compatible with to the declared type). 41 * 42 * @version $Id: FieldGen.java 1749603 2016-06-21 20:50:19Z ggregory $ 43 * @see Field 44 */ 45 public class FieldGen extends FieldGenOrMethodGen { 46 47 private Object value = null; 48 private static BCELComparator bcelComparator = new BCELComparator() { 49 50 @Override 51 public boolean equals(final Object o1, final Object o2) { 52 final FieldGen THIS = (FieldGen) o1; 53 final FieldGen THAT = (FieldGen) o2; 54 return THIS.getName().equals(THAT.getName()) 55 && THIS.getSignature().equals(THAT.getSignature()); 56 } 57 58 @Override 59 public int hashCode(final Object o) { 60 final FieldGen THIS = (FieldGen) o; 61 return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); 62 } 63 }; 64 65 /** 66 * Declare a field. If it is static (isStatic() == true) and has a basic 67 * type like int or String it may have an initial value associated with it 68 * as defined by setInitValue(). 69 * 70 * @param access_flags access qualifiers 71 * @param type field type 72 * @param name field name 73 * @param cp constant pool 74 */ 75 public FieldGen(final int access_flags, final Type type, final String name, final ConstantPoolGen cp) { 76 super(access_flags); 77 setType(type); 78 setName(name); 79 setConstantPool(cp); 80 } 81 82 /** 83 * Instantiate from existing field. 84 * 85 * @param field Field object 86 * @param cp constant pool (must contain the same entries as the field's 87 * constant pool) 88 */ 89 public FieldGen(final Field field, final ConstantPoolGen cp) { 90 this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); 91 final Attribute[] attrs = field.getAttributes(); 92 for (final Attribute attr : attrs) { 93 if (attr instanceof ConstantValue) { 94 setValue(((ConstantValue) attr).getConstantValueIndex()); 95 } else if (attr instanceof Annotations) { 96 final Annotations runtimeAnnotations = (Annotations) attr; 97 final AnnotationEntry[] annotationEntries = runtimeAnnotations.getAnnotationEntries(); 98 for (final AnnotationEntry element : annotationEntries) { 99 addAnnotationEntry(new AnnotationEntryGen(element, cp, false)); 100 } 101 } else { 102 addAttribute(attr); 103 } 104 } 105 } 106 107 private void setValue(final int index) { 108 final ConstantPool cp = super.getConstantPool().getConstantPool(); 109 final Constant c = cp.getConstant(index); 110 value = ((ConstantObject) c).getConstantValue(cp); 111 } 112 113 /** 114 * Set (optional) initial value of field, otherwise it will be set to 115 * null/0/false by the JVM automatically. 116 */ 117 public void setInitValue(final String str) { 118 checkType(ObjectType.getInstance("java.lang.String")); 119 if (str != null) { 120 value = str; 121 } 122 } 123 124 public void setInitValue(final long l) { 125 checkType(Type.LONG); 126 if (l != 0L) { 127 value = l; 128 } 129 } 130 131 public void setInitValue(final int i) { 132 checkType(Type.INT); 133 if (i != 0) { 134 value = i; 135 } 136 } 137 138 public void setInitValue(final short s) { 139 checkType(Type.SHORT); 140 if (s != 0) { 141 value = (int) s; 142 } 143 } 144 145 public void setInitValue(final char c) { 146 checkType(Type.CHAR); 147 if (c != 0) { 148 value = (int) c; 149 } 150 } 151 152 public void setInitValue(final byte b) { 153 checkType(Type.BYTE); 154 if (b != 0) { 155 value = (int) b; 156 } 157 } 158 159 public void setInitValue(final boolean b) { 160 checkType(Type.BOOLEAN); 161 if (b) { 162 value = 1; 163 } 164 } 165 166 public void setInitValue(final float f) { 167 checkType(Type.FLOAT); 168 if (f != 0.0) { 169 value = f; 170 } 171 } 172 173 public void setInitValue(final double d) { 174 checkType(Type.DOUBLE); 175 if (d != 0.0) { 176 value = d; 177 } 178 } 179 180 /** 181 * Remove any initial value. 182 */ 183 public void cancelInitValue() { 184 value = null; 185 } 186 187 private void checkType(final Type atype) { 188 final Type superType = super.getType(); 189 if (superType == null) { 190 throw new ClassGenException("You haven't defined the type of the field yet"); 191 } 192 if (!isFinal()) { 193 throw new ClassGenException("Only final fields may have an initial value!"); 194 } 195 if (!superType.equals(atype)) { 196 throw new ClassGenException("Types are not compatible: " + superType + " vs. " + atype); 197 } 198 } 199 200 /** 201 * Get field object after having set up all necessary values. 202 */ 203 public Field getField() { 204 final String signature = getSignature(); 205 final int name_index = super.getConstantPool().addUtf8(super.getName()); 206 final int signature_index = super.getConstantPool().addUtf8(signature); 207 if (value != null) { 208 checkType(super.getType()); 209 final int index = addConstant(); 210 addAttribute(new ConstantValue(super.getConstantPool().addUtf8("ConstantValue"), 2, index, 211 super.getConstantPool().getConstantPool())); // sic 212 } 213 addAnnotationsAsAttribute(super.getConstantPool()); 214 return new Field(super.getAccessFlags(), name_index, signature_index, getAttributes(), 215 super.getConstantPool().getConstantPool()); // sic 216 } 217 218 private void addAnnotationsAsAttribute(final ConstantPoolGen cp) { 219 final Attribute[] attrs = AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries()); 220 for (final Attribute attr : attrs) { 221 addAttribute(attr); 222 } 223 } 224 225 private int addConstant() { 226 switch (super.getType().getType()) { // sic 227 case Const.T_INT: 228 case Const.T_CHAR: 229 case Const.T_BYTE: 230 case Const.T_BOOLEAN: 231 case Const.T_SHORT: 232 return super.getConstantPool().addInteger(((Integer) value)); 233 case Const.T_FLOAT: 234 return super.getConstantPool().addFloat(((Float) value)); 235 case Const.T_DOUBLE: 236 return super.getConstantPool().addDouble(((Double) value)); 237 case Const.T_LONG: 238 return super.getConstantPool().addLong(((Long) value)); 239 case Const.T_REFERENCE: 240 return super.getConstantPool().addString((String) value); 241 default: 242 throw new RuntimeException("Oops: Unhandled : " + super.getType().getType()); // sic 243 } 244 } 245 246 @Override 247 public String getSignature() { 248 return super.getType().getSignature(); 249 } 250 251 private List<FieldObserver> observers; 252 253 /** 254 * Add observer for this object. 255 */ 256 public void addObserver(final FieldObserver o) { 257 if (observers == null) { 258 observers = new ArrayList<>(); 259 } 260 observers.add(o); 261 } 262 263 /** 264 * Remove observer for this object. 265 */ 266 public void removeObserver(final FieldObserver o) { 267 if (observers != null) { 268 observers.remove(o); 269 } 270 } 271 272 /** 273 * Call notify() method on all observers. This method is not called 274 * automatically whenever the state has changed, but has to be called by the 275 * user after he has finished editing the object. 276 */ 277 public void update() { 278 if (observers != null) { 279 for (final FieldObserver observer : observers) { 280 observer.notify(this); 281 } 282 } 283 } 284 285 public String getInitValue() { 286 if (value != null) { 287 return value.toString(); 288 } 289 return null; 290 } 291 292 /** 293 * Return string representation close to declaration format, `public static 294 * final short MAX = 100', e.g.. 295 * 296 * @return String representation of field 297 */ 298 @Override 299 public final String toString() { 300 String name; 301 String signature; 302 String access; // Short cuts to constant pool 303 access = Utility.accessToString(super.getAccessFlags()); 304 access = access.isEmpty() ? "" : (access + " "); 305 signature = super.getType().toString(); 306 name = getName(); 307 final StringBuilder buf = new StringBuilder(32); // CHECKSTYLE IGNORE MagicNumber 308 buf.append(access).append(signature).append(" ").append(name); 309 final String value = getInitValue(); 310 if (value != null) { 311 buf.append(" = ").append(value); 312 } 313 return buf.toString(); 314 } 315 316 /** 317 * @return deep copy of this field 318 */ 319 public FieldGen copy(final ConstantPoolGen cp) { 320 final FieldGen fg = (FieldGen) clone(); 321 fg.setConstantPool(cp); 322 return fg; 323 } 324 325 /** 326 * @return Comparison strategy object 327 */ 328 public static BCELComparator getComparator() { 329 return bcelComparator; 330 } 331 332 /** 333 * @param comparator Comparison strategy object 334 */ 335 public static void setComparator(final BCELComparator comparator) { 336 bcelComparator = comparator; 337 } 338 339 /** 340 * Return value as defined by given BCELComparator strategy. By default two 341 * FieldGen objects are said to be equal when their names and signatures are 342 * equal. 343 * 344 * @see java.lang.Object#equals(java.lang.Object) 345 */ 346 @Override 347 public boolean equals(final Object obj) { 348 return bcelComparator.equals(this, obj); 349 } 350 351 /** 352 * Return value as defined by given BCELComparator strategy. By default 353 * return the hashcode of the field's name XOR signature. 354 * 355 * @see java.lang.Object#hashCode() 356 */ 357 @Override 358 public int hashCode() { 359 return bcelComparator.hashCode(this); 360 } 361 } |