How can I find all singletons on Guice which implement a specific type? - singleton

Imagine I have a type Disposable which some classes implement:
class FactoryImpl implements Disposable {}
I can bind this class as a singleton:
bind(Factory.class)
.to(FactoryImpl.class)
.in(Singleton.class);
or as an eager singleton:
bind(Factory.class)
.to(FactoryImpl.class)
.asEagerSingleton();
Note that the implementation has the type, not the interface.
How can I find all singletons which Guice has actually created and which implement the type Disposable?
Note that I don't want to blindly call get() in the provider to avoid to create stuff which I don't need (especially since I'm destroying singletons, so creating new ones might cause problems).
This is the opposite of questions like How can I get all singleton instances from a Guice Injector? which only work then the interface contains the keys that you need.
[EDIT] This is how far I got. Is this code correct?
First, I need my interface.
public interface Disposable {
public void dispose();
}
The magic happens here:
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.beust.jcommander.internal.Lists;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
import com.google.inject.util.Modules;
/** Support for disposable beans. */
#Singleton
public class DisposableListener implements InjectionListener<Object> {
private static final Logger log = LoggerFactory.getLogger(DisposableListener.class);
/** Use this method to create the injector */
public static Module createModule(Module ...modules) {
/* Create a new module with ourself at the start. That way, our listeners will see all bindings. */
List<Module> list = Lists.newArrayList(new DisposingModule());
Collections.addAll(list, modules);
return Modules.combine(list);
}
/** To dispose all disposables, call this method.
*
* <p>Good places to call this is at the end of {#code main()},
* in an destroy listener of a {#link javax.servlet.ServletContext}, or after a test.
*/
public static void dispose(Injector injector) {
injector.getInstance(DisposableListener.class).disposeAll();
}
/** Everything that is disposable */
private List<Disposable> beans = Lists.newArrayList();
private void disposeAll() {
log.debug("Disposing {} beans", beans.size());
for(Disposable bean: beans) {
try {
bean.dispose();
} catch(Exception e) {
log.warn("Error disposing {}", bean, e);
}
}
}
#Override
public void afterInjection(Object injectee) {
if(injectee instanceof Disposable) {
log.debug("Noticed disposable bean {}", injectee);
beans.add((Disposable) injectee);
}
}
/** Module which creates the {#link DisposableListener} for the injector and sets everything up. */
private static class DisposingModule extends AbstractModule {
#Override
protected void configure() {
DisposableListener disposableListener = new DisposableListener();
/* Attach a type listener to Guice which will add disposableListener to all types which extend Disposable */
bindListener(TypeMatchers.subclassesOf(Disposable.class), new TypeListener() {
#Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
Class<?> clazz = type.getRawType();
log.debug("Found disposable: {}", clazz);
encounter.register(disposableListener);
}
});
/* Add the listener instance to the module, so we can get it later */
bind(DisposableListener.class)
.toInstance(disposableListener);
}
}
}
The code wraps the other modules and makes sure the DisposableListener is installed in the injector early on. Then it listens for new instances which are created and collects them in a list.
The code probably should check that these are all singletons but I don't know how to do that.
Here are the unit tests:
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Joiner;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Singleton;
public class DisposableListenerTest {
private static List<String> events = Lists.newArrayList();
#Before
public void clearEvents() {
events.clear();
}
#Test
public void testEagerNoGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestEagerSingleton()));
// No call to getInstance()
DisposableListener.dispose(injector);
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testEagerGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestEagerSingleton()));
Foo inst1 = injector.getInstance(Foo.class);
Foo inst2 = injector.getInstance(Foo.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testLazyNoGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
// No call to getInstance()
DisposableListener.dispose(injector);
assertEvents();
}
#Test
public void testLazyGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
Foo inst1 = injector.getInstance(Foo.class);
Foo inst2 = injector.getInstance(Foo.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testAnnotation() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
FooWithAnnotation inst1 = injector.getInstance(FooWithAnnotation.class);
FooWithAnnotation inst2 = injector.getInstance(FooWithAnnotation.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("FooWithAnnotation created", "FooWithAnnotation disposed");
}
private void assertEvents(String...expectedEvents) {
Joiner joiner = Joiner.on('\n');
String expected = joiner.join(expectedEvents);
String actual = joiner.join(events);
assertEquals(expected, actual);
}
public static class Foo implements Disposable {
public Foo() {
events.add("Foo created");
}
#Override
public void dispose() {
events.add("Foo disposed");
}
}
#Singleton
public static class FooWithAnnotation implements Disposable {
public FooWithAnnotation() {
events.add("FooWithAnnotation created");
}
#Override
public void dispose() {
events.add("FooWithAnnotation disposed");
}
}
public static class TestLazySingleton extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).in(Singleton.class);
}
}
public static class TestEagerSingleton extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).asEagerSingleton();
}
}
// TODO test when bean isn't a singleton
}

