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