0

I am running the keycloak Photoz example. When I deploy to Wildfly, the EntityManager is not injected and I get a NullPointerException (below). I've tried a few different strategies -- tweaking persistence.xml (remove LOCAL_RESOURCE) and switching to the @PersistenceContext attribute without luck. Since the examples are canned, one would think I can't be too far off?? I don't really understand Java well enough to debug this. This would seem to have something to do with my Wildfly installation? But the example is designed to run in wildfly (mvn clean package wildfly:deploy). Any advice?

Note: I am able to manually create the EntityManager as shown below. Also note, that I must call init(), so something seems to be wrong with DI in this app in general...

Resources r = new Resources();
r.init();
EntityManager entityManager = r.createEntityManager();

Stack trace:

Caused by: java.lang.NullPointerException
keycloak_1    |     at org.keycloak.example.photoz.album.AlbumService.findAll(AlbumService.java:86)
keycloak_1    |     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
keycloak_1    |     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
keycloak_1    |     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
keycloak_1    |     at java.lang.reflect.Method.invoke(Method.java:498)
keycloak_1    |     at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139)
keycloak_1    |     at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:295)
keycloak_1    |     at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:249)
keycloak_1    |     at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:236)
keycloak_1    |     at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:395)

Service:

...
@Path("/album")
@Transaction
public class AlbumService {

    public static final String SCOPE_ALBUM_VIEW = "urn:photoz.com:scopes:album:view";
    public static final String SCOPE_ALBUM_DELETE = "urn:photoz.com:scopes:album:delete";

    @Inject
    private EntityManager entityManager;
...

    @GET
    @Produces("application/json")
    public Response findAll() {
        return Response.ok(this.entityManager.createQuery("from Album where userId = '" + request.getUserPrincipal().getName() + "'").getResultList()).build();
    }

...

.../src/main/resources/META-INF/beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <interceptors>
        <class>org.keycloak.example.photoz.util.TransactionInterceptor</class>
    </interceptors>
</beans>

.../src/main/resources/META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <class>org.keycloak.example.photoz.entity.Album</class>
        <class>org.keycloak.example.photoz.entity.Photo</class>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
            <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
            <property name="hibernate.connection.url" value="jdbc:h2:~/keycloak-photoz-example" />
            <property name="hibernate.connection.user" value="sa" />
            <property name="hibernate.flushMode" value="FLUSH_AUTO" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="false" />
        </properties>
    </persistence-unit>
</persistence>

.../src/main/java/org/keycloak/example/photoz/util/TransactionInterceptor.java

@Interceptor
@Transaction
public class TransactionInterceptor {

    @Inject
    private Instance<EntityManager> entityManager;

    @AroundInvoke
    public Object aroundInvoke(InvocationContext context) {
        EntityManager entityManager = this.entityManager.get();
        EntityTransaction transaction = entityManager.getTransaction();

        try {
            transaction.begin();
            Object proceed = context.proceed();
            transaction.commit();
            return proceed;
        } catch (Exception cause) {
            if (transaction != null && transaction.isActive()) {
                transaction.rollback();
            }
            throw new RuntimeException(cause);
        } finally {
            entityManager.close();
        }
    }
}

.../src/main/java/org/keycloak/example/photoz/util/Resources.java

@ApplicationScoped
public class Resources {

    private EntityManagerFactory entityManagerFactory;

    @PostConstruct
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory("primary");
    }

    @PreDestroy
    public void dispose() {
        entityManagerFactory.close();
    }

    @RequestScoped
    @Produces
    public EntityManager createEntityManager() {
        return entityManagerFactory.createEntityManager();
    }
}
Brett
  • 8,575
  • 5
  • 38
  • 51
  • Is your AlbumService a bean? Cause I don't see a bean annotation – David Maes Apr 03 '18 at 13:20
  • @DavidMaes I'm embarrassed to say I don't know how to answer that question. :( – Brett Apr 03 '18 at 13:21
  • Ok so to use the "@Inject", your AlbumService needs to be a Spring Bean I assume in this case? So place the annotation "@Named" above the AlbumService class. Otherwise the injection of the entityManager won't work. Are you using Spring? – David Maes Apr 03 '18 at 13:25
  • @DavidMaes I added the TransactionInterceptor above. I suspect this is part of the story as well. Note that the complete source is available in the Github link in the first para. https://github.com/keycloak/keycloak/tree/3.1.0.Final/examples/authz/photoz – Brett Apr 03 '18 at 13:25
  • The interceptor hooks into the jboss application server. So for every transaction it will first go to keycloak to check if the user is logged in I assume. Inside the TransactionInterceptor the entitymanager is wired correctly because the TransactionInterceptor is bean. However the exception states a nullPointer is thrown in the AlbumService which I assume is not a bean as I can't see any configuration that specifies that should be a bean. – David Maes Apr 03 '18 at 13:30
  • Adding the @Named attribute above AlbumService did not resolve the problem. – Brett Apr 03 '18 at 13:30
  • See the "note" above. If I add the following code to the service call, I can force creation of the EntityManager: `Resources r = new Resources();` `r.init();` `EntityManager entityManager = r.createEntityManager();` – Brett Apr 03 '18 at 13:44
  • Ok if that works for you. But looking inside the repository I would think everything should work out of the box. Honestly I can't figure out how the EntityManager should be injected in the AlbumService. And I assume that even if you create the entityManager manually in the AlbumService. You will run into the same problems in the other services? – David Maes Apr 03 '18 at 13:57
  • I didn't mean to suggest that awful workaround as a strategy! Just in the interest of not sitting on my thumbs -- potentially offering modestly helpful info... :( – Brett Apr 03 '18 at 14:01
  • 1
    I'm sorry, I don't think that I can help you :/. It might be preferable to contact a developer through the github page. – David Maes Apr 03 '18 at 14:11
  • No worries. Appreciate the effort! – Brett Apr 03 '18 at 14:13
  • I don't know this example, but a few things I noticed that look strange: a) no Password for your h2 Connection, try 'sa' b) @ Transaction? shouldn't it be @ Transactional in JEE? c) shouldn't it be @ PersistenceContest to inject the EntityManager? d) I think the code in this example is pretty strange, you shouldn't start JEE with writing a Transaction Interceptor! – EasterBunnyBugSmasher Apr 04 '18 at 12:50
  • Question: you copy the `RESOURCE_LOCAL` example from _keycloak_ but as you are running on Wildfly, can you consider switching to [`JTA`](https://stackoverflow.com/a/28998110/4906586)? And agreed on @EasterBunnyBugSmasher a): password is missing and I'm also not a fan of Transaction Interceptor neither – Al-un Apr 24 '18 at 03:32
  • thats because you trying to recreate the EntityManagerFactory which already created in Init. Just change your createEntityManager methode to simple getEntityManager. – mtz1406 Jan 08 '22 at 22:21

0 Answers0