folks!
I have two maven modules in my application - domain and persistence.
Domain has a domain object, services and "data provider" interfaces to external endpoints, for example, persistence. Domain contains business logic and has no external dependencies - he know nothing about persistence.
Persistence depends on domain. It implements "data provider" interfaces from domain module. It may be relational db implementation, nosql implementation, file implementation etc.
For example, I have interface PersonRepository in domain, like this:
public interface PersonRepository {
List<Person> findAll();
List<Customer> findByLastName(String lastName);
}
I want to implement data provider interface with Spring Data JPA. I need to write something like that:
public interface PersonRepository extends CrudRepository<Person, Long> {
List<Person> findAll();
List<Person> findByLastName(String lastName);
}
But I don't want to inject spring dependencies to "core domain". I want to stay my domain very lightweight and independent.
Is there way to implement PersonRepository with Spring Data in Persistence module?
Instead of extending the ready-made interfaces by Spring Data you can just copy the methods in your own interface. Normally you would just put a #Repository annotation on it and Spring Data would do its job. But that would reintroduce the dependency.
So what you could do instead is in your Spring Configuration invoke the JpaRepositoryFactory.getRepository yourself. Something like this should work:
#Bean
public PersonRepository(RepositoryFactorySupport factory) {
return factory.getRepository(PersonRepository.class);
}
This will be either in your persistence module or in a third module which does the wiring of all your modules, so the dependencies shouldn't be an issue.
The Spring Data JPA interface can extend multiple interfaces. Something like the following should work.
Defined in your domain module:
public interface PersonRepository {
List<Person> findAll();
List<Customer> findByLastName(String lastName);
}
In your persistence module:
#Reposistory
public interface SpringDataJPAPersonRepository extends CrudRepository<Person, Long>, PersonRepository {
// Any Spring Data JPA specific overrides e.g. #Query
}
Related
I have a spring boot application and connected to Mongo DB.
I know all most all of documents or blogs said the sample code should like this:
#Repository
public interface ProductRepository extends MongoRepository<Product, String> {
}
#Document
public class Product {
private String id;
private String name;
private int price;
}
But I found even if I remove #Repository and #Document annotations. The application still can start without error. Spring still can know ProductRepository is spring bean and also can CRUD Product collection.
So does these not necessary to add #Repository and #Document? Or is there any difference add or not add?
Not necessery.
Spring can found it, because you extends the MongoRepository interface, and add Product as it type.
#Repository is useful anyway, for example if you create a custom repository.
#Document is also, if you want to specify custom property values, for example collection name..
The annotation #Repository registers a class as a Spring bean which makes it autowirable. Spring Data doesn't use annotations but provides functionality through extending reposotory classes such as JpaRepository or MongoRepository.
This question already has answers here:
How are Spring Data repositories actually implemented?
(1 answer)
How does Spring Data JPA work internally
(1 answer)
Closed 3 years ago.
I have a code like this:
Repository
#Repository
public interface EquipmentRepository extends JpaRepository<Equipment, Integer>{
Equipment findById(int id);
}
Service
#Service
public class EquipmentServiceImpl implements EquipmentService {
#Autowired
EquipmentRepository equipmentRepository;
#Override
public Equipment findById(int id) {
return equipmentRepository.findById(id);
}
}
I wonder that why i can call a method of 'interface EquipmentRepository'. EquipmentRepository is a interface, Right ?
Spring Repository is responsible for importing the DAO's into the DI container and also it makes the unchecked exceptions into Spring DataAccessException. The Spring Repository annotation is meta annotated with the #Component annotation so that the repository classes will be taken up for component scanning.
Teams implementing traditional Java EE patterns such as "Data Access
Object" may also apply this stereotype to DAO classes, though care
should be taken to understand the distinction between Data Access
Object and DDD-style repositories before doing so. This annotation is
a general-purpose stereotype and individual teams may narrow their
semantics and use as appropriate.
A class thus annotated is eligible for Spring DataAccessException
translation when used in conjunction with a
PersistenceExceptionTranslationPostProcessor. The annotated class is
also clarified as to its role in the overall application architecture
for the purpose of tooling, aspects, etc.
Source: JavaDoc
but in your case you are also extending the JpaRepository of Spring Data JPA. Spring Data automatically provides implementations of common CRUD operations. The JpaRepository extends the interface CrudRepository which has the methods declared for all basic crud operations.
public interface EquipmentRepository extends JpaRepository<Account, Long> { … }
Defining this interface serves two purposes:
First, by extending JpaRepository we get a bunch of generic CRUD
methods into our type that allows saving Equipments, deleting them and
so on.
Second, this will allow the Spring Data JPA repository infrastructure
to scan the classpath for this interface and create a Spring bean for
it.
The #EnableJpaRepositories scans all packages below com.acme.repositories for interfaces extending JpaRepository and creates a Spring bean for it that is backed by an implementation of SimpleJpaRepository (spring data provides default imlpementations of CRUD repository through this class).
So that is why even when you haven't defined the method , you are able to do crud operations through this setup.
Refer : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories
1 quick question on Spring JPA repositories transactionality.
I have a service that is not marked as transactional and calls Spring JPA repository method
userRegistrationRepository.deleteByEmail(email);
And it is defined as
#Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {
UserRegistration findByEmail(String email);
void deleteByEmail(String email);
}
The problem is that it fails with "No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException" exception.
Ok, I can solve it by marking the service or deleteByEmail(..) method as transactional, but I just can't understand why it crashes now. Spring documentation explicitly states that "CRUD methods on repository instances are transactional by default." (http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions), but apparently this one is not... So Is this statement related to only members of CrudRepository?
ps: that's for Spring Data JPA 1.9.4
You are right. Only CRUD methods (CrudRepository methods) are by default marked as transactional.
If you are using custom query methods you should explicitly mark it with #Transactional annotation.
#Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {
UserRegistration findByEmail(String email);
#Transactional
void deleteByEmail(String email);
}
You should also be aware about consequences of marking repository interface methods instead of service methods. If you are using default transaction propagation configuration (Propagation.REQUIRED) then:
The transaction configuration at the repositories will be neglected
then as the outer transaction configuration determines the actual one
used.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
If you want more information about how it is implemented, take a look at default CrudRepository / JpaRepository implementation - SimpleJpaRepository (which you are probably using):
https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java
The interesting lines are here:
#Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
and some of transactional methods here:
#Transactional
public void deleteById(ID id) {
#Transactional
public <S extends T> S save(S entity) {
I'm about to create a stock-standard rest CRUD api and have taken note of the handy CrudRepository class given in the spring-data framework. I'm planning on also using spring to declare #RequestMappings to hook up the default crud operations to their URL counterparts (e.g. /customer/{id} --> CrudRepository.findOne({id}), etc).
Is there a spring utility class to acheive this or will i need to roll my own?
Ah ha! What I'm looking for is a org.springframework.data.rest.core.annotation.RepositoryRestResource located in the spring data rest webmvc project. maven co-ordinates: "org.springframework.data:spring-data-rest-webmvc"
an example extract from the documentation:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
}
enter code here
This repository is an interface and will allow you to perform various operations involving Person objects. It gets these operations by > extending the PagingAndSortingRepositry interface defined in Spring Data Commons.
At runtime, Spring Data REST will create an implementation of this interface automatically. Then it will use the #RepositoryRestResource > annotation to direct Spring MVC to create RESTful endpoints at /people.
I need an advice w.r.t. one of the design approach we are considering.
We are implementing a Java web service provider which acts on data in relational database. Our propose classes are:
IDAO - interface with execute() method
GetCustomerDAO and UpdateCustomerDAO implements IDAO
DAOFactory - List of DAO to be reads configuration file which has a mapping of DAOs to be invoked for a particular service.
ServiceImpl - contains getCustomer, updateCustomer methods. The service uses DAOFactory to get list of DAO objects and it then iterates over the list and calls DAO.execute method.
I think it's more of like we have converted DAOs in to Command. However, I don't quite like this approach for some reasons:
- In ServiceImpl : you can't influence the flow of DAOs being called. For e.g. after execution of 1st DAO if I don't want to execute 2nd DAO but execute 3rd DAO, it's hard to have this implemented.
- besides not sure if we can conceptually use DAO. because a Command object can have business logic, however DAOs should only deal with aspects of reading and writing data to db.
Please let me know your views whether the design looks appropriate. thanks
I don't see the benefit of using the Command design pattern in this case.
1. The idea with DAO, is to provide an interface that abstract a persistence mechanism. This interface traditionally defines CRUD methods. Each DAO concrete class, would typically implement the DAO interface, for a specific persistence mechanism.For instance, you could have one implementation that stores data into a relational database and another that stores data into an xml file. Both these implementation can be interchangeable since they implement the same inteface.
2. The service functionality can be separated into a separate service layer. Normally, this layer has a dependency on your DAO layer(for persistence). The service interface can be similar to a façade that exposes the business logic implemented in the application (typically, logic in the business layer) to potential clients. Example:
User DAO interface:
public interface UserDao {
void save(User user);
void delete(User user);
void update(User user);
User findByUsername(String username);
List findAll();
...
}
User Service interface:
public interface UserService {
void createUser(String username, String password);
boolean loginUser(String username, String password);
boolean isUsernameUnique(String username);
....
}
Service implementation:
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao){
this.userDao = userDao;
}
...
}