1

I've created a server filter that extends jersey's ContainerRequestFilter, within this custom filter I'd like to inject an (EntityManager) object. To accomplish this I created a factory that implements jersey's hk2.api.Factory and configuration. This setup successfully injects the object into resources, however, it fails to inject the object into the filter.

Does anyone know how to configure jersey to inject objects into filters?

Original Error:

A MultiException has 3 exceptions. They are:

  1. java.lang.IllegalStateException: Not inside a request scope.
  2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of co.example.filters.Filter errors were found
  3. java.lang.IllegalStateException: Unable to perform operation: resolve on co.example.filters.Filter

Error Messages:

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected: MultiException stack 1 of 2 javax.persistence.PersistenceException: [PersistenceUnit: egunit] Unable to build Hibernate SessionFactory at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl. at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120) at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860) at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425) at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849) at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75) at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:54) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39) at co.example.factories.ExampleEntityManagerFactory.(ExampleEntityManagerFactory.java:21)

...

...

...

MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: create on co.example.factories.ExampleEntityManagerFactory at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:395)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471) at org.jvnet.hk2.internal.PerLookupContext.findOrCreate(PerLookupContext.java:69) at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2064) at org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:105) at org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:87) at org.jvnet.hk2.internal.FactoryCreator.create(FactoryCreator.java:117) at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471) at org.glassfish.jersey.process.internal.Reque.findOrCreate(RequestScope.java:162) at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2064) at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:711) at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:661) at org.jvnet.hk2.internal.IterableProviderImpl.get(IterableProviderImpl.java:108) at co.example.filters.Filter.filter(Filter.java:35)

Custom Filter:

@Provider
public class Filter implements ContainerRequestFilter {

@Inject private javax.inject.Provider<EntityManager> entityManagerProvider;

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
    EntityManager entityManager = entityManagerProvider.get();
    EntityDao ed = new EntityDao(entityManager);
    ...
}

Factory:

public class ExampleEntityManagerFactory implements Factory<EntityManager> {
private final CloseableService closeableService;
private final EntityManagerFactory entityManagerFactory;

@Inject
public ExampleEntityManagerFactory(CloseableService closeableService) {
    this.closeableService = closeableService;
    this.entityManagerFactory = Persistence.createEntityManagerFactory("egunit");
}

@Override
public EntityManager provide() {
    final EntityManager instance = entityManagerFactory.createEntityManager();
    //closeableService.add(new Closeable() {            
    //  @Override
    //  public void close() throws IOException {
    //      if (instance.isOpen()) instance.close();
    //  }
    //});
    return instance;
}

@Override
public void dispose(EntityManager instance) {
    if (instance.isOpen()) instance.close();
}

}

Binding:

public class Configuration extends ResourceConfig {
public Configuration() {
...
        register(new AbstractBinder() {         
            @Override
            protected void configure() {
                bindFactory(ExampleEntityManagerFactory.class).to(EntityManager.class).in(RequestScoped.class);
            }
        });     

}
}
Ari
  • 4,121
  • 8
  • 40
  • 56
  • After your edit, is this the same problem (exception) you are getting now, as before making the changes suggested in my answer? – Paul Samsotha Jul 16 '15 at 03:08
  • The pre and post edit exceptions are NOT the same. The pre edit exception(s) is **Not inside a request scope**, while post edit it seems as though the provider is unable to return a proper `EntityManagerFactory` and subsequent `EntityManager` instance. Thoughts/ideas on how to proceed? – Ari Jul 17 '15 at 04:57
  • Have a look at [this post](http://stackoverflow.com/a/28122910/2587435). Might be related. Notice the EMF is not created inside the EM factory, but injected as a singleton. Try and make that change and see what happens. Also instead of creating the EM in the `provide` try and create it in the constructor, also as seen in the post. It seems it's being called in a per lookup, which is a smaller scope than request scoped. Not sure why that's happening. – Paul Samsotha Jul 17 '15 at 05:01

1 Answers1

1

Hard to tell for sure without seeing some code (and verifying), but I'm just going to make an educated guess and say that it's a scoping issue. The EntityManager should be inherently inside a request scope, so I'm guessing that's how you have it set up. So it works fine in your resource class, which I'm guessing is also request scoped (default behavior).

Your ContainerRequestFilter on the other hand, is in a singleton scope. So trying to inject a request scoped EntityManager into the singleton scoped filter is not possible, and you are probably getting the message "Not in a request scope" on startup.

One easy fix is to simply inject javax.inject.Provider<EntityManager>. One of the things it states about the Provider in the javadoc:

Compared to injecting T directly, injecting Provider<T>:

  • abstracting scope so you can look up an instance in a smaller scope from an instance in a containing scope.

So just do

@Provider
public static class Filter implements ContainerRequestFilter {
    
    @Inject
    private javax.inject.Provider<EntityManager> emProvider;

    @Override
    public void filter(ContainerRequestContext request) throws IOException {
        EntityManager em = emProvider.get();
    }
}

Given all else is functional, this should work (as tested). If this is not the problem/solution, please post some code and the complete stack trace.


For anyone interested, here is the complete test, using Jersey Test Framework.

Only Maven dependency required

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.17</version>
    <scope>test</scope>
</dependency>

Test (If you want to see it fail, remove the javax.inject.Provider in the filter, and simple inject EntityManager)

import java.io.IOException;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import junit.framework.Assert;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

public class FilterScopeTest extends JerseyTest {

    public static class EntityManager {

        public String getEntity() {
            return "Some Entity";
        }

        public void close() {
        }
    }

    public static class EntityManagerFactory implements Factory<EntityManager> {

        EntityManager em = new EntityManager();

        public EntityManagerFactory() {
            System.out.println("+++++ EntityManagerFactory Created +++++");
        }

        @Override
        public EntityManager provide() {
            return em;
        }

        @Override
        public void dispose(EntityManager t) {
            em.close();
        }
    }

    public static class Binder extends AbstractBinder {

        @Override
        protected void configure() {
            bindFactory(EntityManagerFactory.class).to(EntityManager.class).in(RequestScoped.class);
        }
    }

    @Provider
    public static class Filter implements ContainerRequestFilter {

        @Inject
        private javax.inject.Provider<EntityManager> em;
        
        public Filter() {
            System.out.println("+++++ Filter Created +++++");
        }

        @Override
        public void filter(ContainerRequestContext request) throws IOException {
            System.out.println("+++++ In filter EM is null: " + (em.get() == null) + " +++++");
            System.out.println("+++++ EM entity value: " + (em.get().getEntity()) + " +++++");
        }
    }

    @Path("em")
    public static class EmResource {

        @Inject
        EntityManager em;

        @GET
        public String getStuff() {
            return em.getEntity();
        }
    }

    @Override
    public Application configure() {
        return new ResourceConfig(EmResource.class, Filter.class).register(new Binder());
    }

    @Test
    public void doIt() {
        Response response = target("em").request().get();
        Assert.assertEquals(200, response.getStatus());
        System.out.println(response.readEntity(String.class));
        response.close();
    }
    
    @Test
    public void doIt2() {
        Response response = target("em").request().get();
        Assert.assertEquals(200, response.getStatus());
        System.out.println(response.readEntity(String.class));
        response.close();
    }
}
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • After making the suggested changes to the custom filter class, when the `get` method of the Provider is executed the Hibernate Session Factory fails to build, which in turns causes the creation of the EntityManagerFactory to fail. Any suggestions/ideas? I've added relevant code and stacktrace to the original post. – Ari Jul 16 '15 at 03:02