So i am using Spring to access my DB and fetch Users based on different Properties. With a #Restcontroller I get the Data. I created a UserRepository which extends the CrudRepository.
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Integer> {
Iterable<User> findByNachname(String nachname);
Iterable<User> findByRolle(Rolle rolle);
Optional<User> findByBenutzername(String benutzername);
#Transactional
String deleteByBenutzername(String benutzername);
}
I use #Autowire to get an Instance of the UserRepo in my Controller-class
#RestController
public class LoginController {
#Autowired
private UserRepository userRepository;
}
This works perfectly fine in all Controllers i have.
But now when i try the same in another class the userRepository Instance is null.
public class Authentificator {
#Autowired
private UserRepository userRepository;
}
The Authentificator and the LoginController are not in the same package. But both of them are not in the same package as the UserRepo.
project
UserRepo-package
Controller-Package
Authentificator-Package
you must make sure Authentificator is also a spring bean - I mean you must annotate it with something like #Component or #Service. After this step you’ll also have to “get” the Authentificator instance from spring instead of instantiating it with the new keyword.
#Autowired does work only with the spring context. This means that it will work only with class instances which are managed by Spring. Your Authentificator class is managed by you and Spring does not have to take care or know about it, it's not important for the Java Framework.
This is more of a configuration issue rather than an annotation issue.
If you want Spring to inject a field in Authenticator object the dependent object must be also created by Spring. You can do it by marking this class as a #Component or by creating a method with Authenticator return type marked with #Beanannotation. Then it must be injected somewhere.
Related
I'm trying to inject a service-annotated class into a configuration class in a Spring Boot application, but it doesn't get injected (is set to null), which I assume is due to the Spring lifeycle.
Also, this service has an overloaded constructor that uses constructor injection, and I guess this is also a problem, as autowiring acts upon a default constructor. However, the service needs to be Spring-configured, so I don't think one can create a new instance in a Bean annotated method.
How can one solve this?
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private SessionService sessionService;
#Bean
public SessionService sessionService() {
return sessionService;
}
}
public interface SessionService extends BaseCacheService<Session> {
void extendExpiration(String key);
String getSessionId(String key);
}
#Service
public class SessionServiceImpl implements SessionService {
private Environment environment;
private UserService userService;
#Autowired
public SessionServiceImpl(Environment environment, UserService userService) {
this.environment = environment;
this.userService = userService;
}
}
If I exclude the #Bean method, then I get a compilation error:
Your error is the following (you are returning a null value):
#Bean
public SessionService sessionService() {
return sessionService;
}
Solution
Since your SessionServiceImpl is annotated with #Service, you can just remove the #Bean method and let spring create it. Spring already makes it available for you.
Or, If your SessionServiceImpl wasn't annotated with #Service, you would need the following :
#Bean
public SessionService sessionService() {
return new SessionService();
}
If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by #Miloš Milivojević)
You may add #ComponentScan to your Configuration class
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
Expanding on #Alex's answer, when you annotate a method with #Bean, it tells Spring that this method will produce that type. So, you essentially told Spring to give you the null reference you already had for all Beans of type SessionService.
If you are using Annotation-based context configuration, you can Autowire any #Component Bean (not just #Service) that can be constructed without runtime parameters (e.g. has a default constructor or an Autowired Constructor). If you need to do something to create the bean (e.g. runtime configuration required), you would either create a method as #Alex suggested, or you can use getBean and pass in the Type and Constructor arguments. The former is generally preferred.
I was facing similar issue while writing an integration test class for a spring boot application. RestTemplate class and CounterService of metrics API are autowired in my service class. I could use #ContextConfiguration(Classes={RestTemplate.class}) for injecting RestTemplate to my service, but adding CounterService.class to above annotation does not help, maybe because CounterService is an interface not a concrete class, Hence I was getting "No bean of type CounterService found" issue.
Thanks to answer by Milos, I included #EnableAutoConfiguration to my integration test class, issue was resolved!
If Alex's answer does not work (removing the #Bean method), you're probably not using #EnableAutoConfiguration or your Application is not in the root-hierarchy package so it's not scanning the whole classpath. Try adding #ComponentScan("service.class.package") to your configuration (in addition to removing the sessionService method) and see if it helps.
When the bean is createt for a class as MyBean the bean id is myBean but what will be the bean ID if I create the service bean from an interface like below?
#Service
public class ProfileServiceImpl implements ProfileService
When I try to access the bean as #profileService thymeleaf gives the below error.
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'profileService' is defined
All this time I'm using this bean by autowiring to the controller. But at the moment I need to access this from the thymeleaf.
My thymeleaf code segment
<div th:unless="${#profileService.isMe(user)}">
When Spring creates a Bean Definition from a #Service or #Component annotation, it will by default create an id for the bean by lowercasing the first letter of the Class Name. If you want to override that the behavior, you can provide an alternative id in the annotation, eg. #Service("profileService").
Regarding what you are experiencing with the Repository - by default Spring looks for a custom implementation of a Repository by appending "Impl" to the Repository Interface name. If it finds it, it will not create a default implementation. So, if you had UserRepositoryImpl extends UserRepository instead of UserRepositoryImpl extends DatatablesCriteriasRepository than Spring wouldn't have created the userRepository bean. Addtionally, if you add #NoRepositoryBean annotation to the UserRepository interface, that will suppress the creation of the userRepository bean.
However, UserRepositoryImpl really should be implementing UserRepository. If it really is intended to extend DatatablesCriteriasRepository, than it should be nameed DatatablesCriteriasRepositoryImpl. Having UserRepsitoryImpl extend DatatablesCriteriasRepository is indication of a problem in the design.
for (String name : context.getBeanDefinitionNames()){
System.out.println(name);
}
This test revealed some interesting outcomes.
service beans
Service beans are named after the concrete class name regardless of the interface.
#Service
public class ProfileServiceImpl implements ProfileService
ie. profileServiceImpl in the above question.
Repository beans
Further Repository beans are something more interesting. Below is my crud repository interface without any annotations.
public interface UserRepository extends CrudRepository<User, Long>, DatatablesCriteriasRepository<User>{
And I created an implementation of the UserRepositoryImpl for the DatatablesCriteriasRepository as below without any annotations.
public class UserRepositoryImpl implements DatatablesCriteriasRepository<User>
these two included two beans with IDs userRepository userRepositoryImpl respectively.
I'm creating an application that use Spring Remoting.
I have my applicationContext.xml and i want to migrate it in a pure-code configuration.
Right not i have my main class with:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
I would like to "centralize" the loading and #Inject my bean when needed, without using:
UsersRepository userRepositories = context.getBean(UsersRepository.class);
For WebApplication i've seen WebApplicationInitializer.
but what if the application is not Web Based (no web.xml ecc)
So, I cannot guarantee this is going to be entirely accurate, but here is how I do this.
In your service class (or whatever class is utilizing the UserRepository), you want to Make it an argument of the constructor and make it a global variable, add the #Inject tag above the constructor. Here is an example.
public class UserService {
private UserRepository userRepository;
#Inject
public UserService(UserRepository userRepository){
this.userRepository = userRepository
}
}
Like I said, this is how I do and we can access the repository freely from any of the methods in the class. Hope this helps.
I am attempting to get a reference to my repository interface (UserRepository) that extends CrudRepository within my custom implementation (UserRepositoryExtensionImpl) in order to gain access to all the methods provided by Spring JPA.
Crud Extension:
#Repository
public interface UserRepository extends CrudRepository<User, String>, UserRepositoryExtension<RosterUser> {
...any custom spring JPA methods...
}
Extension Interface:
#Repository
public interface UserRepositoryExtension <T> {
public T put(T entity);
}
Custom Implementation:
public class UserRepositoryExtensionImpl implements UserRepositoryExtension<User> {
UserRepository userRepository;
#Autowired
public UserRepositoryExtensionImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public User put(User user) {
System.out.println(user + "was put");
// ...put logic here
return null;
}...
}
However, I am unable to inject UserRepository since a circular dependency exists (given that UserRepository extends the interface implemented by my UserRepositoryImpl). I am getting the following error:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ' userRepositoryImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?
A possible, but less than ideal solution would be to inject and EntityManager into UserRepositoryImp, but in that case, I do not have access to any of the Spring JPA methods provided by CrudRepository, or any additional methods that I might have created in UserRepository.
Any suggestions on how to get around this?
Any help would be greatly appreciated.
EDIT: As mentioned in #shelley's answer, I was able to solve this by making 3 changes:
Removing the #Repository from UserRepositoryExtensionImpl
Renaming UserRepositoryExtensionImpl to UserRepositoryImpl. Apparently this makes Spring aware of the implementation's existence. See Spring Doc
Removing my constructor and moving the #Autowired to the userRepository field
SUCCESS!
A couple small things need to be changed in order for this to work:
Remove the #Repository annotation from the custom repository interface (UserRepositoryExtension).
The custom repository implementation should actually be named "<StandardRepository>Impl" rather than "<CustomRepository>Impl". In your code example, this should be UserRepositoryImpl instead of UserRepositoryExtensionImpl.
As shelley pointed out, the naming is really important to make the autowire work. In the example below, I follow the right naming standard for my custom interface and its implementation. But my interface that extended the JpaRepository was named “ItemDao” instead of “ItemRepository”, this resulted in that spring ignored my custom implementation altogether...
OBS!!! Should be "ItemRepository"
#Repository
public interface ItemDao extends JpaRepository<Item, Long>, ItemRepositoryCustom {}
my interface
interface ItemRepositoryCustom {...}
my implementation class
class ItemRepositoryImpl implements ItemRepositoryCustom {...}
If anyone have similar problems, start by following the naming standard that is used in the spring documentation at the link below.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
There is a well defined way to create custom repository implementations in Spring Data JPA which you should follow. Basically you need to extend CrudRepository so you don't have to inject an instance of it in your custom implementation.
I have solved problem by injecting ApplicationContext and getting bean in lazy way using applicationContext.getBean(UserRepository.class).
It works this way.
I found I way of how to do it without the need for #Autowire:
public interface UserRepository extends
UserRepositoryBasic,
UserRepositoryExtension
{
}
public interface UserRepositoryBasic extends
JpaRepository<User, String>
{
// standard Spring Data methods, like findByLogin
}
public interface UserRepositoryExtension
{
public void customMethod();
}
public class UserRepositoryExtensionImpl implements
UserRepositoryExtension
{
private final UserRepositoryBasic userRepositoryBasic;
// constructor-based injection
public UserRepositoryExtensionImpl(
UserRepositoryBasic userRepositoryBasic)
{
this.userRepositoryBasic = userRepositoryBasic;
}
public void customMethod()
{
// we can call all basic Spring Data methods using
// userRepositoryBasic
}
}
Well in this case I suggest to use the #Lazy annotation.
public class MyCustomRepositoryImpl implements MyCustomRepository {
#Lazy
#Autowired
private MyRepository myRepository;
#Override
public boolean customMethod() {
return myRepository.count() > 0;
}
}
With constructor parameter Spring tries to create the "basic" repository class which require you custom repository which requires you "basic" repository - the typical case with circular dependency.
Without #Lazy but with only the #Autowired it also won't work (there will be problem with factory bean for the basic repo).
I think in this case the #Lazy is the most elegant solution.
Say I need to rely on several implementations of a Spring bean. I have one AccountService interface and two implementations: DefaultAccountServiceImpl and SpecializedAccountServiceImpl.
How is this possible (injecting one or the other implementation) in Spring?
Which implementation will the following injection use?
#Autowired
private AccountService accountService;
Ad. 1: you can use #Qualifier annotation or autowire using #Resource as opposed to #Autowired which defaults to field name rather than type.
Ad. 2: It will fail at runtime saying that two beans are implementing this interface. If one of your beans is additionally annotated with #Primary, it will be preferred when autowiring by type.
#Autowired
#Qualifier("impl1")
BaseInterface impl1;
#Autowired
#Qualifier("impl2")
BaseInterface impl2;
#Component(value="impl1")
public class Implementation1 implements BaseInterface {
}
#Component(value = "impl2")
public class Implementation2 implements BaseInterface {
}
For full code: https://github.com/rsingla/springautowire/