Don't re-invent scopes
First off, manually "disposing" of singleton Guice bindings is somewhat putting the cart before the horse. Instead of binding objects as singletons and then needing to regularly clean them up, you should use a more appropriate scope (or define your own) so that these objects have natural life cycles for the duration of time that they're expected to exist, such as for a single request or test.
This is evidenced by the documentation on DisposableListener.dispose():
Good places to call this is at the end of main(), in an destroy listener of a ServletContext, or after a test
None of those are place you should need something like this:
When .main() terminates the JVM will soon terminate too (and presumably your injector will go out of scope) so there's generally no need to do any such cleanup before letting the binary terminate.
Similarly when a ServletContext has been destroyed you're generally just about to terminate the JVM, so just let it exit normally.
In tests you should normally be constructing isolated injectors for each test, thereby avoiding any cross-test pollution. When the test ends the injector and all its bindings goes out of scope, and there should be nothing to clean up.
Manage resources separately from Guice
Of course, you could be creating objects that need to be cleaned up, such as an AutoCloseable instance, but that shouldn't be the responsibility of Guice. Generally the .getInstance() call site that obtains the closeable resource should be responsible for cleaning it up. Alternatively the module(s) could be responsible for creating and managing these resources. Then you construct the injector inside a try-with-resources block that manages the lifecycle of the resources module(s).
If those options aren't sufficient and you really need more powerful life cycle semantics use a proper life cycle framework such as Guava's ServiceManager, rather than co-opting Guice into one.
That said, having objects that require cleanup in Guice is itself generally not a good idea. Consider instead binding a wrapper type that allows the caller to open (and close) resources as needed, rather than binding a long-lived stateful resource object directly.
Prefer explicit bindings over Guice listeners
If you really, really need to collect several unrelated objects bound in a Guice injector, do so explicitly at .configure() time, rather than implicitly via introspection. Using a Multibinder allows your modules to explicitly declare which objects need to be disposed of, by binding them to a Multibinder<Disposable> instance which aggregates them all. Then your cleanup step is simply:
for (Disposable resource : injector.getInstance(new Key<Set<Disposable>>() {}) {
resource.dispose();
}
This avoids the "magic" of a listener that silently comes in and cleans up after you, instead allowing module authors to determine how best to handle the resources they bind, and optionally taking advantage of this cleanup functionality if necessary.

Related

How to define pointcut for class initialization

I'm a newbie to AspectJ, and trying to understand joinpoint model
Now i have class like this
public class Account {
private static Map<String, PaymentMethod> supportedPayments = new HashMap<>();
static {
supportedPayments.add("COD", new CodPaymentMethod());
supportedPayments.add("ATM", new ATMPaymentMethod());
}
}
as i read from AspectJ In Action, there is a way to define pointcut when class is intialization, but i could not find syntax.
Anyone help me?
This one does not work:
#Pointcut("initialization(com.jas.aop.bean.Payment"))
it say
ERROR] Syntax error on token "initialization(com.jas.aop.bean.Payment)", "name pattern" expected
/Users/admin/eclipse-workspace/aop/src/main/java/com/jas/aop/aspect/ClassInitializationAspect.java:9
#Pointcut("initialization(com.jas.aop.bean.Payment)")
Your pointcut has several problems:
There is a missing closing parenthesis ).
initialization intercepts constructors (i.e. object initialisation) rather than static class initialisation, which is not what you want and also would require a constructor pattern, not a class name pattern.
If your aspect does not happen to be in the exact same package as the target class, you must use a fully qualified class name such as my.package.Account in order to make the pointcut match.
By the way, your code snippets are just pseudo code because a hash map does not have an add method, rather a put method. The sample class does not even compile. Don't just invent code when posting questions here. Make life easier for the people trying to help you.
Now here is an MCVE, something I always suggest you to specify in your question in order to help people reproduce your situation. I did it for you this time, this was your free shot. Next time, please do it yourself.
Dependency classes used by the main class:
package de.scrum_master.app;
public interface PaymentMethod {}
package de.scrum_master.app;
public class ATMPaymentMethod implements PaymentMethod {}
package de.scrum_master.app;
public class CodPaymentMethod implements PaymentMethod {}
Target class with driver application:
package de.scrum_master.app;
import java.util.HashMap;
import java.util.Map;
public class Account {
private static Map<String, PaymentMethod> supportedPayments = new HashMap<>();
static {
System.out.println("Static initialiser block");
supportedPayments.put("COD", new CodPaymentMethod());
supportedPayments.put("ATM", new ATMPaymentMethod());
}
public Account() {
System.out.println("Creating account");
}
public void doSomething() {
System.out.println("Doing something");
}
public static void main(String[] args) {
new Account().doSomething();
}
}
Aspect:
The aspect shows both initialization and staticinitialization in order to show the difference in both syntax and functionality. You can find all of this explained with examples in the AspectJ manual, which I warmly recommend you to read.
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class AccountAspect {
#Before("initialization(de.scrum_master.app.Account.new(..))")
public void interceptObjectInitialisation(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
#Before("staticinitialization(de.scrum_master.app.Account)")
public void interceptClassInitialisation(JoinPoint joinPoint) {
System.out.println(joinPoint);
}
}
Console log:
staticinitialization(de.scrum_master.app.Account.<clinit>)
Static initialiser block
initialization(de.scrum_master.app.Account())
Creating account
Doing something

Process custom annotation in implementing class of an Resource interface

I am trying to process a custom annotation on a class that implements an external interface that defines a Resource. The setup is the following:
A Resource interface, I can't modify it:
#Path("/v1")
public interface Resource {
#GET
#Path("/foo")
Response foo();
}
An implementation that I can modify:
public class ResourceImpl implements Resource {
#Override
#CustomAnnotation // has Retention.RUNTIME
public Response foo() {
// foo logic
}
}
I've implemented a filter to try and process the #CustomAnnotation on the overriden foo() method:
#Provider
#ServerInterceptor
#Precedence("SECURITY")
public class CustomAnnotationInterceptor implements ContainerRequestFilter {
#Context
ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
// check if the invoked resource method is annotated with #CustomAnnotation and do logic
}
}
However, when I try to get the matched resource class from the ResourceInfo instance, I get the Resource interface, and when I get the matched method, I get the foo() method from the interface which is lacking the #CustomAnnotation. Is there any way around this?
I'm using RESTEasy as an implementation of JAX-RS.
You could implement an interceptor, where you can get hold of the actual resource (method and class) being called. The interceptor should be bound to your annotation using #InterceptorBinding (see 54.2.4 Binding Interceptors to Components).
// Interceptor
#Interceptor
#CustomAnnotation
#Priority(Interceptor.Priority.APPLICATION)
public class CustomAnnotationInterceptor {
#AroundInvoke
public Object interceptCustomAnnotation(InvocationContext ctx) throws Exception {
CustomAnnotation customAnnotation = null;
// The actual method being called
Method method = ctx.getMethod();
if (method != null) {
customAnnotation = method.getAnnotation(CustomAnnotation.class);
}
// ... do stuff with the annotation
return ctx.proceed();
}
}
To get the instance of the class that implements your interface you could use ctx.getMethod().getDeclaringClass() or ctx.getTarget().getClass().getSuperclass().

