Closed GoogleCodeExporter closed 9 years ago
package guice;
import static com.google.inject.matcher.Matchers.annotatedWith;
import static com.google.inject.matcher.Matchers.any;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
public class AnnotationTest {
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
}
@ImplementedBy(TotoImpl.class)
interface Toto {
String getBidule();
void setBidule(String bidule);
}
class TotoImpl implements Toto {
private String bidule;
@Inject
public TotoImpl() { }
public String getBidule() {
return bidule;
}
@MyAnno
public void setBidule(String bidule) {
this.bidule = bidule;
}
}
static class MyInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation mi) throws Throwable {
return mi.proceed();
}
}
static class MyModule extends AbstractModule {
public void configure() {
// Comment or uncomment this line to see the problem:
// When this binding is uncomment, bellow main method
// will print 'false' otherwise 'true'
bindInterceptor(any(), annotatedWith(MyAnno.class), new
MyInterceptor());
}
}
public static void main(String[] args) throws Throwable {
Injector injector = Guice.createInjector(new MyModule());
Toto toto = injector.getInstance(Toto.class);
Method setter = toto.getClass().getMethod("setBidule",
new Class[] { String.class });
boolean isPresent = setter.isAnnotationPresent(MyAnno.class);
System.out.println("Present : " + isPresent);
}
}
Original comment by anthony....@gmail.com
on 30 May 2008 at 9:41
I'd like to know more -- is there a particular use case, tool or library that
requires this?
Original comment by limpbizkit
on 3 Jun 2008 at 9:49
As I noted on the mailing list, there's a workaround:
You could use an @Inherited-enabled annotation at the class level, and sneak the
class in like that:
@Retention(RUNTIME)
@Target(TYPE)
@Inherited
public @interface TheType {
Class<?> value();
}
@TheType(TotoImpl.class)
static class TotoImpl implements Toto {
...
}
Method setter =
toto.getClass().getAnnotation(TheType.class).value()
.getMethod("setBidule", new Class[] { String.class });
boolean isPresent = setter.isAnnotationPresent(MyAnno.class);
System.out.println("Present : " + isPresent);
I'm also curious to see what the use case is though.
Original comment by robbie.v...@gmail.com
on 3 Jun 2008 at 5:13
My Use Case is quite simple, I add some annotations in my business classes like
@Property, @GenerateEvent, @Children, @Parent, ... That allows to add extra
information to make usage easier, to perform some tests to print out reports
about
object model structure...
Original comment by anthony....@gmail.com
on 3 Jun 2008 at 7:26
Chris - I'm totally ignorant of cglib's API, so I'll ask you. Would fixing this
require a whole lot of code?
Original comment by limpbizkit
on 4 Jun 2008 at 12:19
It would require code to copy the annotations from the superclass to the
subclass. It
would be a significant effort, and would have to be optional as it is not
backwards-compatible, which means the option would have to be propagated into
the
Guice API somehow, which would be ugly. It is usually easier to just modify your
application code to look "one level up" when dealing with a proxy. It might be
helpful if Guice had a static method that could tell you if an object is from a
proxy
class, or maybe it could just give you back the unproxied class regardless.
Original comment by chris.no...@gmail.com
on 4 Jun 2008 at 12:49
See also issue 101.
Original comment by limpbizkit
on 8 Jun 2008 at 11:28
When integrating to existing frameworks annotation inheritence on the subclass
is
very useful. For example, the swing application framework uses @Action on
methods
that you can bind to a JButton. To make it work with Guice you'll have to
explicitly
pass in the class that contains the actions, in stead of "this" as Chris
suggests.
This works, but it also implicates that you can't just enable some AOP aspect
without
risking to break existing code.
Original comment by botte...@gmail.com
on 29 Jun 2008 at 2:18
FYI, Jersey has a new hook that allows me to pass it the unproxied class, it
then
examines *that* class for Jersey-specific annotations.
Original comment by gili.tza...@gmail.com
on 24 Nov 2008 at 4:19
In my particular use-case I had a problem with Struts2 @SkipValidation action
method
annotation when I used other interceptors... at the time I was convinced that
@SkipValidation wasn't set on the proxy class method.
http://struts.apache.org/2.x/struts2-core/apidocs/org/apache/struts2/interceptor
/validation/SkipValidation.html
Original comment by pavel.jb...@gmail.com
on 24 Nov 2008 at 5:28
I assume this issue also implies that parameter annotations are not copied to
the proxy?
I tried intercepting some service methods that use annotations to define
parameter
names for JSON-RPC clients, but the required annotations were all gone.
Looking "up
a level" doesn't seem like a viable option in this case.
Original comment by roger.go...@gmail.com
on 17 Sep 2009 at 1:31
I've been very frustrated by this shortcoming myself: my team is using
JPA/Hibernate with Guice. To facilitate a "rich domain model" (ie, domain-logic
directly in our entity-classes), I'm using a Hibernate Interceptor to augment
Hibernate's Entity-instantiation, and constructing the entity instances with a
Guice Injector. This enables Guice AOP and injection in our Entity instances:
we can annotate model-methods with @Transactional (a-la warp-persist), and we
can @Inject dependencies into our Entities directly. Sweet!
This works beautifully, EXCEPT that the standard JPA method annotations for
lifecycle-event observers (@PrePersist, @PreUpdate, etc) aren't retained on the
Guice-enhanced entity instances. Surprise! This caused a subtle bug that only
appeared when we added a guice MethodInterceptor to an existing entity class...
Suddenly, our entity-lifecycle callbacks stopped being invoked! Thank goodness
for integration-tests.
I'm currently building a workaround involving a class-level EntityListener that
will look up-the-tree to find and invoke persistence-event annotations, but
this is very cumbersome and, more importantly, doesn't feel like it should be
*my* concern: Guice is constructing my objects and providing "magic" AOP, but
the abstraction is leaking here.
If it's too expensive to perform method-annotation-preservation by default, it
seems appropriate that the framework should at least support it *upon
request*, as a binding configuration..?
Annotation-based tools and functionality continue to become more pervasive; I
anticipate the impact of this subtle failure may become more common and
expensive for guice-enhanced developers. Plz fix.
Original comment by joshgr@gmail.com
on 22 Aug 2010 at 12:44
Original comment by cgruber@google.com
on 16 Jul 2012 at 6:13
I'm facing the very same problem joshgr described and it's really frustrating.
I just add a method annotation and Guice stops "coping" some (others)
annotations to the proxy object. Please, fix it!
Original comment by leitao.o...@gmail.com
on 16 Feb 2014 at 5:50
+1 for this. Appreciate the complexity of copying the annotations to the proxy,
but without it there are a number of unexpected side affects. This is a deal
breaker unfortunately.
Original comment by jameshar...@gmail.com
on 8 Aug 2014 at 7:12
The code.google.com guice project has migrated to GitHub. This issue site is
no longer being used. Please use https://github.com/google/guice/issues/201
instead.
Original comment by sberlin
on 8 Aug 2014 at 11:28
Original issue reported on code.google.com by
anthony....@gmail.com
on 30 May 2008 at 9:41