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 }