Skip to content

Instantly share code, notes, and snippets.

@odrotbohm
Created July 19, 2012 07:49
Show Gist options
  • Save odrotbohm/3141439 to your computer and use it in GitHub Desktop.
Save odrotbohm/3141439 to your computer and use it in GitHub Desktop.
Proposal: Allow EntityManager(Factory) to be injected through a constructor.

When designing application components it's best practice to inject mandatory dependencies though the constructor and essentially make the application component immutable like this:

@Named
class MyComponent implements Component {

  private final Dependency dependency;

  @Inject
  public MyComponent(Dependency dependency) {
    Assert.notNull(dependency, "Dependency must not be null!");
    this.dependency = dependency;
  }

  public void myBusinessMethod() {
    dependency.someOtherMethod();
  }
}

This has the advantage that MyComponent exposes its dependencies and in turn a large number of constructor arguments act as code smell to indicate the class is having to many responsibilities. Beyond that the class cannot be instantiated in an invalid state which is important. Once we get an instance of the class we can safely call methods on it without running into NullPointerExceptions or essentially having to guard every access to the dependencies with a null-check which makes the code tedious to read and scattered with non-business concerns.

When using JPA you essentially have to break with this design approach as you cannot get the EntityManager(Factory) injected into it (@Targeton @Persistence(Context|Unit) not listing PARAMETER). This results in the following code:

@Named
class MyComponent implements Component {

  private final Dependency dependency;

  @PersistenceContext
  private EntityManager em;

  @Inject
  public MyComponent(Dependency dependency) {
    Assert.notNull(dependency, "Dependency must not be null!");
    this.dependency = dependency;
  }

  public void myBusinessMethod() {
    dependency.someOtherMethod();

    Query query = em.createQuery(…);
  }
}

Essentially you now can add another constructor to be able to at least inject the EntityManager manually in a unit test case or rely on the class only being used in a container context. Still, the consistency in the design (mandatory dependencies into constructor-args, null-checked, into final fields) is gone.

Thus I propose to allow EntityManager(Factory) instances to be injected through @Inject and @Persistence(Unit|Context) to be usable with constructor parameters if further configuration is needed.

@daniel-shuy
Copy link

+1
I can't believe its been 5 years and this is still not possible. Sometimes I really hate Java...

@shawnjohnson
Copy link

I saw some tickets related to this, especially DATAJPA-445, but I'm not sure if/how this is possible?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment