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