Verifications involving non-mocked class with mocked abstract parent

A member of my team has written a JMockit-based test method that using a Verifications instance to assert a method was invoked on the UUT, which is not mocked, but extends a mocked abstract parent (it happens to be a Hibernate repository). The test passes, but my opinion, based on the JMockit documentation, is that only mocks should be used in a Verifications instance initializer. I think the result is a false negative but my team member insists it's a valid verification call. The test itself is simple, so I've recreated it using contrived objects:
package com.acme.dataacess;
public abstract class AbstractRepository {
public final T list(Class<T> clazz, final Collection<String> keys) {
.....
}
}
package com.acme.module.dataacess
public class FooRepository extends AbstractRepository<Foo> {
public List<Foo> list() {
return getFoos(null);
}
public List<Foo> list(Collection<String> keys) {
return list(Foo.class, keys);
}
}
public class FooRepositoryTest {
#Tested
private FooRepository uut;
#Mocked
private AbstractRepository mockAbstractRepository;
#Test
public void testFoo1() {
// Execute the test.
this.uut.list(null);
// Verify the results.
new Verifications() {
{
// I don't think this is a valid verification, because the goal
// of the test is to assert a delegated method in a non-mocked
// class was invoked.
uut.list(null);
}
};
}
}
Is this a valid JMockit verification?

