Separating repository and implementation in Spring-Data - spring

Given some abstract entity:
public interface Person{
long getID();
String getFirstName();
String getLastName();
}
And repository to work with this entity:
public interface PersonRepository {
void save(Person person);
Person findOne(long id);
}
I want to implement above repository with different technologies: MongoDB with Spring Data MongoDB, Jpa with Spring Data JPA and for example Cassandra with my own implementation of repository. Can somebody point me on documentation about implementing own Spring Data module?
How can I use Spring Data concepts to use both existed solutions and create my own implementation?
It will be great if you can provide simple example.

There's already a module for Cassandra in the making, so I suggest to contact the maintainers and help out if you like to. Other than that, most of the community driven modules have started by simply studying the existing modules and working their way backwards.

Related

spring-data-jdbc integrate with mybatis

I am currently using myBatis for my project, it is good for complex SQL, but I found that I need to create many redundant SQL for basic CRUD. So I come across spring-data-jdbc (here), which is a very nice library (similar to spring-data-jpa but without JPA persistence) to help to generate CRUD SQL statement via method name.
The guide on their official website on how to integrate with myBatis is very vague, I couldn't find any other source which showing how to do that. Basically I am looking for a way to do like below:
#Repository
#Mapper
public interface PersonRepository extends CrudRepository<Person, Long> {
//via spring-data-jdbc
List<Person> findAll();
//via spring-data-jdbc
List<Person> findByFirstName(String name);
//via myBatis, the actual query is in PersonMapper.xml
List<Person> selectAllRow();
}
As you can see, when I call findAll and findByFirstName, they will be handled by spring-data-jdbc. When I call selectAllRow, it will look for corresponding myBatis mapper file for actual SQL. In this way I can combine two mechanism to handle simple CRUD query and complex query (via myBatis) together.
But above doesn't work, so currently I have to split them into two interface, one for PersonRepository, and another one for PersonMapper, which is not a very nice design.
Anyone has done similar before?
Having two separate interfaces one for repository and another for mybatis mapper is just how mybatis integration in spring-data-jdbc works as of now (version 2.2.1).
Mapper is just an implemenation detail of the spring data repository and just should not be used by the clients, so it should not be an issue.
What you want can be probably done but will require quite some work and might not be worth it.
#Repository annotation instructs spring-data-jdbc to create a proxy implementing PersonRepository with all the machinery of fetching/saving objects to the database.
#Mapper on the other hand instructs mybatis-spring to create another proxy that will handle queries from the mapping provided in xml or via annotations on the interface method.
Only one of this proxies can be injected in the places where you are going to use PersonRepository. What you can do is to create your own proxy for PersonRepository that will create both spring-data-jdbc and mybatis proxy and will dispatch calls to them. But the complexity of this solution will be rather high compared to a simple class that delegates to two separate PersonRepository and PersonMapper.
Update: it seems there is a way to combine mybatis mapper with repository as described in this comment https://github.com/spring-projects/spring-data-jdbc/pull/152#issuecomment-660151636
This approach uses repository fragments to add mybatis fragment to the repository implementation.

where does jpa picks up the method userbyusername as i have not given any implementation and i have checked the inner classes too

In my spring boot project, I am using this starter jpa . i have done all the db related thing in appliction.properties. Project is working fine . I fail to undestand where is this methods defination. We have just defined a abstract method how is this method even working?
public interface UserRepository extends JpaRepository<UserEntity, Integer>{
Optional<UserEntity> getUserByUserName(String user);
}
This is part of the magic of JPA Repositories. I don't actually know the details of how it works either, I just know how to use it.
Ultimately, I think it has to do with how Spring proxies interfaces. Spring will create an instance of an interface at runtime. When the methods are named according to the specs, Spring can generate an appropriate method.
Here is a good article that goes into detail on how you can construct the method names to make the query that you want: https://www.baeldung.com/spring-data-derived-queries.

Adding new DB support in spring data

Currently spring data has multiple db support (mysql, cassandra, mongo.. very big list), however i want to add my custom repository from the scratch like adding custom db support in spring data. I don't want to extend any existing repositories, instead I want to create a parallel repository strutcutre for my custom datasource. Looking at current implementation it looks like tedious task. It would be a great if someone could help me with minimal requirement to do this.
You could create a repository annotated bean where you would inject EntityManager or the proper bean that is acting like that, depending on database type that you are using.
#Repository
public class MyCustomRepositoryImpl implements MyCustomRepository {
#Autowired
private EntityManager entityManager;
//the methods that you are going to create.
}
For more details see:
https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
Chapter: 1.3 Custom implementations for Spring Data repositories

Use jpa and mongo repositories based on #profiles in Spring Boot MVC application

I am very new to spring and mongo db.Please suggest the way for my problem: I have this web app written in Spring boot and it mainly uses JPA for database. I have a multiple entity and then I have multiple repositories that extends JPARepository with some methods that fetch data from the database.
But now I need to have a second database and it must be MongoDB. Everything is identical to the JPA, but now I have a new repository class, that this time extends MongoRepository.
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
public interface CustomerRepositoryMongo extends MongoRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
So now I have two classes, CustomerRepository and CustomerRepositoryMongo.
1.First of all what all changes i have to made to run it in a mongodb inside the eclipse Ide and how can i configure mongodb inside eclipse IDE.?
2.How can i easily switch between two dbs,how to specify which repository to used?
3.I have no idea how can i achieve this also i can not have both the interfaces with the same name.
4.I have tried the jpa approach with #profile annotation,its working fine..but to use the mongodb ,i have to create the collection for all the entities which has #table ,#entity annotation.So shall i use #document annotation as well to specify the collection name because i am using the different names in my queries.

Spring data - Manual implementation

Is it possible to write my own function implementation along usage of spring repositories?
I would like to actually implement the function
getUserByFirstName()
and not get it automagically.
While i still want to get
getUserById()
automagically from spring-data.
1) is it possible?
2) is it possible to achieve logging for all methods spring data automagically generates? (or should i write them manually with
logger.log("entering method ...");
See section 1.3 of the manual for the first requirement:
http://docs.spring.io/spring-data/jpa/docs/1.4.2.RELEASE/reference/html/repositories.html#repositories.single-repository-behaviour
For the second requirement I guess some AOP based solution might work for you well here. See here for example using Spring's AOP support:
logging with AOP in spring?
Yes, you can!!!
There is an amazing feature in Spring data that allows this:
Create an interface with your custom method:
public interface UserRepositoryCustom {
User getUserByFirstName();
}
Make your Spring Data interface extends this new interface, as well as the Spring data crud interface (or JPA, Mongo or whatever spring data interface you're extending):
public interface MySpringDataRepository extends CrudRepository<User, Long>, UserRepositoryCustom {
}
Create a class that implements only your custom interface. The name of the class must be Impl, for instance: UserRepositoryImpl:
public class MySpringDataRepositoryImpl implements UserRepositoryCustom {
public User getUserByFirstName(){
//Your custom implementation
}
}
Now, you only need to inject the Spring data repository in your service and you can use both methods: the spring-data implemented method and your custom implemented method:
#Inject private MySpringDataRepository myRepository;
That's it!!
Look at this section in the documentation:
Spring Data Custom implementations

Resources