1 package net.sf.cglib.transform.impl;
2
3 import net.sf.cglib.transform.*;
4 import net.sf.cglib.core.*;
5 import org.objectweb.asm.ClassVisitor;
6 import org.objectweb.asm.CodeAdapter;
7 import org.objectweb.asm.CodeVisitor;
8 import org.objectweb.asm.Attribute;
9 import org.objectweb.asm.Label;
10 import org.objectweb.asm.Type;
11
12 /***
13 * @author Juozas Baliuka, Chris Nokleberg
14 */
15 public class InterceptFieldTransformer extends ClassEmitterTransformer {
16 private static final String CALLBACK_FIELD = "$CGLIB_READ_WRITE_CALLBACK";
17 private static final Type CALLBACK =
18 TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldCallback");
19 private static final Type ENABLED =
20 TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldEnabled");
21 private static final Signature ENABLED_SET =
22 TypeUtils.parseSignature("void setInterceptFieldCallback(net.sf.cglib.transform.impl.InterceptFieldCallback)");
23 private static final Signature ENABLED_GET =
24 TypeUtils.parseSignature("net.sf.cglib.transform.impl.InterceptFieldCallback getInterceptFieldCallback()");
25
26 private InterceptFieldFilter filter;
27
28 public InterceptFieldTransformer(InterceptFieldFilter filter) {
29 this.filter = filter;
30 }
31
32 public void begin_class(int access, String className, Type superType, Type[] interfaces, String sourceFile) {
33 if (!TypeUtils.isInterface(access)) {
34 super.begin_class(access, className, superType, TypeUtils.add(interfaces, ENABLED), sourceFile);
35
36 super.declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
37 CALLBACK_FIELD,
38 CALLBACK,
39 null,
40 null);
41
42 CodeEmitter e;
43 e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_GET, null, null);
44 e.load_this();
45 e.getfield(CALLBACK_FIELD);
46 e.return_value();
47 e.end_method();
48
49 e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_SET, null, null);
50 e.load_this();
51 e.load_arg(0);
52 e.putfield(CALLBACK_FIELD);
53 e.return_value();
54 e.end_method();
55 } else {
56 super.begin_class(access, className, superType, interfaces, sourceFile);
57 }
58 }
59
60 public void declare_field(int access, String name, Type type, Object value, Attribute attrs) {
61 super.declare_field(access, name, type, value, attrs);
62 if (!TypeUtils.isStatic(access)) {
63 if (filter.acceptRead(getClassType(), name)) {
64 addReadMethod(name, type);
65 }
66 if (filter.acceptWrite(getClassType(), name)) {
67 addWriteMethod(name, type);
68 }
69 }
70 }
71
72 private void addReadMethod(String name, Type type) {
73 CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
74 readMethodSig(name, type.getDescriptor()),
75 null,
76 null);
77 e.load_this();
78 e.getfield(name);
79 e.load_this();
80 e.getfield(CALLBACK_FIELD);
81 Label intercept = e.make_label();
82 e.ifnonnull(intercept);
83 e.return_value();
84
85 e.mark(intercept);
86 Local result = e.make_local(type);
87 e.store_local(result);
88 e.load_this();
89 e.getfield(CALLBACK_FIELD);
90 e.load_this();
91 e.push(name);
92 e.load_local(result);
93 e.invoke_interface(CALLBACK, readCallbackSig(type));
94 if (!TypeUtils.isPrimitive(type)) {
95 e.checkcast(type);
96 }
97 e.return_value();
98 e.end_method();
99 }
100
101 private void addWriteMethod(String name, Type type) {
102 CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
103 writeMethodSig(name, type.getDescriptor()),
104 null,
105 null);
106 e.load_this();
107 e.dup();
108 e.getfield(CALLBACK_FIELD);
109 Label skip = e.make_label();
110 e.ifnull(skip);
111
112 e.load_this();
113 e.getfield(CALLBACK_FIELD);
114 e.load_this();
115 e.push(name);
116 e.load_this();
117 e.getfield(name);
118 e.load_arg(0);
119 e.invoke_interface(CALLBACK, writeCallbackSig(type));
120 if (!TypeUtils.isPrimitive(type)) {
121 e.checkcast(type);
122 }
123 Label go = e.make_label();
124 e.goTo(go);
125 e.mark(skip);
126 e.load_arg(0);
127 e.mark(go);
128 e.putfield(name);
129 e.return_value();
130 e.end_method();
131 }
132
133 public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions, Attribute attrs) {
134 return new CodeEmitter(super.begin_method(access, sig, exceptions, attrs)) {
135 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
136 Type towner = TypeUtils.fromInternalName(owner);
137 switch (opcode) {
138 case Constants.GETFIELD:
139 if (filter.acceptRead(towner, name)) {
140 helper(towner, readMethodSig(name, desc));
141 return;
142 }
143 break;
144 case Constants.PUTFIELD:
145 if (filter.acceptWrite(towner, name)) {
146 helper(towner, writeMethodSig(name, desc));
147 return;
148 }
149 break;
150 }
151 super.visitFieldInsn(opcode, owner, name, desc);
152 }
153
154 private void helper(Type owner, Signature sig) {
155 invoke_virtual(owner, sig);
156 }
157 };
158 }
159
160 private static Signature readMethodSig(String name, String desc) {
161 return new Signature("$cglib_read_" + name, "()" + desc);
162 }
163
164 private static Signature writeMethodSig(String name, String desc) {
165 return new Signature("$cglib_write_" + name, "(" + desc + ")V");
166 }
167
168 private static Signature readCallbackSig(Type type) {
169 Type remap = remap(type);
170 return new Signature("read" + callbackName(remap),
171 remap,
172 new Type[]{ Constants.TYPE_OBJECT,
173 Constants.TYPE_STRING,
174 remap });
175 }
176
177 private static Signature writeCallbackSig(Type type) {
178 Type remap = remap(type);
179 return new Signature("write" + callbackName(remap),
180 remap,
181 new Type[]{ Constants.TYPE_OBJECT,
182 Constants.TYPE_STRING,
183 remap,
184 remap });
185 }
186
187 private static Type remap(Type type) {
188 switch (type.getSort()) {
189 case Type.OBJECT:
190 case Type.ARRAY:
191 return Constants.TYPE_OBJECT;
192 default:
193 return type;
194 }
195 }
196
197 private static String callbackName(Type type) {
198 return (type == Constants.TYPE_OBJECT) ?
199 "Object" :
200 TypeUtils.upperFirst(TypeUtils.getClassName(type));
201 }
202 }
This page was automatically generated by Maven