I have a spring boot application which I am trying to inject a repository. Every time I try to use the repository its null. Here is a snippet of code:
My main application
package com.cisco.ido.no2.deployment;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#EnableAutoConfiguration
#SpringBootApplication
public class No2AlDeviceDeploymentIdApplication {
public static void main(String[] args) {
SpringApplication.run(No2AlDeviceDeploymentIdApplication.class, args);
}
}
My component
#Component
#PostBack(route = "no2.deployment", dataClass = String.class, queue = "no2-deployment")
public class DevicePostbackRunnable extends PostBackRunnable<String> {
#Autowired
private DeviceTypeRepository deviceTypeRepository;
public DevicePostbackRunnable() {}
public DevicePostbackRunnable(Class<String> dataClass) {
super(dataClass);
}
#Override
public void processTaskResult(String result, RunningTask runningTask) {
DeviceType dt = deviceTypeRepository.findOne((long)12); // <-----here
int yy = 90;
}
}
Here is my repository code:
package com.cisco.ido.no2.deployment.repositories;
import com.cisco.ido.no2.deployment.entities.DeviceType;
import org.springframework.data.repository.CrudRepository;
public interface DeviceTypeRepository extends CrudRepository<DeviceType, Long> {
}
My package name for DevicePostBackRunnable is com.cisco.ido.no2.deployment. When I call DeviceType dt = deviceTypeRepository.findOne it is always null. Is there a way to make this work? Also, when I inject this repository in my Rest Controller it works fine.
You should put #Repository in your interface DeviceTypeRepository. So that
the class will automatically be detected by the Spring container as part of the container's component scanning process when you used #Autowired.
From Spring Documentation: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-stereotype-annotations
The #Repository annotation is a marker for any class that fulfills the
role or stereotype of a repository (also known as Data Access Object
or DAO). Among the uses of this marker is the automatic translation of
exceptions as described in Section 20.2.2, “Exception translation”.
Spring provides further stereotype annotations: #Component, #Service,
and #Controller. #Component is a generic stereotype for any
Spring-managed component. #Repository, #Service, and #Controller are
specializations of #Component for more specific use cases, for
example, in the persistence, service, and presentation layers,
respectively. Therefore, you can annotate your component classes with
#Component, but by annotating them with #Repository, #Service, or
#Controller instead, your classes are more properly suited for
processing by tools or associating with aspects. For example, these
stereotype annotations make ideal targets for pointcuts. 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. Similarly, as
stated above, #Repository is already supported as a marker for
automatic exception translation in your persistence layer.
Your interface should have one of the following annotations in order to be injectable by spring:
#Component
#Service
#Repository
#Controller
Related
I am trying to understand which types of beans in Spring are being proxied, so far i understood its the #Aspect , #Transactional annotated classes. So I played a bit on my PC, and noted that if I annotate a class with #Component, it's not getting proxied when Autowired, but if I just change the annotation to #Repository, it is proxied by CGLIB. As far as i understand, #Repository is just an alias of #Component, why is it getting proxied and the other one not ?
Here are the example very simple classes
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Repository
public class JustForTest {
private final String hello = "";
public String getHello() {
return hello;
}
}
and
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Component
public class JustForTest {
private final String hello = "";
public String getHello() {
return hello;
}
}
Why does Spring need to proxy bean classes? The basic high level answer is: because it needs to add additional logic to the class at runtime so you don't have to write it yourself (or configure things in lengthy XML descriptor files...). Just like the #Transactional annotation adds magic transaction management to bean methods, the Repository annotation must also have something attached to it; you know this for a fact already because the bean gets proxied as soon as you add the annotation.
So to find your answer, simply research what the purpose of the Repository annotation is. A basic search brings up this article from a reputable source which exactly puts it as simple as I was hoping to be able to put it:
https://www.baeldung.com/spring-component-repository-service
I quote:
#Repository’s job is to catch persistence-specific exceptions and re-throw them as one of Spring’s unified unchecked exceptions
Read: this functionality is added at runtime. Hence: proxy.
I have a repository in different package than the configuration class , so I annotated it as the following with #Repostiory:
package test;
#Repository
public interface UserTest extends JpaRepository<User, Long> {
}
I have done the component scan on it and it didn't work :
package com.app;
#SpringBootApplication
#ComponentScan({"test","com.app"})
public class Application extends SpringBootServletInitializer {
}
Exception : No qualifying bean of type 'test.UserTest' available: expected at least 1 bean which qualifies as autowire candidate.
why doesn't the component scan work on repository unless I add enableJpaRepositories ? I thought componetScan is enough
Update:
as some of the answers provides solution , I'm asking about explanation not solution . The following will work without even doing component scan on "test" :
SpringBootApplication
#EnableJpaRepositories({"test","com.app"})
public class Application extends SpringBootServletInitializer{
}
Now the question why do I even need to use componentscan on #Repository when it doesn't work ? why in the documentation the #Repository is scanned by componentscan when it doesnt have effect and #EnableJpaRepostiories is enoguh?
from Spring documentation on component scan :
Indicates whether automatic detection of classes annotated with #Component #Repository, #Service, or #Controller should be enabled.
the #Repository in my case is not detected
In order to let spring knows what DataSource is related to what Repository you should define it at the #EnableJpaRepositories annotation.
Try enabling jpa repositories like below.
#SpringBootApplication
#ComponentScan({"test","com.app"})
#EnableJpaRepositories("test")
public class Application extends SpringBootServletInitializer {
}
UPDATE : Why #EnableJpaRepositories needed?
#SpringBootApplication automatically provides the features of the following annotations
#Configuration
#EnableAutoConfiguration
#ComponentScan
But if you try defining your own annotation then spring boot will not take care of internal auto configurations so this is the reason we have to enable repositories.
I have projects in which only #SpringBootApplication is enough if you are not writing your own things.
I hope you got the point.
Golden words :
If you want to get the maximum advantage of spring boot’s auto configuration feature, it is expected to put all your class packages under spring boot main application package (directly in main package or indirectly as sub packages).
I found an explanation about what I was doing wrong. The #Repository annotation with componentscan will not cause spring to implement the spring jpa repository. for the interfaces that implement crud repository enablejparepository should be used.
Now the use of #Repository with componentscan is when you have a repository class and you have your own DAO not for spring curd repo otherwise the implementation won't be created :
#Repository
public class UserTest {
public List<Object> findById(long l) {
.......
}
}
you should use your code like below as #ComponentScan always work with basepackages so your implementation should be like below.
package com.app;
#SpringBootApplication
#ComponentScan(basePackages={"test","com.app"})
#EnableJPARepositories
public class Application extends SpringBootServletInitializer {
}
Per Spring 3 document, The IoC container, the #Named annotation is a standard equivalent to the #Component annotation.
Since #Repository, #Service, and #Controller are all #Component, I tried to used #Named for all of them in my Spring MVC application. It works fine. But I found the replacement of #Controller seems to have a bug. In the controller class, originally, it was
#Controller
public class MyController{
...
}
It works fine. When I changed #Controller to #Named
#Named
public class MyController{
...
}
It failed with error:
"No mapping found for HTTP request with URI ...".
But if I added #RequestMapping to the class as follow
#Named
#RequestMapping
public class MyController{
...
}
It would work as expected.
For #Repository and #Service, I can simply replace them with #Named with no issue. But the replacement of #Controller needs extra work. Is there anything I am missing in the configuration?
#Named works the same as #Component. However, the annotations #Controller, #Service, and #Repository are more specific.
From the Spring docs:
#Component is a generic stereotype for any Spring-managed component.
#Repository, #Service, and #Controller are specializations of
#Component for more specific use cases, for example, in the
persistence, service, and presentation layers, respectively.
For example, these stereotype annotations make ideal targets for
pointcuts. 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. Similarly, as stated above, #Repository is already supported
as a marker for automatic exception translation in your persistence
layer.
This section explains the difference with #Named.
Many components, like Spring's DispatcherServlet (MVC configuration in WebApplicationContext) aren't looking for Component, they are looking for #Controller. So when it scans your class, it won't find it in #Named. In a similar fashion, transaction management with #Transactional looks for #Service and #Repository, not for the more generic #Component.
All #Repository, #Service and #Controller are mainly for declaring Spring beans, apart from that it gives extra information to Spring about the type of bean like controller, dao etc
Per Spring 3 document, The IoC container, the #Named annotation is a standard equivalent to the #Component annotation.
Since #Repository, #Service, and #Controller are all #Component, I tried to used #Named for all of them in my Spring MVC application. It works fine. But I found the replacement of #Controller seems to have a bug. In the controller class, originally, it was
#Controller
public class MyController{
...
}
It works fine. When I changed #Controller to #Named
#Named
public class MyController{
...
}
It failed with error:
"No mapping found for HTTP request with URI ...".
But if I added #RequestMapping to the class as follow
#Named
#RequestMapping
public class MyController{
...
}
It would work as expected.
For #Repository and #Service, I can simply replace them with #Named with no issue. But the replacement of #Controller needs extra work. Is there anything I am missing in the configuration?
#Named works the same as #Component. However, the annotations #Controller, #Service, and #Repository are more specific.
From the Spring docs:
#Component is a generic stereotype for any Spring-managed component.
#Repository, #Service, and #Controller are specializations of
#Component for more specific use cases, for example, in the
persistence, service, and presentation layers, respectively.
For example, these stereotype annotations make ideal targets for
pointcuts. 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. Similarly, as stated above, #Repository is already supported
as a marker for automatic exception translation in your persistence
layer.
This section explains the difference with #Named.
Many components, like Spring's DispatcherServlet (MVC configuration in WebApplicationContext) aren't looking for Component, they are looking for #Controller. So when it scans your class, it won't find it in #Named. In a similar fashion, transaction management with #Transactional looks for #Service and #Repository, not for the more generic #Component.
All #Repository, #Service and #Controller are mainly for declaring Spring beans, apart from that it gives extra information to Spring about the type of bean like controller, dao etc
I came into IOC via Google Guice.
And now I've been forced to use Spring 2.5.6 at work & I am lost because Spring is quite complicated. Here are some questions after reading bits of the spring docs:
What is the difference between #Service, #Controller and #Component ? If I just want to auto wire my objects like Guice, do I need to be bothered by all these stereotypes ?
I'm planning to go the component-scan route with only constructor injection (Setter injection is mostly advocated by the Church of Scientology) and no freaking XML stuff. So is this code extract all I need ?
#Component
public class Foo
{
#Autowired(required=true)
public Foo( Bar bar, #Qualifier("yay") Boo yay,
#Qualifier("hoo") Boo hoo )
{
_bar = bar; _boo = boo;
}
Bar _bar;
Boo _boo;
....snipped...
}
#Component
#Qualifier("yay")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public BooYay implements Boo
{
}
#Component
#Qualifier("hoo")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public BooHoo implements Boo
{
}
In the above example, did I correctly qualify the 2 different implementations of Boo ?
Is there any feature similar to Google Guice's Providers ?
How do I mimic the #Singleton behaviour (in Guice) in Spring ?
Looking at your code, it seems all fine and your components will get autowired. You must give your package name in XML config file, so Spring can scan that for annotations.
Spring-managed components in general, the default and most common scope for autodetected components is singleton.
Actually, #Component is a generalisation of #Service and #Controller. See the docs.
Spring 2.5 introduces further
stereotype annotations: #Component,
#Service and #Controller. #Component
serves as a generic stereotype for any
Spring-managed component; whereas,
#Repository, #Service, and #Controller
serve as specializations of #Component
for more specific use cases (e.g., in
the persistence, service, and
presentation layers, respectively).
What this means is that you can
annotate your component classes with
#Component, but by annotating them
with #Repository, #Service, or
#Controller instead, your classes are
more properly suited for processing by
tools or associating with aspects. For
example, these stereotype annotations
make ideal targets for pointcuts. Of
course, it is also possible that
#Repository, #Service, and #Controller
may carry additional semantics in
future releases of the Spring
Framework. Thus, if you are making a
decision between using #Component or
#Service for your service layer,
#Service is clearly the better choice.
Similarly, as stated above,
#Repository is already supported as a
marker for automatic exception
translation in your persistence layer.
Make sure that your default-autowire or autowire value for those beans is byType. And then you should modify your Boo components like below,
#Component("yay")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public BooYay implements Boo
{...}
#Component("hoo")
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public BooHoo implements Boo
{...}
You might like to do it with autowire = "byName", in that case you will not need #Qualifiers, but have to provide the matching setters. I hope you will managed to knock the thing off now.