try {
bytecode = env.getClassfile(classWrapper.wrapped).getInputStream();
final ClassReader reader = new ClassReader(bytecode);
final ClassVisitor writeClass = new WriteClass();
// we're doing most of this by hand; we only read the original class to hijack signature, ctor exceptions,
// etc.:
reader.accept(new ClassVisitor(Opcodes.ASM4) {
Type supertype;
@Override
public void visit(final int version, final int access, final String name, final String signature,
final String superName, final String[] interfaces) {
supertype = Type.getObjectType(superName);
writeClass.visit(version, Opcodes.ACC_PUBLIC, result, signature, superName, interfaces);
visitAnnotation(Type.getType(Marker.class).getDescriptor(), false);
}
@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
if (INIT.equals(name)) {
final Method staticCtor = new Method(INIT, key.getRight());
final Type[] argumentTypes = staticCtor.getArgumentTypes();
final Type[] exceptionTypes = toObjectTypes(exceptions);
{
final GeneratorAdapter mgen =
new GeneratorAdapter(Opcodes.ACC_PUBLIC, staticCtor, signature, exceptionTypes,
writeClass);
mgen.visitCode();
mgen.loadThis();
for (int i = 0; i < argumentTypes.length; i++) {
mgen.loadArg(i);
}
mgen.invokeConstructor(supertype, staticCtor);
mgen.returnValue();
mgen.endMethod();
}
/*
* now declare a dummy constructor that will match, and discard,
* any originally inner-class bound constructor i.e. that set up a this$0 field.
* By doing this we can avoid playing with the stack that originally
* invoked such a constructor and simply rewrite the method
*/
{
final Method instanceCtor =
new Method(INIT, Type.VOID_TYPE, ArrayUtils.add(argumentTypes, 0, OBJECT_TYPE));
final GeneratorAdapter mgen =
new GeneratorAdapter(Opcodes.ACC_PUBLIC, instanceCtor, signature, exceptionTypes,
writeClass);
mgen.visitCode();
mgen.loadThis();
for (int i = 0; i < argumentTypes.length; i++) {
mgen.loadArg(i + 1);
}
mgen.invokeConstructor(supertype, staticCtor);
mgen.returnValue();
mgen.endMethod();
}
return null;
}
return null;
}
@Override
public void visitEnd() {
writeClass.visitEnd();
}
}, 0);
} finally {
IOUtils.closeQuietly(bytecode);
}