Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #31325 > unrolled thread
| Started by | rupertlssmith@googlemail.com |
|---|---|
| First post | 2015-03-16 05:10 -0700 |
| Last post | 2015-03-17 14:24 +0000 |
| Articles | 4 — 3 participants |
Back to article view | Back to comp.lang.java.programmer
Dynamic proxy causes downstream code to not find annotations. How to solve? rupertlssmith@googlemail.com - 2015-03-16 05:10 -0700
Re: Dynamic proxy causes downstream code to not find annotations. How to solve? rupertlssmith@googlemail.com - 2015-03-16 07:44 -0700
Re: Dynamic proxy causes downstream code to not find annotations. How to solve? Robbie Brown <rob@example.com> - 2015-03-16 16:33 +0000
Re: Dynamic proxy causes downstream code to not find annotations. How to solve? Steven Simpson <ss@domain.invalid> - 2015-03-17 14:24 +0000
| From | rupertlssmith@googlemail.com |
|---|---|
| Date | 2015-03-16 05:10 -0700 |
| Subject | Dynamic proxy causes downstream code to not find annotations. How to solve? |
| Message-ID | <9a31318b-4de7-42cb-9d29-202a973ae557@googlegroups.com> |
Hi,
Consider this class:
class MyClass {
@MyAnnotation
public void myMethod() { ... }
}
Which is coerced to this interface:
interface SomeIterface {
public void myMethod() { ... }
}
If downstream code is looking for "MyAnnotation" it will not find it when using a dynamic proxy.
Here is a "default" dynamic proxy, which effectively does nothing except to call the method and report its exceptions as normal:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(obj, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
The problem is that when invoke is called the Method passed to it is the one from the interface, not the object, so it is SomeInterface.myMethod(), which does not have any annotations.
What I want is to try to match the method on the actual object being proxied, or perhaps some specific interface that I have identified, and effectively "lift" the actual method being invoked, to being that one.
I am running into this problem because I am using the client proxy from Jersey, which uses a dynamic proxy to create a REST client for me, given an HTTP endpoint and an interface. The problem is that when you call it, it checks that there is a @Path annotation on the method being called, and in this case that method is on a different interface, and it fails to find the annotation. So I need to make sure that I call it with the method from the correct interface.
Any suggestions? A problem you have run into before? Thanks for your thoughts.
Rupert
[toc] | [next] | [standalone]
| From | rupertlssmith@googlemail.com |
|---|---|
| Date | 2015-03-16 07:44 -0700 |
| Message-ID | <4f429c73-7025-44e2-aadb-f971fbeba006@googlegroups.com> |
| In reply to | #31325 |
On Monday, March 16, 2015 at 12:10:53 PM UTC, rupert...@googlemail.com wrote:
> Hi,
>
> Consider this class:
>
> class MyClass {
> @MyAnnotation
> public void myMethod() { ... }
> }
>
> Which is coerced to this interface:
>
> interface SomeIterface {
> public void myMethod() { ... }
> }
>
> If downstream code is looking for "MyAnnotation" it will not find it when using a dynamic proxy.
>
> Here is a "default" dynamic proxy, which effectively does nothing except to call the method and report its exceptions as normal:
>
> public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
> try {
> return method.invoke(obj, args);
> } catch (InvocationTargetException e) {
> throw e.getCause();
> }
> }
>
> The problem is that when invoke is called the Method passed to it is the one from the interface, not the object, so it is SomeInterface.myMethod(), which does not have any annotations.
>
> What I want is to try to match the method on the actual object being proxied, or perhaps some specific interface that I have identified, and effectively "lift" the actual method being invoked, to being that one.
>
> I am running into this problem because I am using the client proxy from Jersey, which uses a dynamic proxy to create a REST client for me, given an HTTP endpoint and an interface. The problem is that when you call it, it checks that there is a @Path annotation on the method being called, and in this case that method is on a different interface, and it fails to find the annotation. So I need to make sure that I call it with the method from the correct interface.
>
> Any suggestions? A problem you have run into before? Thanks for your thoughts.
>
> Rupert
Looking into this some more, I ran this code:
public class QuickTest {
public static void main(String[] args) {
for (Method method : Test.class.getMethods()) {
System.out.println(method);
}
}
}
class Test implements ITest<Integer> {
public Integer someMethod() {
return 1;
}
}
interface ITest<T> {
T someMethod();
}
And got this output:
public java.lang.Integer org.mygovscot.stars.client.Test.someMethod()
public java.lang.Object org.mygovscot.stars.client.Test.someMethod()
(... other methods on Object)
This is actually the problem in my code. The dynamic proxy gets the method with types erased, which corresponds to the one on the interface, so it fails to see the annotations.
I am surprised, because I thought that type erasure would mean that there would only be one method at run time, not two.
Is there some way to ensure the dynamic proxy picks up the right method?
Rupert
[toc] | [prev] | [next] | [standalone]
| From | Robbie Brown <rob@example.com> |
|---|---|
| Date | 2015-03-16 16:33 +0000 |
| Message-ID | <me70ir$gjq$1@dont-email.me> |
| In reply to | #31326 |
On 16/03/15 14:44, rupertlssmith@googlemail.com wrote:
> On Monday, March 16, 2015 at 12:10:53 PM UTC, rupert...@googlemail.com wrote:
>> Hi,
>>
>> Consider this class:
>>
>> class MyClass {
>> @MyAnnotation
>> public void myMethod() { ... }
>> }
>>
>> Which is coerced to this interface:
>>
>> interface SomeIterface {
>> public void myMethod() { ... }
>> }
>>
>> If downstream code is looking for "MyAnnotation" it will not find it when using a dynamic proxy.
>>
>> Here is a "default" dynamic proxy, which effectively does nothing except to call the method and report its exceptions as normal:
>>
>> public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
>> try {
>> return method.invoke(obj, args);
>> } catch (InvocationTargetException e) {
>> throw e.getCause();
>> }
>> }
>>
>> The problem is that when invoke is called the Method passed to it is the one from the interface, not the object, so it is SomeInterface.myMethod(), which does not have any annotations.
>>
>> What I want is to try to match the method on the actual object being proxied, or perhaps some specific interface that I have identified, and effectively "lift" the actual method being invoked, to being that one.
>>
>> I am running into this problem because I am using the client proxy from Jersey, which uses a dynamic proxy to create a REST client for me, given an HTTP endpoint and an interface. The problem is that when you call it, it checks that there is a @Path annotation on the method being called, and in this case that method is on a different interface, and it fails to find the annotation. So I need to make sure that I call it with the method from the correct interface.
>>
>> Any suggestions? A problem you have run into before? Thanks for your thoughts.
>>
>> Rupert
>
> Looking into this some more, I ran this code:
>
> public class QuickTest {
> public static void main(String[] args) {
> for (Method method : Test.class.getMethods()) {
> System.out.println(method);
> }
> }
> }
>
> class Test implements ITest<Integer> {
> public Integer someMethod() {
> return 1;
> }
> }
>
> interface ITest<T> {
> T someMethod();
> }
>
> And got this output:
>
> public java.lang.Integer org.mygovscot.stars.client.Test.someMethod()
> public java.lang.Object org.mygovscot.stars.client.Test.someMethod()
> (... other methods on Object)
>
> This is actually the problem in my code. The dynamic proxy gets the method with types erased, which corresponds to the one on the interface, so it fails to see the annotations.
>
> I am surprised, because I thought that type erasure would mean that there would only be one method at run time, not two.
>
> Is there some way to ensure the dynamic proxy picks up the right method?
>
> Rupert
Isn't type erasure more to do with replacing type parameters with
'ordinary classes' at compile time to support generics?
In fact you can see this in action by virtue of the fact that the
interface method has a return type of Object
Why do you think type erasure would 'hide' a method from the hierarchy?
In fact AIUI there needs to be two methods 'visible' to the VM as it is
not possible to determine at compile time which one will be used at
runtime, hence 'runtime', or 'dynamic' binding.
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Or maybe I'm missing something.
--
Not floundering ... just fishing
[toc] | [prev] | [next] | [standalone]
| From | Steven Simpson <ss@domain.invalid> |
|---|---|
| Date | 2015-03-17 14:24 +0000 |
| Message-ID | <o1qltb-jt8.ln1@s.simpson148.btinternet.com> |
| In reply to | #31326 |
On 16/03/15 14:44, rupertlssmith@googlemail.com wrote:
> class Test implements ITest<Integer> {
> public Integer someMethod() {
> return 1;
> }
> }
>
> interface ITest<T> {
> T someMethod();
> }
>
> And got this output:
>
> public java.lang.Integer org.mygovscot.stars.client.Test.someMethod()
> public java.lang.Object org.mygovscot.stars.client.Test.someMethod()
> (... other methods on Object)
(I'm confused about your problem now, because I thought you didn't have
anything explicitly implementing your interface...)
In the invocation handler, can you not look up the method on your target
object? The simple way would be:
obj.getClass().getMethod(method.getName(), method.getParameterTypes())
However, it might not find a method if your interface declares:
void myMethod(String s);
...while the class declares:
void myMethod(T s); // in MyClass<T>
...and the instance is a MyClass<String>.
So, more generally, can you do your own look-up along these lines?:
private static Method findMethod(Class<?> clazz,
String name, Class<?>[] types)
throws NoSuchMethodException {
next_method:
for (Method meth : clazz.getMethods()) {
if (!meth.getName().equals(name)) continue;
if (meth.getParameterCount() != types.length) continue;
Class<?>[] params = meth.getParameterTypes();
for (int i = 0; i < types.length; i++) {
if (!params[i].isAssignableFrom(types[i]))
continue next_method;
}
return meth;
}
throw new NoSuchMethodException();
}
--
ss at comp dot lancs dot ac dot uk
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.java.programmer
csiph-web