View Javadoc
1 package net.sf.cglib.transform.impl; 2 3 import net.sf.cglib.transform.*; 4 import java.util.*; 5 import net.sf.cglib.core.*; 6 import org.objectweb.asm.Attribute; 7 import org.objectweb.asm.Label; 8 import org.objectweb.asm.Type; 9 10 public class FieldProviderTransformer extends ClassEmitterTransformer { 11 12 private static final String FIELD_NAMES = "CGLIB$FIELD_NAMES"; 13 private static final String FIELD_TYPES = "CGLIB$FIELD_TYPES"; 14 15 private static final Type FIELD_PROVIDER = 16 TypeUtils.parseType("net.sf.cglib.transform.impl.FieldProvider"); 17 private static final Type ILLEGAL_ARGUMENT_EXCEPTION = 18 TypeUtils.parseType("IllegalArgumentException"); 19 private static final Signature PROVIDER_GET = 20 TypeUtils.parseSignature("Object getField(String)"); 21 private static final Signature PROVIDER_SET = 22 TypeUtils.parseSignature("void setField(String, Object)"); 23 private static final Signature PROVIDER_SET_BY_INDEX = 24 TypeUtils.parseSignature("void setField(int, Object)"); 25 private static final Signature PROVIDER_GET_BY_INDEX = 26 TypeUtils.parseSignature("Object getField(int)"); 27 private static final Signature PROVIDER_GET_TYPES = 28 TypeUtils.parseSignature("Class[] getFieldTypes()"); 29 private static final Signature PROVIDER_GET_NAMES = 30 TypeUtils.parseSignature("String[] getFieldNames()"); 31 32 private int access; 33 private Map fields; 34 35 public void begin_class(int access, String className, Type superType, Type[] interfaces, String sourceFile) { 36 if (!TypeUtils.isAbstract(access)) { 37 interfaces = TypeUtils.add(interfaces, FIELD_PROVIDER); 38 } 39 this.access = access; 40 fields = new HashMap(); 41 super.begin_class(access, className, superType, interfaces, sourceFile); 42 } 43 44 public void declare_field(int access, String name, Type type, Object value, Attribute attrs) { 45 super.declare_field(access, name, type, value, attrs); 46 47 if (!TypeUtils.isStatic(access)) { 48 fields.put(name, type); 49 } 50 } 51 52 public void end_class() { 53 if (!TypeUtils.isInterface(access)) { 54 try { 55 generate(); 56 } catch (RuntimeException e) { 57 throw e; 58 } catch (Exception e) { 59 throw new CodeGenerationException(e); 60 } 61 } 62 super.end_class(); 63 } 64 65 private void generate() throws Exception { 66 final String[] names = (String[])fields.keySet().toArray(new String[fields.size()]); 67 68 int indexes[] = new int[names.length]; 69 for (int i = 0; i < indexes.length; i++) { 70 indexes[i] = i; 71 } 72 73 super.declare_field(Constants.PRIVATE_FINAL_STATIC, FIELD_NAMES, Constants.TYPE_STRING_ARRAY, null, null); 74 super.declare_field(Constants.PRIVATE_FINAL_STATIC, FIELD_TYPES, Constants.TYPE_CLASS_ARRAY, null, null); 75 76 // use separate methods here because each process switch inner class needs a final CodeEmitter 77 initFieldProvider(names); 78 getNames(); 79 getTypes(); 80 getField(names); 81 setField(names); 82 setByIndex(names, indexes); 83 getByIndex(names, indexes); 84 } 85 86 private void initFieldProvider(String[] names) { 87 CodeEmitter e = getStaticHook(); 88 EmitUtils.push_object(e, names); 89 e.putstatic(getClassType(), FIELD_NAMES, Constants.TYPE_STRING_ARRAY); 90 91 e.push(names.length); 92 e.newarray(Constants.TYPE_CLASS); 93 e.dup(); 94 for(int i = 0; i < names.length; i++ ){ 95 e.dup(); 96 e.push(i); 97 Type type = (Type)fields.get(names[i]); 98 EmitUtils.load_class(e, type); 99 e.aastore(); 100 } 101 e.putstatic(getClassType(), FIELD_TYPES, Constants.TYPE_CLASS_ARRAY); 102 } 103 104 private void getNames() { 105 CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_NAMES, null, null); 106 e.getstatic(getClassType(), FIELD_NAMES, Constants.TYPE_STRING_ARRAY); 107 e.return_value(); 108 e.end_method(); 109 } 110 111 private void getTypes() { 112 CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_TYPES, null, null); 113 e.getstatic(getClassType(), FIELD_TYPES, Constants.TYPE_CLASS_ARRAY); 114 e.return_value(); 115 e.end_method(); 116 } 117 118 private void setByIndex(final String[] names, final int[] indexes) throws Exception { 119 final CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_SET_BY_INDEX, null, null); 120 e.load_this(); 121 e.load_arg(1); 122 e.load_arg(0); 123 e.process_switch(indexes, new ProcessSwitchCallback() { 124 public void processCase(int key, Label end) throws Exception { 125 Type type = (Type)fields.get(names[key]); 126 e.unbox(type); 127 e.putfield(names[key]); 128 e.return_value(); 129 } 130 public void processDefault() throws Exception { 131 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field index"); 132 } 133 }); 134 e.end_method(); 135 } 136 137 private void getByIndex(final String[] names, final int[] indexes) throws Exception { 138 final CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_BY_INDEX, null, null); 139 e.load_this(); 140 e.load_arg(0); 141 e.process_switch(indexes, new ProcessSwitchCallback() { 142 public void processCase(int key, Label end) throws Exception { 143 Type type = (Type)fields.get(names[key]); 144 e.getfield(names[key]); 145 e.box(type); 146 e.return_value(); 147 } 148 public void processDefault() throws Exception { 149 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field index"); 150 } 151 }); 152 e.end_method(); 153 } 154 155 // TODO: if this is used to enhance class files SWITCH_STYLE_TRIE should be used 156 // to avoid JVM hashcode implementation incompatibilities 157 private void getField(String[] names) throws Exception { 158 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, PROVIDER_GET, null, null); 159 e.load_this(); 160 e.load_arg(0); 161 EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 162 public void processCase(Object key, Label end) { 163 Type type = (Type)fields.get(key); 164 e.getfield((String)key); 165 e.box(type); 166 e.return_value(); 167 } 168 public void processDefault() { 169 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field name"); 170 } 171 }); 172 e.end_method(); 173 } 174 175 private void setField(String[] names) throws Exception { 176 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, PROVIDER_SET, null, null); 177 e.load_this(); 178 e.load_arg(1); 179 e.load_arg(0); 180 EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 181 public void processCase(Object key, Label end) { 182 Type type = (Type)fields.get(key); 183 e.unbox(type); 184 e.putfield((String)key); 185 e.return_value(); 186 } 187 public void processDefault() { 188 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field name"); 189 } 190 }); 191 e.end_method(); 192 } 193 }

This page was automatically generated by Maven