Created
August 1, 2013 06:44
-
-
Save rednaxelafx/6128972 to your computer and use it in GitHub Desktop.
Dynamic proxy in Java loses generic type information. Demo with CLHSDB, run on JDK8b99/Mac OS X 10.7.5. This gist is to answer question from https://gist.github.com/kdlan/6128766
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ jps | |
78131 Jps | |
78118 Test | |
$ clhsdb | |
Password: | |
hsdb> verbose true | |
hsdb> attach 78118 | |
Attaching to process 78118, please wait... | |
hsdb> jseval "t = jvm.threads[jvm.threads.length-1]" | |
Thread (address=0x00000007eaa852b8, name=main) | |
hsdb> jseval "f = t.frames[t.frames.length-1]" | |
Frame (method=Test.main(java.lang.String[]), bci=42, line=39) | |
hsdb> jseval "f.locals" | |
{proxyBean=Object 0x00000007eabc9d68, args=Object 0x00000007eabb7d08, rawBean=Object 0x00000007eabb9dd8} | |
hsdb> jseval "sa.objHeap.newOop(any2addr('0x00000007eabc9d68').addOffsetToAsOopHandle(0))" | |
sun.jvm.hotspot.oops.Instance@eabc9d68 | |
hsdb> jseval "p = sa.objHeap.newOop(any2addr('0x00000007eabc9d68').addOffsetToAsOopHandle(0))" | |
sun.jvm.hotspot.oops.Instance@eabc9d68 | |
hsdb> jseval "p.klass.name.asString()" | |
com/sun/proxy/$Proxy0 | |
hsdb> jseval "pk = p.klass" | |
sun.jvm.hotspot.oops.InstanceKlass@0x00000007b9c60a50 | |
hsdb> print 0x00000007b9c60a50 | |
public final class com.sun.proxy.$Proxy0 @0x00000007b9c60a50 | |
Super Class | |
public class java.lang.reflect.Proxy @0x00000007b9c4ad50 | |
Interfaces | |
public abstract interface Test$TestService @0x00000007b9c60240 | |
Fields | |
private static java.lang.reflect.Method m1; (offset = 104) | |
private static java.lang.reflect.Method m0; (offset = 108) | |
private static java.lang.reflect.Method m3; (offset = 112) | |
private static java.lang.reflect.Method m2; (offset = 116) | |
Methods | |
public void <init>(java.lang.reflect.InvocationHandler) @0x0000000104fc3b40; | |
static void <clinit>() @0x0000000104fc4100; | |
public final boolean equals(java.lang.Object) @0x0000000104fc3c30; | |
public final java.lang.String toString() @0x0000000104fc3ef0; | |
public final int hashCode() @0x0000000104fc3d20; | |
public final java.util.List list(java.util.List) @0x0000000104fc3e10; | |
Constant Pool | |
Constant Pool of [public final class com.sun.proxy.$Proxy0 @0x00000007b9c60a50] @0x0000000104fc36a0 | |
hsdb> jseval "b = sa.objHeap.newOop(any2addr('0x00000007eabb9dd8').addOffsetToAsOopHandle(0))" | |
sun.jvm.hotspot.oops.Instance@eabb9dd8 | |
hsdb> jseval "bk = b.klass" | |
sun.jvm.hotspot.oops.InstanceKlass@0x00000007b9c60440 | |
hsdb> print 0x00000007b9c60440 | |
public class Test$TestServiceImpl @0x00000007b9c60440 | |
Super Class | |
public class java.lang.Object @0x00000007b9c00fc0 | |
Interfaces | |
public abstract interface Test$TestService @0x00000007b9c60240 | |
Methods | |
public void <init>() @0x0000000104fc2f20; | |
public java.util.List list(java.util.List) [signature (Ljava.util.List<Ljava.util.Map<Ljava.lang.String;Ljava.lang.Object;>;>;)Ljava.util.List<Ljava.util.Map<Ljava.lang.String;Ljava.lang.Object;>;>;] @0x0000000104fc3040; | |
Constant Pool | |
Constant Pool of [public class Test$TestServiceImpl @0x00000007b9c60440] @0x0000000104fc2d20 | |
hsdb> print 0x0000000104fc3e10 | |
public final java.util.List list(java.util.List) @0x0000000104fc3e10 | |
Holder Class | |
public final class com.sun.proxy.$Proxy0 @0x00000007b9c60a50 | |
Bytecode | |
bci bytecode | |
0 aload_0 | |
1 getfield #16 [Field java.lang.reflect.InvocationHandler h] of public class java.lang.reflect.Proxy @0x00000007b9c4ad50 | |
4 aload_0 | |
5 getstatic #60 [Field java.lang.reflect.Method m3] of public final class com.sun.proxy.$Proxy0 @0x00000007b9c60a50 | |
8 iconst_1 | |
9 anewarray #22 [Class java.lang.Object] | |
12 dup | |
13 iconst_0 | |
14 aload_1 | |
15 aastore | |
16 invokeinterface #28 [Method java.lang.Object invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])] | |
21 checkcast #62 [Class java.util.List] | |
24 areturn | |
25 athrow | |
26 astore_2 | |
27 new #42 [Class java.lang.reflect.UndeclaredThrowableException] | |
30 dup | |
31 aload_2 | |
32 invokespecial #45 [Method void <init>(java.lang.Throwable)] | |
35 athrow | |
Exception Table | |
start bci end bci handler bci catch type | |
0 25 25 java.lang.Error | |
0 25 25 java.lang.RuntimeException | |
0 25 26 java.lang.Throwable | |
Constant Pool | |
Constant Pool of [public final class com.sun.proxy.$Proxy0 @0x00000007b9c60a50] @0x0000000104fc36a0 | |
hsdb> print 0x0000000104fc3040 | |
public java.util.List list(java.util.List) [signature (Ljava.util.List<Ljava.util.Map<Ljava.lang.String;Ljava.lang.Object;>;>;)Ljava.util.List<Ljava.util.Map<Ljava.lang.String;Ljava.lang.Object;>;>;] @0x0000000104fc3040 | |
Holder Class | |
public class Test$TestServiceImpl @0x00000007b9c60440 | |
Bytecode | |
line bci bytecode | |
16 0 aload_1 | |
16 1 areturn | |
Constant Pool | |
Constant Pool of [public class Test$TestServiceImpl @0x00000007b9c60440] @0x0000000104fc2d20 | |
hsdb> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Proxy; | |
import java.lang.reflect.Type; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.Map; | |
public class Test { | |
public interface TestService{ | |
List<Map<String,Object>> list(List<Map<String,Object>> list); | |
} | |
public static class TestServiceImpl implements TestService { | |
public List<Map<String, Object>> list(List<Map<String, Object>> list) { | |
return list; | |
} | |
} | |
public static TestService proxy(TestService bean) { | |
return (TestService) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{TestService.class}, new InvocationHandler() { | |
public Object invoke(Object proxy, Method method, Object[] args) | |
throws Throwable { | |
return null; | |
} | |
}); | |
} | |
static Type[] getGenericTypeParams(TestService bean) throws Exception{ | |
Class<?> clazz = bean.getClass(); | |
return clazz.getDeclaredMethod("list", List.class).getGenericParameterTypes(); | |
} | |
public static void main(String[] args) throws Exception { | |
TestService rawBean = new TestServiceImpl(); | |
TestService proxyBean = proxy(rawBean); | |
System.out.println(Arrays.toString(getGenericTypeParams(rawBean))); | |
System.out.println(Arrays.toString(getGenericTypeParams(proxyBean))); | |
System.in.read(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment