Commit 0e3dd41eb133563ef7cc5c1d1a2fedde47eb4142

Authored by Mumfrey
1 parent d28d5dde

adding javadoc to AccessorTransformer, throw an exception from un-annotated methods

java/common/com/mumfrey/liteloader/transformers/access/AccessorTransformer.java
@@ -7,7 +7,6 @@ import java.util.List; @@ -7,7 +7,6 @@ import java.util.List;
7 7
8 import net.minecraft.launchwrapper.Launch; 8 import net.minecraft.launchwrapper.Launch;
9 9
10 -import org.objectweb.asm.ClassReader;  
11 import org.objectweb.asm.Opcodes; 10 import org.objectweb.asm.Opcodes;
12 import org.objectweb.asm.Type; 11 import org.objectweb.asm.Type;
13 import org.objectweb.asm.tree.AnnotationNode; 12 import org.objectweb.asm.tree.AnnotationNode;
@@ -15,8 +14,10 @@ import org.objectweb.asm.tree.ClassNode; @@ -15,8 +14,10 @@ import org.objectweb.asm.tree.ClassNode;
15 import org.objectweb.asm.tree.FieldInsnNode; 14 import org.objectweb.asm.tree.FieldInsnNode;
16 import org.objectweb.asm.tree.FieldNode; 15 import org.objectweb.asm.tree.FieldNode;
17 import org.objectweb.asm.tree.InsnNode; 16 import org.objectweb.asm.tree.InsnNode;
  17 +import org.objectweb.asm.tree.LdcInsnNode;
18 import org.objectweb.asm.tree.MethodInsnNode; 18 import org.objectweb.asm.tree.MethodInsnNode;
19 import org.objectweb.asm.tree.MethodNode; 19 import org.objectweb.asm.tree.MethodNode;
  20 +import org.objectweb.asm.tree.TypeInsnNode;
20 import org.objectweb.asm.tree.VarInsnNode; 21 import org.objectweb.asm.tree.VarInsnNode;
21 22
22 import com.mumfrey.liteloader.core.runtime.Obf; 23 import com.mumfrey.liteloader.core.runtime.Obf;
@@ -26,7 +27,7 @@ import com.mumfrey.liteloader.transformers.ObfProvider; @@ -26,7 +27,7 @@ import com.mumfrey.liteloader.transformers.ObfProvider;
26 import com.mumfrey.liteloader.util.log.LiteLoaderLogger; 27 import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
27 28
28 /** 29 /**
29 - * Transformer which can inject accessor methods into a target class 30 + * Transformer which can inject accessor methods defined by an annotated interface into a target class
30 * 31 *
31 * @author Adam Mummery-Smith 32 * @author Adam Mummery-Smith
32 */ 33 */
@@ -59,34 +60,47 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -59,34 +60,47 @@ public abstract class AccessorTransformer extends ClassTransformer
59 */ 60 */
60 private final Obf target; 61 private final Obf target;
61 62
  63 + /**
  64 + * Create a new new accessor using the specified template interface
  65 + *
  66 + * @param iface Template interface
  67 + * @throws IOException Thrown if an problem occurs when loading the interface bytecode
  68 + */
62 protected AccessorInjection(String iface) throws IOException 69 protected AccessorInjection(String iface) throws IOException
63 { 70 {
64 this(iface, null); 71 this(iface, null);
65 } 72 }
66 73
  74 + /**
  75 + * Create a new new accessor using the specified template interface
  76 + *
  77 + * @param iface Template interface
  78 + * @param obfProvider Obfuscation provider for this context
  79 + * @throws IOException Thrown if an problem occurs when loading the interface bytecode
  80 + */
