generic service and controller spring - spring

package com.lhoussaine.springjsfjpa.entities;
#Table(name="address")
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String streetNumber;
private String streetName;
private String city;
getter/setter
}
and I Have 30 entities.
Now repositories:
package com.lhoussaine.springjsfjpa.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.repository.annotation.RestResource;
import com.lhoussaine.springjsfjpa.entities.Address;
#RestResource(rel="address", path="address")
public interface AddressRepository extends JpaRepository<Address,Integer> {
}
Here I dont need to implemente CRUD operation! thanks to spring-data-jpa! And I want same standard for controller and services:
public interface IAddressService {
}
package com.lhoussaine.springjsfjpa.services.generic;
import java.util.List;
public abstract class GenericService<T,K> {
public abstract T create(T saved);
public abstract void remove(T deleted);
public abstract T findById(K id) ;
public abstract List<T> findAll();
public abstract T removeById(K id);
}
package com.lhoussaine.springjsfjpa.services.impl;
#Service
#Transactional
public class AddressService extends GenericService<Address, Integer> implements IAddressService {
#Autowired private AddressRepository iaddressRepository;
public Address create(Address saved) {
Address address=saved;
return iaddressRepository.save(address);
}
public void remove(Address deleted) {
iaddressRepository.delete(deleted);
}
public Address findById(Integer id) {
return iaddressRepository.findOne(id);
}
public List<Address> findAll() {
return iaddressRepository.findAll();
}
public Address removeById(Integer id) {
Address addr= iaddressRepository.findOne(id);
if(addr!=null){
iaddressRepository.delete(addr);
}
return addr;
}
}
Now the question is: with controller how I do?
Develop a controller for each class? knowing that I have 30 service classes.
Is there something approaching the same standard such as Spring Data JPA but for services and controller?
As you see with services classes! I'm obliged to make GenericService classes and create an interface for each class that I have in my package entities.

The controllers and the services should not be generic. Although it's understandable that every entity in your app could be created or found by ID, the services should only have the methods needed to implement the business logic of the app.
And the controllers should be created to implement the UI layer of your app. So, once you have a specification (or a clear idea in mind) of how a specific page of your application should look like and work, then implement te controller and the services to implement this page.
If your app is so generic that all it does is create, update and delete rows in tables, then you don't need to implement anything: a generic database web interface like PHPMyAdmin will do.

You can use generic service and controllers only without annotations, i.e with XML configuration. For controllers you also have to set Map<[methodName],org.springframework.web.bind.annotation.RequestMapping> for each controller and extend (override) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping to use it.
See example https://sites.google.com/site/beigeerp/home/spring-generic-controller

Related

How to configure spring JpaRepository to be one of the implementations of an interface

Hello I'm working on a task where based on configuration I need to use either a custom implementation of a repository that uses an api to fetch data or a normal repository that extends a JpaRepository.
So something like this:
public interface PersonRepository {
Person findPersonById(Long id);
}
and the possible implementations for that would be:
public interface PersonDatabaseRepository extends PagingAndSortingRepository<Person, Long>, JpaSpecificationExecutor<Person>{
Person findPersonById(Long id);
}
public class PersonApiRepository extends implements PersonRepository {
public Person findPersonById(Long id) {
return someApiClient.findPersonById(id);
}
}
Is that possible? I know I could add another interface in the upper layer where the implementations would use either PersonDatabaseRepository or PersonApiRepository inside but I was wondering if it would be possible to skip that

Clean Architecture - Repository is a Gateway? If is right, a usecase can call a Repository directly?

We now that, os clean architecture we have a layers and arrow dependence to center, ask this, a usecase can call a Repository directly?
Example:
Usecase:
public class SomeRepository{
DBImplementatio db;
public String save(String string){
db.implSave(string);
}
}
public class SomeUsecase{
SomeRepository repository;
public void doSomething(){
repository.save("saveMe");
}
}
Repository and Gateway are used interchangeably to abstract the API of another service such as a database.
A use case should not call a repository directly. In fact it shouldn't know anything about any concrete repository at all.
The Repository/Gateway should be an interface and must be implemented by the Repository implementation class.
Then, you can inject the Repository implementation instance in the use case constructor(Dependency inversion). This way use case wont depend on the implementation itself but on the abstraction(interface).
public interface Repository {
String save(String string);
}
public class RepositoryImpl implements Repository {
public String save(String string) {
// Implementation of save here
}
}
public class SomeUsecase{
Repository repository;
public SomeUsecase(Repository repository) {
this.repository = repository
}
public void doSomething(){
this.repository.save("saveMe");
}
}
The best option in my opinion is to create a interface for your use case:
public interface SomeUsecase{
void doSomething;
}
Then you create a implementation of this interface in the data layer:
public class SomeUsecaseImplementation implements SomeUsecase{
SomeRepository repository;
public void doSomething(){
repository.save("saveMe");
}
}
This way your data layer is coupled with the repository instead of your use case.

Custom delete method in JpaRepository

