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

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.

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

How can I create a Pointcut or Around for extended classes with shared interface?

I have an abstract service class.
abstract class AbstractService<T> {
public void saveNew(T entity) {
}
}
And I have two more abstract classes extends AbstractService and implement a shared interface.
abstract class MoreAbstractService2<T extends Some2>
extends AbstractService<T>
implements SharedInterface {
}
abstract class MoreAbstractService3<T extends Some3>
extends AbstractService<T>
implements SharedInterface {
}
Now I want to validate the entity argument on these two extending services' saveNew(T) method.
How can I define a #Pointcut and (or) an #Around for following conditions?
extends the AbstractService class
implements the SharedInterface interface
you can use within as following:
within(com.somepackage.Super+)
where com.somepackage.Super is the fully qualified base class name and + means "all subclasses". Other pointcut is
execution(* com.somepackage.Super+.*(..))
R.G's solution has a few disadvantages:
The pointcut matches too many joinpoints.
Thus it needs reflection in order to filter out the unnecessary ones.
I am going to show you a stand-alone AspectJ solution (no Spring, I am not a Spring user), but the aspect would look just the same in Spring, you only need to make it a #Component or declare a #Bean factory in your configuration. But the same applies to all the classes you want to intercept, of course.
Because I prefer a full MCVE with all necessary dependency classes in order for you to be able to copy, compile and run it, and because I also added negative test cases (sub-classes only extending the abstract base class or only implementing the interface), this is a lot of code. So please bear with me:
Abstract classes, interface and helper classes:
package de.scrum_master.app;
public abstract class AbstractService<T> {
public void saveNew(T entity) {
System.out.println("Saving new entity " + entity);
}
}
package de.scrum_master.app;
public class Some2 {}
package de.scrum_master.app;
public class Some3 {}
package de.scrum_master.app;
public abstract class MoreAbstractService2<T extends Some2>
extends AbstractService<T>
implements SharedInterface {}
package de.scrum_master.app;
public abstract class MoreAbstractService3<T extends Some3>
extends AbstractService<T>
implements SharedInterface {}
package de.scrum_master.app;
public interface SharedInterface {
void doSomething();
}
Driver application (AspectJ + POJOs, not Spring):
This driver class contains some static inner classes subclassing the given base classes and/or implementing the shared interface. Two are used for positive tests (should be intercepted), two for negative tests (should not be intercepted). Each class also contains an additional method as another negative test case which should not be matched - better safe than sorry.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
// Should be intercepted
InterceptMe1 interceptMe1 = new InterceptMe1();
interceptMe1.saveNew(new Some2());
interceptMe1.doSomething();
interceptMe1.additional();
printSeparator();
// Should be intercepted
InterceptMe2 interceptMe2 = new InterceptMe2();
interceptMe2.saveNew(new Some3());
interceptMe2.doSomething();
interceptMe2.additional();
printSeparator();
// Should NOT be intercepted
DontInterceptMe1 dontInterceptMe1 = new DontInterceptMe1();
dontInterceptMe1.saveNew(new Some2());
dontInterceptMe1.additional();
printSeparator();
// Should NOT be intercepted
DontInterceptMe2 dontInterceptMe2 = new DontInterceptMe2();
dontInterceptMe2.additional();
printSeparator();
}
private static void printSeparator() {
System.out.println("\n----------------------------------------\n");
}
static class InterceptMe1 extends MoreAbstractService2<Some2> {
#Override
public void doSomething() {
System.out.println("Doing something in MoreAbstractService2<Some2>");
}
public void additional() {
System.out.println("Additional method in MoreAbstractService2<Some2>");
}
}
static class InterceptMe2 extends MoreAbstractService3<Some3> {
#Override
public void doSomething() {
System.out.println("Doing something in MoreAbstractService3<Some3>");
}
public void additional() {
System.out.println("Additional method in MoreAbstractService3<Some3>");
}
}
static class DontInterceptMe1 extends AbstractService<Some2> {
public void additional() {
System.out.println("Additional method in AbstractService<Some2>");
}
}
static class DontInterceptMe2 implements SharedInterface {
#Override
public void doSomething() {
System.out.println("Doing something in SharedInterface"); }
public void additional() {
System.out.println("Additional method in SharedInterface");
}
}
}
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class EntityValidationAspect {
#Before(
"execution(* saveNew(*)) && " +
"args(entity) && " +
"target(de.scrum_master.app.SharedInterface) && " +
"target(de.scrum_master.app.AbstractService)"
)
public void validateEntity(JoinPoint thisJoinPoint, Object entity) {
System.out.println("-> Pre-save entity validation: " + entity);
}
}
As you can see, the aspect uses two target() pointcuts which must both match. It also specifically targets any saveNew method with a single argument saveNew(*), binding that argument as an advice method parameter via args().
For demonstration's sake I do not validate anything (I don't know how you want to do that) but just print the entity. Thus, a #Before advice is sufficient. If in case of negative validation you want to throw an exception, this advice type is also okay. If you need to do more, such as manipulate the entity's state or replace it before passing it on to the target method, call an alternative target method instead or none at all, return a specific result (in case of non-void methods, here not applicable), handle exceptions from the target method etc., you ought to use an #Around advice instead.
Console log:
-> Pre-save entity validation: de.scrum_master.app.Some2#28a418fc
Saving new entity de.scrum_master.app.Some2#28a418fc
Doing something in MoreAbstractService2<Some2>
Additional method in MoreAbstractService2<Some2>
----------------------------------------
-> Pre-save entity validation: de.scrum_master.app.Some3#5305068a
Saving new entity de.scrum_master.app.Some3#5305068a
Doing something in MoreAbstractService3<Some3>
Additional method in MoreAbstractService3<Some3>
----------------------------------------
Saving new entity de.scrum_master.app.Some2#1f32e575
Additional method in AbstractService<Some2>
----------------------------------------
Additional method in SharedInterface
----------------------------------------
Et voilĂ  - the aspect does exactly what you asked for, as far as I understand your requirement. :-) More specifically, it does not get triggered in the third case when saveNew is being called, but the class does not implement the interface.
Following code can be used for the validation mentioned.
The point cut is to intercept on the execution of a specific method for the subclasses of AbstractService and the code logic is to only validate if SharedInterface is a superinterface of the target bean.
The use of isAssignableFrom() is required as the interfaces proxied by the AOP proxy does not include SharedInterface. As per my understanding , a pointcut expression to match the second criteria will not be possible for the same reason and hence handled the requirement in the code logic.
Hope this helps
#Aspect
#Component
public class ValidationAspect {
#Pointcut("execution(* package.to.AbstractService+.saveNew(..))")
public void isAbstractServiceType() {
}
#Around("isAbstractServiceType() && args(entity) && target(bean)")
public void validateEntityArugments(ProceedingJoinPoint pjp, Object entity, Object bean) throws Throwable {
if (SharedInterface.class.isAssignableFrom(bean.getClass())) {
System.out.println(entity);
// ..validate
}
pjp.proceed();
}
}

