Lightweight JPA transaction management library, based on the dagger-aop project.
dagger-jpa is a library that provides abstractions for working with JPA transactions in a Dagger 2 application. It works in all kind of aplication, Java desktop, server application, Servlet environment, etc.
As it is an extension to dagger-aop, it will generate code at compile time using an annotation-based API.
This project has been inspired by Guice Persist.
Classes that have @Transactional
methods must be abstract and have only one constructor or no constructor.
If you are using Maven, add a dependency:
<!-- Core -->
<dependency>
<groupId>com.github.0x3333.dagger.jpa</groupId>
<artifactId>dagger-jpa-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- This is only necessary on compile time, optional -->
<dependency>
<groupId>com.github.0x3333.dagger.jpa</groupId>
<artifactId>dagger-jpa-compiler</artifactId>
<version>1.0-SNAPSHOT</version>
<optional>true</optional>
</dependency>
Despite adding dagger-jpa as a dependency, you need to include the JpaModule
and InterceptorModule
in your Dagger Component/Module and annotated your methods using @Transactional
annotation. You must bind the JPA Unit Name and the JPA Properties in some of your modules.
Also you need to start the JpaService
before any transactional method is called.
// Adding JpaModule and InterceptorModule
@Component(modules = { MyModule.class, JpaModule.class, InterceptorModule.class })
public interface MyComponent {
DbWork dbWork();
JpaService jpaService();
}
This is a normal module where an interface is binded to an implementation, also we bind the JPA Unit Name and JPA Properties:
@Module
public abstract class MyModule {
@Binds
abstract DbWork providesDbWork(DbWorkImpl impl);
// Here we are bind the Unit Name
@Provides
@Named("jpa.unitname")
static String providesJpaUnitName() {
return "dagger-jpa";
}
// Here we are bind the JPA Properties, in this case, there is none, we return null
@Provides
@Nullable
@Named("jpa.properties")
static Map<?, ?> providesJpaProperties() {
return null;
}
}
In your transactional classes, annotated all methods that need to be transactional with @Transactional
:
// Class must be ABSTRACT
public abstract class DbWorkImpl implements DbWork {
private final JpaWork jpaWork;
public DbWorkImpl(JpaWork jpaWork) {
this.jpaWork = jpaWork;
}
@Override
@Transactional
public void doSomeWork() {
// You can get an EntityManager from JpaService
// jpaWork.getEntityManager().createQuery(....);
}
}
To create your Component you need to install JpaModule
which will require the JPA Unit name.
MyComponent component = DaggerMyComponent.builder().build();
component.jpaService().start();
This is all. The InterceptorModule
will bind DbWorkImpl
to the generated Interceptor_DbWorkImpl
, which is a subclass of DbWorkImpl
. Everytime a DbWork
is requested, a Interceptor_DbWorkImpl
will be returned. This subclass will call the interceptor to manage the transaction for you.
If your class have @Inject
fields, but no constructor with @Inject
, means to Dagger that it can inject those fields when requested but it will not create new instances of this class. This behavour is changed when using dagger-jpa
, because it creates a constructor annotated with @Inject
if none is present. Thus, the instance will be created by Dagger and also members injected. This is not an issue to most people, but something to consider in unusual use cases.
Copyright (C) 2016 Tercio Gaudencio Filho
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.