I'd like to know if there's a way of overriding the delete method for some of my JpaRepository's without having to override the rest of the methods.
Currently I have something like
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
And I'd like to override the delete(T Entity) method in CrudRepository. To do so I've tried implementing the UserRepo but then I have to implement all the findByX and haven't really find anything around on how to properly do that.
Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)?
Thanks in advance!
Not sure I understand you clear enough, but lets try:
... I have to implement all the findByX ...
You don't, spring will generate JPQL snippet if you name methods in your interface with suitable convection please take a look at this and this articles
... Is there any annotation to add to a function in the Entity class
so it runs when you call UserRepo.delete(myUser)? ...
You can use #PreRemove / #PostRemove annotation on method in your entity class:
#PreRemove / #PostRemove
public void someMethod() { ... }
In addition to Raheela Aslam post:
Spring-data documentation has an example of how you can override standard repository methods, for example:
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}
You can read about it there:
https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations
UPD:
Read it carefully, because there are some important things, e.g
The most important part of the class name that corresponds to the fragment interface is the Impl postfix.
Also the documentation says:
Custom implementations have a higher priority than the base implementation and repository aspects.
If you want to keep Spring's behavior for deletion, but want to have some logic to be executed either before or after, you may utilize java8's interface default methods, and try the following :
public interface UserRepo extends JpaRepository<User, Long> {
default void customDelete(User user) {
// before logic
// ..
delete(user); // actual call to deletion
// after logic
// ..
}
}
There are several ways to do this depending on what you're trying to do:
Use method naming, and let Spring derive the JPQL query from the naming (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-from-method-names/)
Use the Query annotation and add the desired JPQL query in the annotation (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-the-query-annotation/)
Use a named query (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-named-queries/)
I prefer to use method naming if possible, the method name gets long, but you know exactly what it does by looking at it.
In your case code will be like as below:
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
public interface UserRepositoryCustom {
void deleteByEmail(String email);
}
public interface UserRepositoryImpl implements UserRepositoryCustom {
public void deleteByEmail(String email) {
//provide your custom implimentation
}
}
Hi you can write your own Interface write implementation with EntityManager and
extend in you interface here is the sample :
https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
Actually one more way is writing by soemthing like :
User findByUsername(String username) // it will find the user by specific username
spring data will create you an implementation of this method
The same way you can create your own delete method
Here is useful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
In this link you can go to part 2.3 QueryMethods:
https://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/html/jpa.repositories.html
You can also define #NameQuery in your entity class:
#Entity
#Table(name = "employee", schema="spring_data_jpa_example")
#NamedQuery(name = "Employee.yourMethodQueryName",
query = "yourQuery"
)
public class Employee {}
#Repository
public interface EmployeeRepository extends JpaRepository<Employee,Long> {
List<Employee> yourMethodQueryName(Your list of params);
}
Here is link with sample:
https://www.logicbig.com/tutorials/spring-framework/spring-data/jpa-named-queries.html
I think this is helpful for you
public interface UserRepo extends JpaRepository<User, Long> {
#Modifying
#Query("delete from User u where u.email = ?1")
void deleteByEmail(String email);
}

Auto generate Spring Rest-Controller

currently I have the Task to create a REST api onto an existing service layer in Spring.
This is the Setup:
#Entity
public class Example{
#Id
public Long id;
...
}
public interface ExampleRepository extends CrudRepository<Example, Long> {}
#Service
public class ExampleService{
#Autowired
private ExampleRepository repo;
public List<Example> findAll(){
//do some businesslogic
return repo.findAll();
}
}
#RestController
#RequestMapping("/exampleService/*")
public class ExampleController{
#Autowired
private ExampleService service;
#GetMapping
public List<Example>findAll(){
return service.findAll();
}
}
The controller is only boilerplate to me and I would really like to find a way to generate it automatically because we are talking about a lot of services and even more functions.
I know there is a way to expose the repositories as REST-Endpoints using spring-data-rest but that is not what I want. I want the services to be exposed as REST-Endpoints. Could you please give me a hint on how to do that?
You should write a Generic Rest Controller which then calls your inner services.
You can achieve this by using external resource file for storing the class details and Java Reflection API .

Spring Boot JPA #Transactional #Service does not update, but #Transactional in controller does

I have a very basic Spring Boot/JPA stack app, with a controller, service layer, and repository that does not persist updates as I understand it should.
A trivial Entity:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
protected Customer() {}
public Customer(String name) { this.name = name; }
// standard getters,setters //
}
A trivial Repository:
#Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {}
A simple Service layer:
// If the service is #Transactional and the controller is not, the update does NOT occur
#Transactional
#Service
public class CustomerService {
private static final Logger LOG = getLogger(CustomerService.class);
#Autowired
private CustomerRepository customerRepository;
boolean updateCustomerName(Long id, String name) {
Customer customer = customerRepository.findOne(id);
if (customer == null) { return false; }
// Modifies the entity
customer.setName(name);
// No explicit save()
return true;
}
}
And a REST controller that uses it all:
// If the controller is #Transactional and the service is not, the update occurs
#RestController
#RequestMapping("/mvc")
public class CustomerController {
#Autowired
private CustomerService customerService;
#RequestMapping(path = "{id}", method = RequestMethod.PUT)
public ResponseEntity updateCustomerName(#PathVariable Long id, #RequestParam("name") String name) {
customerService.updateCustomerName(id,name);
return ResponseEntity.noContent().build();
}
}
These are wired together with a simple one-liner SpringBootApplication
I have SQL debug logs enabled and see the selects, update, etc.
With the code above: When the service method is invoked by the controller, the modified entity is not persisted. SQL logs show the select of the entity but no update.
There is also no update if nothing is marked #Transactional
However, simply by moving the #Transactional annotation from the service class to the controller class, the SQL update does occur.
If I add an explicit customerRepository.save(customer) to the service method, the update also occurs. But my understanding is that the ORM should automatically save modified persistent entities.
I'm sure the issue has something to do with the EntityManager lifecycle in the web request, but I'm puzzled. Do I need to do additional configuration?
Complete example at https://github.com/monztech/SO-41515160
EDIT: This was solved, see below. Per the Spring spec #Transactional does not work in package-private methods and mistakenly did not make the update service method public.
The update will occur if the method is public and the service class has the #Transactional annotation.
I do have another question, however. Why is the #Transactional annotation necessary? (the update does not occur without it) Shouldn't the entity manager still persist the object because of the open session in view mechanism that Spring uses, independent of any transaction?
Make your updateCustomerName method public.

Resources