Is it possible to have a constant valued through a Spring Service?

We have a web service that one of its parameters is called origin and this origin is always validated against a code in the database.
For each one of our services I have to validate this code. This code does not change so I want to keep it in a constant, but I still have to validate it to prevent clients from sending a wrong code.
Basically what I want is this:
#Service
public class Service {
#Autowired
private LogBS logBS;
// I know this cannot be used in a static context.
public static final Long CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
public void validateOriginCode(final Long origin) {
if (!origin.equals(CODE)) {
throw new ServiceException("Wrong origin code!");
}
}
}
I know something similar can be done with Spring caching, but is it possible to do it with a constant?
I would rather go with this:
#Service
public class CodeValidatorService {
private LogBS logBS;
private Long CODE;
#Autowired
public CodeValidatorService(LogBS logBS){
this.logBS = logBS;
CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
if (CODE == null){
throw new ServiceException("Code cannot be read from DB!");
}
}
public void validateOriginCode(final Long origin) {
if (!origin.equals(CODE)) {
throw new ServiceException("Wrong origin code!");
}
}
}
Just as a code review, I prefer injecting dependencies in the constructor rather than using #Autowired in the field directly, it makes the service testable. You could also try to read the code in a #PostConstruct method, but I think it's better to do it in the constructor so you always have the service in a ready-to-go state.
For using it in the rest of your services, inject the CodeValidatorService instance on them:
#Service
public class OtherService {
private CodeValidatorService codeValidatorService;
#Autowired
public OtherService(CodeValidatorService codeValidatorService){
this.codeValidatorService = codeValidatorService;
}
public void performAction(final Long origin) {
codeValidatorService.validateOriginCode(origin);
//do the rest of your logic here
}
}
See also:
Spring Beans and dependency injection
Setter injection versus constructor injection
You can have a constantsProvider class
#Component
public class ConstantsProvider {
#Autowired
private LogBS logBS;
private String CODE;
#PostConstruct
public void init() {
CODE = this.logBS.retrieveLogWebServiceCode("webServiceName");
}
public String getCode() {
return CODE;
}
}
Add this snippet of code to Service class
#Autowired
private ConstantsProvider constantsProvider;
You can use constantsProvider.getCode() in your services. This way CODE is going to be immutable and not defined in a static context.
Note: If you have more constants similar to this, there is a better way to define the ConstantsProvider class. If there is only one, I would stick to the above implementation.
Edit 1:
If you need it in all the service classes, make the constantsProvider a spring bean and initialize the CODE there itself. Updated the answer

Spring Data JPA custom method causing PropertyReferenceException

I have been trying to create a spring boot application. In my application I would like to add some custom methods to save the data instead of using the default save method.
My application entry point is something like this:
#Configuration
#ComponentScan
#EnableJpaRepositories(repositoryImplementationPostfix = "CustomImpl")
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
#PropertySource("application.properties")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have changed this line repositoryImplementationPostfix to even Impl but, it didn't work.
My CrudRepository
#RepositoryRestResource
public interface TaRepository extends CrudRepository<Ta, Integer> ,TestRepository{
List<Ta> findByName(#Param("name") String name);
}
My Custom Repository:
public interface TestRepository {
public void myCustomMethod(TestDto dto);
}
My Custom Repository Impl
public class TestRepositoryCustomImpl implements TestRepository{
#PersistenceContext
private EntityManager em;
#Override
public void myCustomMethod(TestDto model){
}
NOTE:
If I change my CrudRepostory from the mentioned to this:
#RepositoryRestResource
public interface TaRepository extends CrudRepository<Ta, Integer> {
List<Ta> findByName(#Param("name") String name);
}
everything works fine. But not with the custom method implementation.
For Spring Data JPA #Repository or #RepositoryRestResource you never need to implement a Custom Interface. For any simple query you can create any kind of method, please follow the simple guide.
http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html
For a complex query you can use JpaSpecificationExecutor.
How can I create a Predicate from a HQL query?

generic service and controller 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

Resources