67 protected AccessorInjection(String iface, ObfProvider obfProvider) throws IOException 81 protected AccessorInjection(String iface, ObfProvider obfProvider) throws IOException
68 { 82 {
69 - ClassNode ifaceNode = this.loadClass(iface); 83 + ClassNode ifaceNode = ByteCodeUtilities.loadClass(iface, false);
  84 +
  85 + if (ifaceNode.interfaces.size() > 0)
  86 + {
  87 + String interfaceList = ifaceNode.interfaces.toString().replace('/', '.');
  88 + throw new RuntimeException("Accessor interface must not extend other interfaces. Found " + interfaceList + " in " + iface);
  89 + }
  90 +
70 this.table = this.setupTable(ifaceNode); 91 this.table = this.setupTable(ifaceNode);
71 this.target = this.setupTarget(ifaceNode); 92 this.target = this.setupTarget(ifaceNode);
72 this.iface = iface; 93 this.iface = iface;
73 this.obfProvider = obfProvider; 94 this.obfProvider = obfProvider;
74 } 95 }
75 -  
76 - private ClassNode loadClass(String iface) throws IOException  
77 - {  
78 - byte[] bytes = this.getClassBytes(iface);  
79 - ClassReader classReader = new ClassReader(bytes);  
80 - ClassNode classNode = new ClassNode();  
81 - classReader.accept(classNode, 0);  
82 - return classNode;  
83 - }  
84 -  
85 - private byte[] getClassBytes(String iface) throws IOException  
86 - {  
87 - return Launch.classLoader.getClassBytes(iface);  
88 - }  
89 96
  97 + /**
  98 + * Get an obfuscation table mapping by name, first uses any supplied context provider, then any obfuscation table
  99 + * class specified by an {@link ObfTableClass} annotation on the interface itself, and fails over onto the LiteLoader
  100 + * obfuscation table. If the entry is not matched in any of the above locations then an exception is thrown
  101 + *
  102 + * @param name Obfuscation table entry to fetch
  103 + */
90 private Obf getObf(String name) 104 private Obf getObf(String name)
91 { 105 {
92 if (this.obfProvider != null) 106 if (this.obfProvider != null)
@@ -107,11 +121,18 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -107,11 +121,18 @@ public abstract class AccessorTransformer extends ClassTransformer
107 throw new RuntimeException("No obfuscation table entry could be found for '" + name + "'"); 121 throw new RuntimeException("No obfuscation table entry could be found for '" + name + "'");
108 } 122 }
109 123
  124 + /**
  125 + * Get the target class of this injection
  126 + */
110 protected Obf getTarget() 127 protected Obf getTarget()
111 { 128 {
112 return this.target; 129 return this.target;
113 } 130 }
114 131
  132 + /**
  133 + * Inspects the target class for an {@link ObfTableClass} annotation and attempts to get a handle for the class
  134 + * specified. On failure, the LiteLoader {@link Obf} is returned.
  135 + */
115 @SuppressWarnings("unchecked") 136 @SuppressWarnings("unchecked")
116 private Class<? extends Obf> setupTable(ClassNode ifaceNode) 137 private Class<? extends Obf> setupTable(ClassNode ifaceNode)
117 { 138 {
@@ -132,12 +153,31 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -132,12 +153,31 @@ public abstract class AccessorTransformer extends ClassTransformer
132 return Obf.class; 153 return Obf.class;
133 } 154 }
134 155
  156 + /**
  157 + * Locates the {@link Accessor} annotation on the interface in order to determine the target class
  158 + */
135 private Obf setupTarget(ClassNode ifaceNode) 159 private Obf setupTarget(ClassNode ifaceNode)
136 { 160 {
137 AnnotationNode annotation = ByteCodeUtilities.getInvisibleAnnotation(ifaceNode, Accessor.class); 161 AnnotationNode annotation = ByteCodeUtilities.getInvisibleAnnotation(ifaceNode, Accessor.class);
138 - return this.getObf(ByteCodeUtilities.<String>getAnnotationValue(annotation)); 162 + if (annotation == null)
  163 + {
  164 + throw new RuntimeException("Accessor interfaces must be annotated with an @Accessor annotation specifying the target class");
  165 + }
  166 +
  167 + String targetClass = ByteCodeUtilities.<String>getAnnotationValue(annotation);
  168 + if (targetClass == null || targetClass.isEmpty())
  169 + {
  170 + throw new RuntimeException("Invalid @Accessor annotation, the annotation must specify a target class");
  171 + }
  172 +
  173 + return this.getObf(targetClass);
139 } 174 }
140 175
  176 + /**
  177 + * Apply this injection to the specified target ClassNode
  178 + *
  179 + * @param classNode Class tree to apply to
  180 + */
