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
Related
The recommended way of executing SQL queries is by creating a repository, using the #Repository annotation. I'm wondering if I can also execute SQL queries within a service, using the #Service annotation, or is this tied to a specific Spring stereotype?
For example: Is there any rule that guarantees that a #Service class must have business logic and #Repository must have query execution? If I execute a query in a #Service class will it throw any exception?
No it won't throw any exception.
But the idea of separating the DB Logic and Business Logic is to use #Service for service implementations (business logic) and #Repository for repositories i.e to handle DB operations (it can be CRUD, PagingAndSorting etc).
Thus, the code becomes modular and obeys the design patterns and coding standards. Service will make use of Repositories. And your handlers will use methods from your Service. That's how it works.
As per the Spring API specification.
A class annotated with #Repository 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.
So DataAccessException aims user code find and handle the kind of error encountered without knowing the details of the particular data access API in use (e.g. JDBC).
#Service does not have any DataAccessException translation thus you can expect un-translated exception on classes which are annotated with #Service annotation. It indicate that a class is a Business Service Facade.
#Service ,#Repository,#Controller are specialization of #Component are all termed as Spring Beans
#Component generic stereotype for any Spring-managed component
#Repository stereotype for persistence layer
#Service stereotype for service layer
#Controller stereotype for presentation layer (spring-mvc)
It's all about distributing the concerns (Presentation,Business,Database),so it won't through any exception as asked by you.
You can refer here for more-Spring Docs
It will not through any exception there are some specification of each annotation.THIS answer will give you more clarity hope it will help you.
When we are going to develop any Project it should be lossy coupled and maintainable. To achieve this layer separation is important
#Service - Annotate all your service classes with #Service. This layer knows the unit of work. All your business logic will be in Service classes. Generally, methods of service layer are covered under a transaction. You can make multiple DAO calls from service method. if one transaction fails all transactions should rollback.
#Repository - Annotate all your DAO classes with #Repository. All your database access logic should be in DAO classes.
#Component - Annotate your other components (for example REST resource classes) with component stereotype.
Reasons to use them :
The main advantage of using #Repository or #Service over #Component
is that it's easy to write an AOP pointcut that targets, for
instance, all classes annotated with #Repository.
You don't have to write bean definitions in context xml file. Instead
annotate classes and use those by autowiring.
Specialized annotations help to clearly demarcate application layers
(in a standard 3 tiers application).
What is Stereotype Refer Here
#Component generic stereotype for any Spring-managed component
#Repository stereotype for persistence layer
#Service stereotype for service layer
#Controller stereotype for presentation layer (spring-mvc)
For More Details Click Here and Here
I have a Java Spring Framework project. After a bit of googling I found a way to include custom JPA methods into a JpaRepository. The injection of my repository into my service class using #Autowired works, but I can't understand how Spring handles the injection in this case. Could someone explain how Spring does the injection of CalendarEventRepository into CalendarEventService when the method implementations are in separate classes. It finds the JpaRepository implementation somewhere and my own custom implementation class with my custom method. Howcome their methods are accessible through the same reference variable calendarEventRepository? Bonus question: how does Spring find and instantiate the implementation for JpaRepository?
public interface CalendarEventRepository extends JpaRepository<CalendarEvent, Long>, CalendarEventRepositoryCustom { }
public interface CalendarEventRepositoryCustom {
public List<CalendarEvent> findCalendarEventsBySearchCriteria(CalendarEventSearchCriteria searchCriteria);
}
public class CalendarEventRepositoryImpl implements
CalendarEventRepositoryCustom {
public List<CalendarEvent> findCalendarEventsBySearchCriteria(CalendarEventSearchCriteria searchCriteria) {
}
}
public class CalendarEventService {
#Autowired
CalendarEventRepository calendarEventRepository;
...
calendarEventRepository.delete(calendarEvent);
...
return calendarEventRepository.findCalendarEventsBySearchCriteria(searchCriteria);
...
}
Thanks in advance!
When you are using Spring JPA repository interface (extend JpaRepository class), the important thing is that the implementation of the interface is generated at runtime. Method names are used by Spring to determine what the method should (since you have written the name findCalendarEventsBySearchCriteria correctly, it means that you already know that). In your particular case, CalendarEventRepository extends CalendarEventRepositoryCustom and therefore has a method findCalendarEventsBySearchCriteria(...), and also extends JpaRepository<CalendarEvent, Long>, which means that it should be treated as JPA repository, and the corresponding implementation should be generated.
To enable the generation of the repository implementation, you need to either include <jpa:repositories base-package="..." /> to your XML configuration file, or #Configuration #EnableJpaRepositories(basePackage = "...") When you have these, that's all the information Spring needs to generate (instantiate) repository and add it to application contexts, and the inject it into other beans. In your case, #Autowired CalendarEventRepository calendarEventRepository; specifies where it should be injected. I guess it more answers bonus question than the main one, but seems better to start with it.
I haven't yet touched CalendarEventRepositoryImpl. You should use such class if you want to drop the mentioned generation of repository implementation for particular methods. Spring looks for a class which name equals to repository interface's name + "Impl". If such class exists, Spring merges its methods with generated ones. So, see for yourself whether auto-generated findCalendarEventsBySearchCriteria method fits your needs or you want to implement it yourself. If the generated one fits, you should consider removing CalendarEventRepositoryImpl at all.
Could someone explain how Spring does the injection of
CalendarEventRepository into CalendarEventService when the method
implementations are in separate classes.
Answer: First, and most important - all Spring beans are managed - they "live" inside a container, called "application context".
Regardless of which type of configuration you are usin (Java or xml based) you enable "Component Scanning" this helps Spring determine which resource to inject.
How spring determines which bean to inject:
Matches the names.
Matches the type.
You even use Qualifiers to narrow down the search for spring.
It finds the JpaRepository implementation somewhere and my own
custom implementation class with my custom method. Howcome their
methods are accessible through the same reference variable
calendarEventRepository?
This is more of a java core question of inheritance. Since JpaRepository, CalendarEventRepositoryCustom and CalendarEventRepository are the base classes (implementations) of your CalendarEventRepositoryImpl so any method/field that is public or protected is available to CalendarEventRepositoryImpl class.
Here you are using "Program though interface" your reference variable here is calendarEventRepository which is an interface (parent) and that is why you are able to access the fields/methods.
Bonus question: how does Spring find and instantiate the
implementation for JpaRepository?
In spring configuration (java based) you tell spring to search for JPARepositories as below:
#EnableJpaRepositories(
basePackages = {
"com.package"}
, entityManagerFactoryRef = "EntityManagerFactory", transactionManagerRef = "jpaTransactionManager"
)
This is how spring gets to know which beans to create.
I recommend reading out Spring in Action (2nd to 4th Edition) by Craig Walls.
You can as well go through the https://spring.io/docs
Annotations (Autowired, Inject, your custom) works because of AOP. Read a bit about AOP and you will know how that works.
Why we needs to use #service inside the service Implementation and #repository in the DAO Implementation. There are no problem occur when I interchange the #service and #repository annotation in the spring MVC.
According to documentaion #Repository,#Service,#Controller are all synonyms. They all are just specializations of #Component annotation. So, generally, they can be used one instead of other. But ... you should not do this.
First reason: any of these annotations make clear the role of your component in the application. Shows - is this component belongs to the controller, service, or data layer.
Second reason: some of these annotations processed differently by different Spring modules. For example, Spring Data JPA will process #Repository and will try to replace with implementation any interface marked by this annotation. Spring also will apply automatic exception translation to such classes. Another example: Spring Web MVC processes #Controller, and uses classes marked with it in URL mappings.
Actually, in future versions, some modules of Spring could process #Service in a particular way. Not as simple #Component. That's why documentation advises:
It is also possible that #Repository, #Service, and #Controller may
carry additional semantics in future releases of the Spring Framework.
Thus, if you are choosing between using #Component or #Service for
your service layer, #Service is clearly the better choice.
It depends on what you use for the remainder of the framework. In theory nothing changes as the #Service and #Repository annotations are basically #Component annotations. The same could be said for #Controller or #Endpoint (for Spring Ws and there are more).
However they express an intent of what a class is (a service, a repository) and makes it clear to the user to what layer that class belongs.
However if you also use Spring for transaction managemnt then #Repository is also a trigger for adding exception translation to that class (also see the reference guide).
Although nothing has to break it probably will at some point.
No [ManagedType] was found for the key class [java.lang.Object] in the Metamodel - please verify that the [Managed] class was referenced in persistence.xml using a specific <class>java.lang.Object</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entityEmbeddableManagedTypeNotFound(MetamodelImpl.java:173) ~[org.eclipse.persistence.jpa-2.5.2.jar:na]
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:495) ~[org.eclipse.persistence.jpa-2.5.2.jar:na]
It's strange because reverting to Spring Data JPA 1.4.3.RELEASE fixed the problem. But we would like to understand what is causing this. The interface repository we're using looks like this
#Repository
public interface BaseRepository<T, K extends Serializable>
extends JpaRepository<T, K>,
QueryDslPredicateExecutor<T> {
}
and
#Repository
public interface PersonRepository extends BaseRepository<Person, Long> { }
In the meantime, we'll use the old version, but I'm not sure where to look in order to fix this. Any ideas?
tl;dr
As stated in the reference documentation, intermediate repository interfaces need to be annotated with #NoRepositoryBean. Generally speaking, Spring Data repositories do not need to be annotated with #Repository.
Details
Spring Data JPA versions until 1.4.x used a lazy instantiation model for repository interfaces. This means that if no one explicitly referred to a particular repository interface, no repository bean was created and thus the generic typing not evaluated.
In Spring Data 1.5 M1 we changed that (more precisely, Spring Data Commons 1.7 M1 - see this ticket, but that is what JPA 1.5 M1 depended on) to align with the default bean instantiation model that's used throughout the Spring container (eager instantiation is the default).
This means, that previously erroneous intermediate interfaces like your BaseRepository now start to fail the context bootstrapped as their generics information is evaluated at startup. As indicated above, the suggested workaround is using #NoRepositoryBean on the intermediate interface as this will cause the interface to be ignored by Spring Data and there will be no attempt to create a Spring bean for it at all.
Do you use BaseRepository somewhere as a bean? If not, maybe remove the #Repository annotation from it, or replace with #NoRepositoryBean
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.