{"action":"created","issue":{"url":"https://api.github.com/repos/ryantenney/metrics-spring/issues/90","labels_url":"https://api.github.com/repos/ryantenney/metrics-spring/issues/90/labels{/name}","comments_url":"https://api.github.com/repos/ryantenney/metrics-spring/issues/90/comments","events_url":"https://api.github.com/repos/ryantenney/metrics-spring/issues/90/events","html_url":"https://github.com/ryantenney/metrics-spring/issues/90","id":45115219,"number":90,"title":"Method lookup fails with generic parameter","user":{"login":"ryantenney","id":124015,"avatar_url":"https://avatars.githubusercontent.com/u/124015?v=3","gravatar_id":"","url":"https://api.github.com/users/ryantenney","html_url":"https://github.com/ryantenney","followers_url":"https://api.github.com/users/ryantenney/followers","following_url":"https://api.github.com/users/ryantenney/following{/other_user}","gists_url":"https://api.github.com/users/ryantenney/gists{/gist_id}","starred_url":"https://api.github.com/users/ryantenney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ryantenney/subscriptions","organizations_url":"https://api.github.com/users/ryantenney/orgs","repos_url":"https://api.github.com/users/ryantenney/repos","events_url":"https://api.github.com/users/ryantenney/events{/privacy}","received_events_url":"https://api.github.com/users/ryantenney/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2014-10-07T14:40:03Z","updated_at":"2015-02-19T10:32:53Z","closed_at":null,"body":"Opened via email:\r\n\r\nI’ve got a situation where I have several objects that implement an interface that has a generic type:\r\n\r\n```java\r\npublic interface MyInterface<T> {\r\n   public void processObject(T object);\r\n}\r\n\r\npublic abstract class AbstractObject implements MyInterface<Identifier> {\r\n\r\n}\r\n\r\npublic class ConcreteObject1 extends AbstractObject {\r\n    @Timed(name = \"process-object-1\", absolute = true)\r\n    public void processObject(Identifier identifier) {\r\n        // do some stuff\r\n    }\r\n}\r\n```\r\n\r\nThe problem occurs in the following code in the `com.ryantenney.metrics` package:\r\n\r\n```java\r\n\tpublic Object invoke(MethodInvocation invocation) throws Throwable {\r\n\t\tfinal AnnotationMetricPair<A, M> annotationMetricPair = metrics.get(MethodKey.forMethod(invocation.getMethod()));\r\n\t\tif (annotationMetricPair != null) {\r\n\t\t\treturn invoke(invocation, annotationMetricPair.getMeter(), annotationMetricPair.getAnnotation());\r\n\t\t}\r\n\t\telse {\r\n\t\t\treturn invocation.proceed();\r\n\t\t}\r\n\t}\r\n```\r\n\r\nThe lookup of metrics is failing because the invocation method key is being generated from the interface’s declared method (which has a signature of `public void processObject(Object)` and not the implementation method (which has a signature of `public void processObject(Identifier)`)\r\n\r\nThe offending code is in the interceptor itself:\r\n\r\n```java\r\n\tpublic void doWith(Method method) throws IllegalAccessException {\r\n\t\tfinal A annotation = method.getAnnotation(annotationClass);\r\n\t\tif (annotation != null) {\r\n\t\t\tfinal MethodKey methodKey = MethodKey.forMethod(method);\r\n\t\t\tfinal String metricName = buildMetricName(targetClass, method, annotation);\r\n\t\t\tfinal M metric = buildMetric(metricRegistry, metricName, annotation);\r\n\r\n\t\t\tif (metric != null) {\r\n\t\t\t\tmetrics.put(methodKey, new AnnotationMetricPair<A, M>(annotation, metric));\r\n\r\n\t\t\t\tif (LOG.isDebugEnabled()) {\r\n\t\t\t\t\tLOG.debug(\"Created {} {} for method {}\", metric.getClass().getSimpleName(), metricName, methodKey);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n```\r\n\r\nIt’s iterating the Methods for the actual object that’s being annotated (`ConcreteObject1`) and entering them into the map with those method signatures, so there is a disconnect when the invocation is called via the advice from using a proxy generated from the interface - which uses the method of the invocation, which is the one from the interface (`MyInterface<T>`)."},"comment":{"url":"https://api.github.com/repos/ryantenney/metrics-spring/issues/comments/75030251","html_url":"https://github.com/ryantenney/metrics-spring/issues/90#issuecomment-75030251","issue_url":"https://api.github.com/repos/ryantenney/metrics-spring/issues/90","id":75030251,"user":{"login":"s17t","id":630819,"avatar_url":"https://avatars.githubusercontent.com/u/630819?v=3","gravatar_id":"","url":"https://api.github.com/users/s17t","html_url":"https://github.com/s17t","followers_url":"https://api.github.com/users/s17t/followers","following_url":"https://api.github.com/users/s17t/following{/other_user}","gists_url":"https://api.github.com/users/s17t/gists{/gist_id}","starred_url":"https://api.github.com/users/s17t/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/s17t/subscriptions","organizations_url":"https://api.github.com/users/s17t/orgs","repos_url":"https://api.github.com/users/s17t/repos","events_url":"https://api.github.com/users/s17t/events{/privacy}","received_events_url":"https://api.github.com/users/s17t/received_events","type":"User","site_admin":false},"created_at":"2015-02-19T10:32:53Z","updated_at":"2015-02-19T10:32:53Z","body":"@YoussefArfaoui , please would you provide a full example ? Thank you."}}