141 protected void apply(ClassNode classNode) 181 protected void apply(ClassNode classNode)
142 { 182 {
143 String ifaceRef = this.iface.replace('.', '/'); 183 String ifaceRef = this.iface.replace('.', '/');
@@ -166,6 +206,12 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -166,6 +206,12 @@ public abstract class AccessorTransformer extends ClassTransformer
166 } 206 }
167 } 207 }
168 208
  209 + /**
  210 + * Add a method from the interface to the target class
  211 + *
  212 + * @param classNode Target class
  213 + * @param method Method to add
  214 + */
169 private void addMethod(ClassNode classNode, MethodNode method) 215 private void addMethod(ClassNode classNode, MethodNode method)
170 { 216 {
171 if (!this.addMethodToClass(classNode, method)) 217 if (!this.addMethodToClass(classNode, method))
@@ -176,26 +222,39 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -176,26 +222,39 @@ public abstract class AccessorTransformer extends ClassTransformer
176 222
177 LiteLoaderLogger.debug("[AccessorTransformer] Attempting to add %s to %s", method.name, classNode.name); 223 LiteLoaderLogger.debug("[AccessorTransformer] Attempting to add %s to %s", method.name, classNode.name);
178 224
  225 + String targetId = null;
179 AnnotationNode accessor = ByteCodeUtilities.getInvisibleAnnotation(method, Accessor.class); 226 AnnotationNode accessor = ByteCodeUtilities.getInvisibleAnnotation(method, Accessor.class);
180 AnnotationNode invoker = ByteCodeUtilities.getInvisibleAnnotation(method, Invoker.class); 227 AnnotationNode invoker = ByteCodeUtilities.getInvisibleAnnotation(method, Invoker.class);
181 if (accessor != null) 228 if (accessor != null)
182 { 229 {
183 - Obf targetName = this.getObf(ByteCodeUtilities.<String>getAnnotationValue(accessor)); 230 + targetId = ByteCodeUtilities.<String>getAnnotationValue(accessor);
  231 + Obf targetName = this.getObf(targetId);
184 if (this.injectAccessor(classNode, method, targetName)) return; 232 if (this.injectAccessor(classNode, method, targetName)) return;
185 } 233 }
186 else if (invoker != null) 234 else if (invoker != null)
187 { 235 {
188 - Obf targetName = this.getObf(ByteCodeUtilities.<String>getAnnotationValue(invoker)); 236 + targetId = ByteCodeUtilities.<String>getAnnotationValue(invoker);
  237 + Obf targetName = this.getObf(targetId);
189 if (this.injectInvoker(classNode, method, targetName)) return; 238 if (this.injectInvoker(classNode, method, targetName)) return;
190 } 239 }
191 else 240 else
192 { 241 {
193 LiteLoaderLogger.severe("[AccessorTransformer] Method %s for %s has no @Accessor or @Invoker annotation, the method will be ABSTRACT!", method.name, this.iface); 242 LiteLoaderLogger.severe("[AccessorTransformer] Method %s for %s has no @Accessor or @Invoker annotation, the method will be ABSTRACT!", method.name, this.iface);
  243 + this.injectException(classNode, method, "No @Accessor or @Invoker annotation on method");
  244 + return;
194 } 245 }
195 246
196 LiteLoaderLogger.severe("[AccessorTransformer] Method %s for %s could not locate target member, the method will be ABSTRACT!", method.name, this.iface); 247 LiteLoaderLogger.severe("[AccessorTransformer] Method %s for %s could not locate target member, the method will be ABSTRACT!", method.name, this.iface);
  248 + this.injectException(classNode, method, "Could not locate target class member '" + targetId + "'");
197 } 249 }
198 250
  251 + /**
  252 + * Inject an accessor method into the target class
  253 + *
  254 + * @param classNode
  255 + * @param method
  256 + * @param targetName
  257 + */
199 private boolean injectAccessor(ClassNode classNode, MethodNode method, Obf targetName) 258 private boolean injectAccessor(ClassNode classNode, MethodNode method, Obf targetName)
200 { 259 {
201 FieldNode targetField = this.findField(classNode, targetName); 260 FieldNode targetField = this.findField(classNode, targetName);
@@ -217,6 +276,13 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -217,6 +276,13 @@ public abstract class AccessorTransformer extends ClassTransformer
217 return false; 276 return false;
218 } 277 }
219 278
  279 + /**
  280 + * Inject an invoke (proxy) method into the target class
  281 + *
  282 + * @param classNode
  283 + * @param method
  284 + * @param targetName
  285 + */
220 private boolean injectInvoker(ClassNode classNode, MethodNode method, Obf targetName) 286 private boolean injectInvoker(ClassNode classNode, MethodNode method, Obf targetName)
221 { 287 {
222 MethodNode targetMethod = this.findMethod(classNode, targetName, method.desc); 288 MethodNode targetMethod = this.findMethod(classNode, targetName, method.desc);
@@ -230,6 +296,13 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -230,6 +296,13 @@ public abstract class AccessorTransformer extends ClassTransformer
230 return false; 296 return false;
231 } 297 }
232 298
  299 + /**
  300 + * Populate the bytecode instructions for a getter accessor
  301 + *
  302 + * @param classNode
  303 + * @param method
  304 + * @param field
  305 + */
233 private void populateGetter(ClassNode classNode, MethodNode method, FieldNode field) 306 private void populateGetter(ClassNode classNode, MethodNode method, FieldNode field)
234 { 307 {
235 Type returnType = Type.getReturnType(method.desc); 308 Type returnType = Type.getReturnType(method.desc);
@@ -238,24 +311,32 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -238,24 +311,32 @@ public abstract class AccessorTransformer extends ClassTransformer
238 { 311 {
239 throw new RuntimeException("Incompatible types! Field type: " + fieldType + " Method type: " + returnType); 312 throw new RuntimeException("Incompatible types! Field type: " + fieldType + " Method type: " + returnType);
240 } 313 }
  314 + boolean isStatic = (field.access & Opcodes.ACC_STATIC) != 0;
241 315
242 method.instructions.clear(); 316 method.instructions.clear();
243 method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method); 317 method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method);
244 method.maxStack = fieldType.getSize(); 318 method.maxStack = fieldType.getSize();
245 319
246 - if ((field.access & Opcodes.ACC_STATIC) == 0) 320 + if (isStatic)
247 { 321 {
248 - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));  
249 - method.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, field.name, field.desc)); 322 + method.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, field.name, field.desc));
250 } 323 }
251 else 324 else
252 { 325 {
253 - method.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, field.name, field.desc)); 326 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
  327 + method.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, field.name, field.desc));
254 } 328 }
255 329
256 method.instructions.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN))); 330 method.instructions.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
257 } 331 }
258 332
  333 + /**
  334 + * Populate the bytecode instructions for a setter
  335 + *
  336 + * @param classNode
  337 + * @param method
  338 + * @param field
  339 + */
259 private void populateSetter(ClassNode classNode, MethodNode method, FieldNode field) 340 private void populateSetter(ClassNode classNode, MethodNode method, FieldNode field)
260 { 341 {
261 Type[] argTypes = Type.getArgumentTypes(method.desc); 342 Type[] argTypes = Type.getArgumentTypes(method.desc);
@@ -269,26 +350,34 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -269,26 +350,34 @@ public abstract class AccessorTransformer extends ClassTransformer
269 { 350 {
270 throw new RuntimeException("Incompatible types! Field type: " + fieldType + " Method type: " + argType); 351 throw new RuntimeException("Incompatible types! Field type: " + fieldType + " Method type: " + argType);
271 } 352 }
  353 + boolean isStatic = (field.access & Opcodes.ACC_STATIC) != 0;
272 354
273 method.instructions.clear(); 355 method.instructions.clear();
274 method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method); 356 method.maxLocals = ByteCodeUtilities.getFirstNonArgLocalIndex(method);
275 method.maxStack = fieldType.getSize(); 357 method.maxStack = fieldType.getSize();
276 358
277 - if ((field.access & Opcodes.ACC_STATIC) == 0) 359 + if (isStatic)
278 { 360 {
279 - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));  
280 - method.instructions.add(new VarInsnNode(argType.getOpcode(Opcodes.ILOAD), 1));  
281 - method.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, field.desc)); 361 + method.instructions.add(new VarInsnNode(argType.getOpcode(Opcodes.ILOAD), 0));
  362 + method.instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, field.name, field.desc));
