I would like to inject an object which implements AutoClosable to a jersey resource and have it automatically closed by the framework at the end of the request.
Basically this is a database connection provider and open connections should be closed at the end of the request.
When using the @inject
annotation the object is not closed.
Is this possible, and how?
You can use the CloseableService
The service may be used within the scope of a request to add instances of
Closeable
that are to be closed when the request goes out of scope, more specifically after the request has been processed and the response has been returned.
You can inject this service into a Factory
where you can create your your provider. Just add the provider to the CloseableService
inside the Factory
, and it will be closed at the end of the request.
public class ConnectionProviderFactory implements Factory<ConnectionProvider> {
@Inject
private CloseableService closeableService;
@Override
public ConnectionProvider provider() {
ConnectionProvider provider = new ConnectionProvider();
closeableService.add(provider);
return provider;
}
@Override
public void dispose(ConnectionProvider provider) {
}
}
Then just register the factory in your binder
bindFactory(ConnectionProviderFactory.class)
.to(ConnectionProvider.class)
.in(RequestScoped.class);
Note that the Factory
class has a dispose
method. I am not 100 percent sure on the details of how it works, as I have had experiences where sometimes it is called, and sometimes it isn't. I've found the CloseableService
to be more reliable. Maybe one of these days I'll go digging around to try and solve the mystery of the dispose
method for myself.
Not quite sure what you're doing differently, but below is a complete test using Jersey Test Framework. Run it like any other JUnit test. Only difference is instead of AutoCloseable
, I use Closeable
import java.io.Closeable;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.CloseableService;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class InjectCloseableTest extends JerseyTest {
public static final String CONNECTION_MSG = "Connection";
public static class ConnectionProvider implements Closeable {
private static final Logger LOGGER
= Logger.getLogger(ConnectionProvider.class.getName());
public String getConnection() {
return CONNECTION_MSG;
}
@Override
public void close() {
LOGGER.info("---- Closing Connection ----");
}
}
@Path("connection")
public static class ConnectionResource {
@Inject
ConnectionProvider connectionProvider;
@GET
public String get() {
return connectionProvider.getConnection();
}
}
public static class ConnectionProviderFactory implements Factory<ConnectionProvider> {
@Inject
CloseableService closeableService;
@Override
public ConnectionProvider provide() {
ConnectionProvider provider = new ConnectionProvider();
closeableService.add(provider);
return provider;
}
@Override
public void dispose(ConnectionProvider t) {}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(ConnectionResource.class)
.register(new LoggingFilter(Logger.getAnonymousLogger(), true))
.register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(ConnectionProviderFactory.class)
.to(ConnectionProvider.class)
.in(RequestScoped.class);
}
});
}
@Test
public void doit() {
Response response = target("connection").request().get();
assertEquals(200, response.getStatus());
assertEquals(CONNECTION_MSG, response.readEntity(String.class));
response.close();
}
}
This is the only dependency you need to run it.
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>