1 16 package net.sf.cglib.core; 17 18 import java.io.*; 19 import java.util.*; 20 import org.objectweb.asm.*; 21 22 25 public class ClassEmitter extends ClassAdapter { 26 private ClassInfo classInfo; 27 private Map fieldInfo; 28 29 private static int hookCounter; 30 private MethodVisitor rawStaticInit; 31 private CodeEmitter staticInit; 32 private CodeEmitter staticHook; 33 private Signature staticHookSig; 34 35 public ClassEmitter(ClassVisitor cv) { 36 super(null); 37 setTarget(cv); 38 } 39 40 public ClassEmitter() { 41 super(null); 42 } 43 44 public void setTarget(ClassVisitor cv) { 45 this.cv = cv; 46 fieldInfo = new HashMap(); 47 48 staticInit = staticHook = null; 50 staticHookSig = null; 51 } 52 53 synchronized private static int getNextHook() { 54 return ++hookCounter; 55 } 56 57 public ClassInfo getClassInfo() { 58 return classInfo; 59 } 60 61 public void begin_class(int version, final int access, String className, final Type superType, final Type[] interfaces, String source) { 62 final Type classType = Type.getType("L" + className.replace('.', '/') + ";"); 63 classInfo = new ClassInfo() { 64 public Type getType() { 65 return classType; 66 } 67 public Type getSuperType() { 68 return (superType != null) ? superType : Constants.TYPE_OBJECT; 69 } 70 public Type[] getInterfaces() { 71 return interfaces; 72 } 73 public int getModifiers() { 74 return access; 75 } 76 }; 77 cv.visit(version, 78 access, 79 classInfo.getType().getInternalName(), 80 null, 81 classInfo.getSuperType().getInternalName(), 82 TypeUtils.toInternalNames(interfaces)); 83 if (source != null) 84 cv.visitSource(source, null); 85 init(); 86 } 87 88 public CodeEmitter getStaticHook() { 89 if (TypeUtils.isInterface(getAccess())) { 90 throw new IllegalStateException ("static hook is invalid for this class"); 91 } 92 if (staticHook == null) { 93 staticHookSig = new Signature("CGLIB$STATICHOOK" + getNextHook(), "()V"); 94 staticHook = begin_method(Constants.ACC_STATIC, 95 staticHookSig, 96 null); 97 if (staticInit != null) { 98 staticInit.invoke_static_this(staticHookSig); 99 } 100 } 101 return staticHook; 102 } 103 104 protected void init() { 105 } 106 107 public int getAccess() { 108 return classInfo.getModifiers(); 109 } 110 111 public Type getClassType() { 112 return classInfo.getType(); 113 } 114 115 public Type getSuperType() { 116 return classInfo.getSuperType(); 117 } 118 119 public void end_class() { 120 if (staticHook != null && staticInit == null) { 121 begin_static(); 123 } 124 if (staticInit != null) { 125 staticHook.return_value(); 126 staticHook.end_method(); 127 rawStaticInit.visitInsn(Constants.RETURN); 128 rawStaticInit.visitMaxs(0, 0); 129 staticInit = staticHook = null; 130 staticHookSig = null; 131 } 132 cv.visitEnd(); 133 } 134 135 public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) { 136 if (classInfo == null) 137 throw new IllegalStateException ("classInfo is null! " + this); 138 MethodVisitor v = cv.visitMethod(access, 139 sig.getName(), 140 sig.getDescriptor(), 141 null, 142 TypeUtils.toInternalNames(exceptions)); 143 if (sig.equals(Constants.SIG_STATIC) && !TypeUtils.isInterface(getAccess())) { 144 rawStaticInit = v; 145 MethodVisitor wrapped = new MethodAdapter(v) { 146 public void visitMaxs(int maxStack, int maxLocals) { 147 } 149 public void visitInsn(int insn) { 150 if (insn != Constants.RETURN) { 151 super.visitInsn(insn); 152 } 153 } 154 }; 155 staticInit = new CodeEmitter(this, wrapped, access, sig, exceptions); 156 if (staticHook == null) { 157 getStaticHook(); 159 } else { 160 staticInit.invoke_static_this(staticHookSig); 161 } 162 return staticInit; 163 } else if (sig.equals(staticHookSig)) { 164 return new CodeEmitter(this, v, access, sig, exceptions) { 165 public boolean isStaticHook() { 166 return true; 167 } 168 }; 169 } else { 170 return new CodeEmitter(this, v, access, sig, exceptions); 171 } 172 } 173 174 public CodeEmitter begin_static() { 175 return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null); 176 } 177 178 public void declare_field(int access, String name, Type type, Object value) { 179 FieldInfo existing = (FieldInfo)fieldInfo.get(name); 180 FieldInfo info = new FieldInfo(access, name, type, value); 181 if (existing != null) { 182 if (!info.equals(existing)) { 183 throw new IllegalArgumentException ("Field \"" + name + "\" has been declared differently"); 184 } 185 } else { 186 fieldInfo.put(name, info); 187 cv.visitField(access, name, type.getDescriptor(), null, value); 188 } 189 } 190 191 boolean isFieldDeclared(String name) { 193 return fieldInfo.get(name) != null; 194 } 195 196 FieldInfo getFieldInfo(String name) { 197 FieldInfo field = (FieldInfo)fieldInfo.get(name); 198 if (field == null) { 199 throw new IllegalArgumentException ("Field " + name + " is not declared in " + getClassType().getClassName()); 200 } 201 return field; 202 } 203 204 static class FieldInfo { 205 int access; 206 String name; 207 Type type; 208 Object value; 209 210 public FieldInfo(int access, String name, Type type, Object value) { 211 this.access = access; 212 this.name = name; 213 this.type = type; 214 this.value = value; 215 } 216 217 public boolean equals(Object o) { 218 if (o == null) 219 return false; 220 if (!(o instanceof FieldInfo)) 221 return false; 222 FieldInfo other = (FieldInfo)o; 223 if (access != other.access || 224 !name.equals(other.name) || 225 !type.equals(other.type)) { 226 return false; 227 } 228 if ((value == null) ^ (other.value == null)) 229 return false; 230 if (value != null && !value.equals(other.value)) 231 return false; 232 return true; 233 } 234 235 public int hashCode() { 236 return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode()); 237 } 238 } 239 240 public void visit(int version, 241 int access, 242 String name, 243 String signature, 244 String superName, 245 String [] interfaces) { 246 begin_class(version, 247 access, 248 name.replace('/', '.'), 249 TypeUtils.fromInternalName(superName), 250 TypeUtils.fromInternalNames(interfaces), 251 null); } 253 254 public void visitEnd() { 255 end_class(); 256 } 257 258 public FieldVisitor visitField(int access, 259 String name, 260 String desc, 261 String signature, 262 Object value) { 263 declare_field(access, name, Type.getType(desc), value); 264 return null; } 266 267 public MethodVisitor visitMethod(int access, 268 String name, 269 String desc, 270 String signature, 271 String [] exceptions) { 272 return begin_method(access, 273 new Signature(name, desc), 274 TypeUtils.fromInternalNames(exceptions)); 275 } 276 } 277 | Popular Tags |