282 } 363 }
283 else 364 else
284 { 365 {
285 - method.instructions.add(new VarInsnNode(argType.getOpcode(Opcodes.ILOAD), 0));  
286 - method.instructions.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, field.name, field.desc)); 366 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
  367 + method.instructions.add(new VarInsnNode(argType.getOpcode(Opcodes.ILOAD), 1));
  368 + method.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, field.desc));
287 } 369 }
288 370
289 method.instructions.add(new InsnNode(Opcodes.RETURN)); 371 method.instructions.add(new InsnNode(Opcodes.RETURN));
290 } 372 }
291 373
  374 + /**
  375 + * Populate the bytecode instructions for an invoker (proxy) method
  376 + *
  377 + * @param classNode
  378 + * @param method
  379 + * @param targetMethod
  380 + */
292 private void populateInvoker(ClassNode classNode, MethodNode method, MethodNode targetMethod) 381 private void populateInvoker(ClassNode classNode, MethodNode method, MethodNode targetMethod)
293 { 382 {
294 Type[] args = Type.getArgumentTypes(targetMethod.desc); 383 Type[] args = Type.getArgumentTypes(targetMethod.desc);
@@ -313,6 +402,31 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -313,6 +402,31 @@ public abstract class AccessorTransformer extends ClassTransformer
313 method.instructions.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN))); 402 method.instructions.add(new InsnNode(returnType.getOpcode(Opcodes.IRETURN)));
314 } 403 }
315 404
  405 + /**
  406 + * Populate bytecode instructions for a method which throws an exception
  407 + *
  408 + * @param classNode
  409 + * @param method
  410 + * @param message
  411 + */
  412 + private void injectException(ClassNode classNode, MethodNode method, String message)
  413 + {
  414 + method.instructions.clear();
  415 + method.maxStack = 2;
  416 +
  417 + method.instructions.add(new TypeInsnNode(Opcodes.NEW, "java/lang/RuntimeException"));
  418 + method.instructions.add(new InsnNode(Opcodes.DUP));
  419 + method.instructions.add(new LdcInsnNode(message));
  420 + method.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V", false));
  421 + method.instructions.add(new InsnNode(Opcodes.ATHROW));
  422 + }
  423 +
  424 + /**
  425 + * Find a field in the target class which matches the specified field name
  426 + *
  427 + * @param classNode
  428 + * @param fieldName
  429 + */
316 private FieldNode findField(ClassNode classNode, Obf fieldName) 430 private FieldNode findField(ClassNode classNode, Obf fieldName)
317 { 431 {
318 for (FieldNode field : classNode.fields) 432 for (FieldNode field : classNode.fields)
@@ -324,6 +438,13 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -324,6 +438,13 @@ public abstract class AccessorTransformer extends ClassTransformer
324 return null; 438 return null;
325 } 439 }
326 440
  441 + /**
  442 + * Find a method in the target class which matches the specified method name and descriptor
  443 + *
  444 + * @param classNode
  445 + * @param methodName
  446 + * @param desc
  447 + */
327 private MethodNode findMethod(ClassNode classNode, Obf methodName, String desc) 448 private MethodNode findMethod(ClassNode classNode, Obf methodName, String desc)
328 { 449 {
329 for (MethodNode method : classNode.methods) 450 for (MethodNode method : classNode.methods)
@@ -335,6 +456,12 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -335,6 +456,12 @@ public abstract class AccessorTransformer extends ClassTransformer
335 return null; 456 return null;
336 } 457 }
337 458
  459 + /**
  460 + * Add a method from the template interface to the target class
  461 + *
  462 + * @param classNode
  463 + * @param method
  464 + */
