Search code examples
javahibernatejpajavalin

Using JPA in a Javalin application


I am creating a web application in Java and would like to use the Javalin framework.

Issues/questions:

  • What would be the best way to use JPA (via hibernate) in a Javalin web application?
  • I.e. what is the best way make a JPA EntityManager object available to the Javalin request handlers?

Update: Some more context

I want to use JPA (via Hibernate) in my javalin application. The central concept in JPA is that you use an EntityManager instance to access the database. To create an EntityManager, there is a EntityManagerFactory.

What I currently do is that I create a global EntityManagerFactory and the handlers that use the database call factory.createEntityManager().

While this works, I wonder if there are other recommended apporaches? Coming from a Flask/SQLAlchemy/Python background - on that stack the ORM session (EntityManager equivalent) is typically available as a request-bound object.


Solution

  • I ended up implementing the following:

    • Create an EntityManagerFactory on startup. Create a Javalin instance on startup. Then call enableRequestBoundEntityManager(javalinApp, entityManagerFactory).
    • Whenever a handler needs an EntityManager, use the extension property Context.entityManager.

    I.e.:

    fun main() {
        val app = Javalin.create()
        val emf = createEntityManagerFactorySomehow()
    
        enableRequestBoundEntityManager(app, emf)
    
        app.get("/list/") { ctx -> ctx.json(
            ctx.entityManager.createQuery("select ... from ...").resultList
        ) }
    
        app.start()
    }
    
    /**
     * Adds an `entityManagerFactory` application attribute, and sets up clean up after requests have been handled
     */
    fun enableRequestBoundEntityManager(app: Javalin, entityManagerFactory: EntityManagerFactory) {
        app.attribute("entityManagerFactory", entityManagerFactory)
    
        app.after {
            val entityManager: EntityManager? = it.attribute("entityManager")
            if (entityManager != null) {
                entityManager.close()
            }
        }
    }
    
    /**
     * Returns a JPA entity manager scoped to the Javalin context
     */
    val Context.entityManager: EntityManager
        get() {
            if (this.attribute<EntityManager>("entityManager") == null) {
                this.attribute("entityManager", this.appAttribute<EntityManagerFactory>("entityManagerFactory").createEntityManager())
            }
            return this.attribute("entityManager")!!
        }