Spring AOP - How to get annotation of parent(caller) method

#Before(value="#annotation(com.aspect.Loggable)",argNames="taskId")
public void logEmail(JoinPoint joinPoint) {
System.out.println("#Before is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}
i have a pointCut on method sendEmail() with custom annotation.
This method sendEmail() is called from differnt location in our application .
Like we call sendEmail from paymentApproved () method of paymentManager when payment is approved.
We call sendEmail from taskComplete() method of taskManger when task is completed.
i have to find out the event for which sendEmail is triggered.
I applied custom annotation #EVENT("PAYMENT") on paymentApproved () of paymentManager and #EVENT("TASK") on taskComplete() method of taskManger.
How can i get the value of #EVENT in logEmail(JoinPoint joinPoint) aspect.
Scaffolding:
Sorry, I do not like all-caps class names and I also used my own package names as an example because my template already generates them.
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Loggable {}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Event {
String value();
}
Driver application:
This is pure Java because I am not a Spring user. Just imagine it is one or more #Components.
Please also note that in one case sendEmail() is called from a method not annotated by #Event. This should not trigger the aspect, only the two calls from the annotated methods.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.doSomething();
application.paymentApproved();
application.taskComplete();
}
public void doSomething() {
sendEmail();
}
#Event("paymentApproved")
public void paymentApproved() {
sendEmail();
}
#Event("taskComplete")
public void taskComplete() {
sendEmail();
}
#Loggable
public void sendEmail() {}
}
Aspect:
Your pointcut wants to express: Catch methods annotated with #Loggable within the control flow of methods annotated by #Event. Control flow can be expressed by cflow() or cflowbelow() pointcuts.
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import de.scrum_master.app.Event;
#Aspect
public class LogAspect {
#Before(
"#annotation(de.scrum_master.app.Loggable) &&" +
"execution(* *(..)) &&" + // only needed for AspectJ, not for Spring AOP
"cflow(#annotation(event))"
)
public void logEmail(JoinPoint thisJoinPoint, Event event) {
System.out.println(thisJoinPoint + " -> " + event);
}
}
Console log:
execution(void de.scrum_master.app.Application.sendEmail()) -> #de.scrum_master.app.Event(value=paymentApproved)
execution(void de.scrum_master.app.Application.sendEmail()) -> #de.scrum_master.app.Event(value=taskComplete)
Update: If you were using full AspectJ (e.g. via load-time weaving) instead of Spring AOP, you just could have used a call() pointcut and from there get the enclosing joinpoint's static information. Then the #Event annotation would not have been necessary. But Spring AOP is just "AOP lite" and does not support call().
You can access to the annotation receiving it as a parameter. Something like this:
#Before(value="#annotation(EVENT)",argNames="taskId")
public void logEmail(JoinPoint joinPoint, Event event) {
// do what you need with event. For example, if the field is called value you can do this:
if ("PAYMENT".equals(event.value())) {
// do sth
}
System.out.println("#Before is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}

Resteasy and Google Guice: how to use multiple #ApplicationPath and resource with #Injection?

I created a project to test the dependency injection offered by Google Guice in my Jax-rs resources, using Resteasy.
My intentions are:
Use multiple #ApplicationPath for the versions of my API. In each class annotated with #ApplicationPath I load a set of classes for the specific version.
Each resource have a #Inject (from Google Guice) in his constructor to inject some services.
I created two classes annotated with #ApplicationPath: ApplicationV1RS and ApplicationV2RS. In both I added the same resources classes (UserResource and HelloResource), only for my test.
My Module is configured like this:
public class HelloModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(IGreeterService.class).to(GreeterService.class);
binder.bind(IUserService.class).to(UserService.class);
}
}
When I call http://localhost:9095/v1/hello/world or http://localhost:9095/v2/hello/world, I receive the same error:
java.lang.RuntimeException: RESTEASY003190: Could not find constructor
for class: org.jboss.resteasy.examples.guice.hello.HelloResource
Well, as I expected, this not works. The Google Guice is not "smart" to instantiate the resource classes using the construtor for me.
But I can't find a way to work. To be really honest, I'm really confuse about how the Google Guice, Jetty and Resteasy play with each other in this scenario.
If I abandon the idea of use #ApplicationPath, my resources work with Google Guice configuring my HelloModule like this:
public class HelloModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(HelloResource.class);
binder.bind(IGreeterService.class).to(GreeterService.class);
binder.bind(UserResource.class);
binder.bind(IUserService.class).to(UserService.class);
}
}
But in this case, I'm passing the control to register my resources (HelloResource and UserResource) to Guice. It's not flexible for me, I can't setup my multiple #ApplicationPath.
So, what I'm missing or not understanding?
I created a project with the problemetic code. Is very easy to setup and test: https://github.com/dherik/resteasy-guice-hello/tree/so-question/README.md
Thanks!
When you have getClasses method in your Application then it tries to create instance for all the registered resources using the default constructor which is missing in our Resources class. One way is to create a default constructor and Inject the dependencies through setter Injection.
And then instead of overriding getClasses in ApplicationV1RS and ApplicationV2RS you override getSingletons. Since Resources can be Singleton.
Below are the changes that I made to make it work the way you want.
ApplicationV1RS.java
#ApplicationPath("v1")
public class ApplicationV1RS extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV1RS(#Context ServletContext servletContext) {
}
#Override
public Set<Object> getSingletons() {
Injector injector = Guice.createInjector(new HelloModule());
HelloResource helloResource = injector.getInstance(HelloResource.class);
UserResource userResource = injector.getInstance(UserResource.class);
singletons.add(helloResource);
singletons.add(userResource);
return singletons;
}
}
ApplicationV2RS.java
#ApplicationPath("v2")
public class ApplicationV2RS extends Application {
private Set<Object> singletons = new HashSet<Object>();
public ApplicationV2RS(#Context ServletContext servletContext) {
}
#Override
public Set<Object> getSingletons() {
Injector injector = Guice.createInjector(new HelloModule());
HelloResource helloResource = injector.getInstance(HelloResource.class);
UserResource userResource = injector.getInstance(UserResource.class);
singletons.add(helloResource);
singletons.add(userResource);
return singletons;
}
}
HelloResource.java
#Path("hello")
public class HelloResource {
#Inject
private IGreeterService greeter;
public HelloResource() {
}
#GET
#Path("{name}")
public String hello(#PathParam("name") final String name) {
return greeter.greet(name);
}
}
UserResource.java
#Path("user")
public class UserResource {
#Inject
private IUserService userService;
public UserResource() {
}
#GET
#Path("{name}")
public String hello(#PathParam("name") final String name) {
return userService.getUser(name);
}
}
Add #Singleton to your Service Classes.
Hope it helps.
I have also pushed the code to forked repo. check it out