338 private boolean addMethodToClass(ClassNode classNode, MethodNode method) 465 private boolean addMethodToClass(ClassNode classNode, MethodNode method)
339 { 466 {
340 MethodNode existingMethod = ByteCodeUtilities.findTargetMethod(classNode, method); 467 MethodNode existingMethod = ByteCodeUtilities.findTargetMethod(classNode, method);
@@ -345,18 +472,33 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -345,18 +472,33 @@ public abstract class AccessorTransformer extends ClassTransformer
345 } 472 }
346 } 473 }
347 474
  475 + /**
  476 + * List of accessors to inject
  477 + */
348 private final List<AccessorInjection> accessors = new ArrayList<AccessorInjection>(); 478 private final List<AccessorInjection> accessors = new ArrayList<AccessorInjection>();
349 479
  480 + /**
  481 + * ctor
  482 + */
350 public AccessorTransformer() 483 public AccessorTransformer()
351 { 484 {
352 this.addAccessors(); 485 this.addAccessors();
353 } 486 }
354 487
  488 + /**
  489 + * @param interfaceName
  490 + */
355 public void addAccessor(String interfaceName) 491 public void addAccessor(String interfaceName)
356 { 492 {
357 this.addAccessor(interfaceName, null); 493 this.addAccessor(interfaceName, null);
358 } 494 }
359 495
  496 + /**
  497 + * Add an accessor to the accessors list
  498 + *
  499 + * @param interfaceName
  500 + * @param obfProvider
  501 + */
360 public void addAccessor(String interfaceName, ObfProvider obfProvider) 502 public void addAccessor(String interfaceName, ObfProvider obfProvider)
361 { 503 {
362 try 504 try
@@ -369,6 +511,9 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -369,6 +511,9 @@ public abstract class AccessorTransformer extends ClassTransformer
369 } 511 }
370 } 512 }
371 513
  514 + /* (non-Javadoc)
  515 + * @see net.minecraft.launchwrapper.IClassTransformer#transform(java.lang.String, java.lang.String, byte[])
  516 + */
372 @Override 517 @Override
373 public byte[] transform(String name, String transformedName, byte[] basicClass) 518 public byte[] transform(String name, String transformedName, byte[] basicClass)
374 { 519 {
@@ -385,6 +530,16 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -385,6 +530,16 @@ public abstract class AccessorTransformer extends ClassTransformer
385 return basicClass; 530 return basicClass;
386 } 531 }
387 532
  533 + /**
  534 + * Apply this transformer, used when this transformer is acting as a delegate via another transformer
  535 + * (eg. an EventTransformer) and the parent transformer already has a ClassNode for the target class.
  536 + *
  537 + * @param name
  538 + * @param transformedName
  539 + * @param basicClass
  540 + * @param classNode
  541 + * @return
  542 + */
388 public ClassNode apply(String name, String transformedName, byte[] basicClass, ClassNode classNode) 543 public ClassNode apply(String name, String transformedName, byte[] basicClass, ClassNode classNode)
389 { 544 {
390 for (Iterator<AccessorInjection> iter = this.accessors.iterator(); iter.hasNext(); ) 545 for (Iterator<AccessorInjection> iter = this.accessors.iterator(); iter.hasNext(); )
@@ -403,10 +558,20 @@ public abstract class AccessorTransformer extends ClassTransformer @@ -403,10 +558,20 @@ public abstract class AccessorTransformer extends ClassTransformer
403 return classNode; 558 return classNode;
404 } 559 }
405 560
  561 + /**
  562 + * Subclasses should add their accessors here
  563 + */
406 protected void addAccessors() 564 protected void addAccessors()
407 { 565 {
408 } 566 }
409 567
  568 + /**
  569 + * Called after transformation is applied, allows custom transforms to be performed by subclasses
  570 + *
  571 + * @param name
  572 + * @param transformedName
  573 + * @param classNode
  574 + */
410 protected void postTransform(String name, String transformedName, ClassNode classNode) 575 protected void postTransform(String name, String transformedName, ClassNode classNode)
411 { 576 {
412 } 577 }