All things possible with Java code are possible with bytecode generation.
I'm not that familiar with cglib, but here is some asm code that will do what you asked for.
The only special part related to generics it the genericSig()
method that defines "a second signature" for the superclass besides the rawform Type.getInternalName(Foo.class)
.
This is not an general solution, it creates the bytecode for the example in the question. For the general solution many other things need to be considered, especially bridge methods.
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;
public class GenExtendFoo {
public static void main(String[] args) throws Exception {
ClassWriter cw = new ClassWriter(0);
/** Extend Foo with normal raw superclass "com/Foo"
And generic superclass genericSig() Lcom/Foo<Ljava/lang/Integer;>;
**/
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "SubClass", genericSig(Foo.class, Integer.class),
Type.getInternalName(Foo.class), new String[] {});
createConstructor(cw);
cw.visitEnd();
byte[] b = cw.toByteArray();
Class<?> cls = (Class<?>) new MyClassLoader().defineClass("SubClass", b);
Foo<Integer> instance = (Foo<Integer>) cls.getConstructor(Integer.class).newInstance(1);
System.out.println(instance.getValue());
/* The generic type is available with GenericSuperclass just like in the plain java version */
ParameterizedType para = (ParameterizedType) instance.getClass().getGenericSuperclass();
System.out.println(para.getActualTypeArguments()[0]);
}
private static void createConstructor(ClassWriter cw) {
// Create constructor with one parameter that calls superclass
// constructor with one parameter
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
"(L" + Type.getInternalName(Integer.class) + ";)V", null, null);
mv.visitMaxs(2, 2);
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Foo.class), "<init>",
"(L" + Type.getInternalName(Object.class) + ";)V", false); // call
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
public static String genericSig(Class<?> mainType, Class<?> typeParameter) {
SignatureVisitor sv = new SignatureWriter();
SignatureVisitor psv = sv.visitSuperclass();
psv.visitClassType(Type.getInternalName(mainType));
SignatureVisitor ppsv = psv.visitTypeArgument('=');
ppsv.visitClassType(Type.getInternalName(typeParameter));
ppsv.visitEnd();
psv.visitEnd();
return sv.toString();
}
}
static class MyClassLoader extends ClassLoader {
public Class<?> defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}