spring IOC qualifier and autowired strange behavior - java

I've specified Qualifier on both autowired et bean method.
So What am i missing ?
#Configuration
#EnableWebSecurity
public class CustomSecurityCOnfig {
#Bean
#Qualifier("entryPoint")
AuthenticationEntryPoint loginUrlAuthenticationEntryPoint() {
return new LoginUrlAuthenticationEntryPoint("/login");
}
}
I autowire the field this way
#Autowired
#Qualifier("entryPoint")
private AuthenticationEntryPoint loginUrlAuthenticationEntryPoint;
Stacktrace of the error :
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.core.env.Environment' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1716) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1272) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
EDIT
I Have another implementation of AuthenticationEntryPoint interface :
#Component
public class CustomAuthenticationEntryPoint extends BasicAuthenticationEntryPoint
But in my opinion it doesn't explain the error (as long as i specify the qualifiers)

You're mixing bean name and Qualifier
#Bean(name="someFancyBean")
public ClassXyx fooBar(){
return new ClassXyz()
}
In this example, method fooBar creates a bean of type ClassXyx and it's named someFancyBean. If you want to auto-wire this bean then you have to use
#Service
class SomeFancyService{
#Autowired #Qualifier("someFancyBean") ClassXyx xyz;
}
A configuration class can create multiple beans of the same type but their names are derived from function name. There's no point in using Bean annotation with name="XYZ" unless you want to rename that bean.
The Qualifier annotation is used for referring one of the beans of the same type.
Now coming back to your code
#Configuration
#EnableWebSecurity
public class CustomSecurityCOnfig {
#Bean
public AuthenticationEntryPoint entryPoint() {
return new LoginUrlAuthenticationEntryPoint("/login");
}
}
In your service you have to Autowired as.
#Autowired
#Qualifier("entryPoint")
private AuthenticationEntryPoint loginUrlAuthenticationEntryPoint;
Also, I would like to point one more thing bean accessibility across package/class.
Generally, all beans created by Spring IOC are public, but it has the same access modifier like Java classes. If you're creating a bean with package scope then you can't auto-wire in another package. Similarly, if a bean is created using private then that bean can be only auto-wired in that class.

Related

Spring : Unsatisfied dependency expressed through field, CrudRepository extended interface

I have extended CrudRepository<ClassName, Id> in user defined Interface, but while trying to inject using #Autowired i am getting following given below error :
creating bean with name 'helloController': Unsatisfied dependency
expressed through field 'danCorePrivateRepository'; nested exception
is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'com.sgcorp.repository.DanCorePrivateRepository' available: expected
at least 1 bean which qualifies as autowire candidate.
HelloController.java
#RestController
#RequestMapping("/hello")
public class HelloController {
#Autowired
private DanCorePrivateRepository danCorePrivateRepository;
#RequestMapping(value = "/service", method= RequestMethod.GET)
public String selectService(){
String result = "<html>";
result += "<div>"+danCorePrivateRepository.findAll()+"</div>";
return result+ "</html>";
}
}
DanCorePrivateRepository.java (user defined interface)
public interface DanCorePrivateRepository extends CrudRepository<DanaModel, String> {
}
Kindly suggest why its not #Autowired properly?
Note: with some other project it was working.
Please add the #EnableJpaRepositories annotation on top on your configuration class. This #EnableJpaRepositories annotation has the basePackages or basePackageClasses attribute, through which you can specify the packages (which are annotated with #Repository) to be scanned by Spring Data JPA.
I think you have missed annotations #RepositoryRestResource and #Repository on your user defined Interface DanCorePrivateRepository. You have to mark it as follows -
#Repository
#RepositoryRestResource
public interface DanCorePrivateRepository extends CrudRepository<DanaModel, String> {
}
#RepositoryRestResource annotation will direct Spring to create RESTful endpoints for your repository.

Spring - No default constructor found

I have a class which looks like this:
#Service("myService")
public class MyServiceImpl {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
and I also have a test class which looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
MyServiceImpl.class})
...
I get this exception:
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not autowire
field: private org.springframework.messaging.simp.SimpMessagingTemplate
myPackage.MyServiceImpl.simpMessagingTemplate; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.messaging.simp.SimpMessagingTemplate] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Does anyone know what I can do in order to get it work, SimpMessagingTemplate does not have a default constructor.
SimpMessagingTemplate seems to have either no default constructor or is not annotated with #Component (or #Service or another sub-class of #Component); or both.
Please check that a default constructor is available and the class is configured to be a Spring bean.
Its not related to missing constructor, but Spring fails to find proper bean to inject into your test class,
Two options to solve it as I see
#ContextConfiguration(classes = {
MyServiceImpl.class, SimpMessagingTemplate.class})
Add #mock SimpMessagingTemplate simpMessagingTemplate; to your test class

How to Autowired in ConversionService in springboot

Trying to access the ConversionControl in model in springboot, no luck.
#Component
public class CityHelperService {
#Autowired
ConversionService conversionService;// = ConversionServiceFactory.registerConverters();
public City toEntity(CityDTO dto){
City entity = conversionService.convert(dto, City.class);
return entity;
}
public CityDTO toDTO(City entity){
CityDTO dto = conversionService.convert(entity, CityDTO.class);
return dto;
}
}
It shows the following error:
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.lumiin.mytalk.model.CityModel com.lumiin.mytalk.controllers.CityController.cityModel;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cityModel' defined in file : Unsatisfied dependency expressed through constructor argument with index 1 of type [com.lumiin.mytalk.dao.CityHelperService]: : Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)};
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cityHelperService': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.core.convert.ConversionService com.lumiin.mytalk.dao.CityHelperService.conversionService;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Apparently there is no ConversionService bean available, judging by the last nested exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.core.convert.ConversionService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
A look into the Spring documentation reveals, that you should declare a ConversionService bean. In the XML configuration it would look like this:
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="example.MyCustomConverter"/>
</set>
</property>
</bean>
And since you're using Spring Boot, I assume you are creating the context programatically, so you should create a method annotated with #Bean, which returns a ConverstionService, like this (explained here):
#Bean(name="conversionService")
public ConversionService getConversionService() {
ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
bean.setConverters(...); //add converters
bean.afterPropertiesSet();
return bean.getObject();
}
Not totally agreed with the accepted answers, because there would be a default ConverstionService named mvcConversionService so you would get duplicate bean exception. Instead addConverter to FormatterRegistry, here is the link for the part answer:
Java Config equivalent for conversionService / FormattingConversionServiceFactoryBean
Also you would need (in some cases) to define to at least an empty Component for ConversionService, something like below:
#Component #Primary
public class MyConversionService extends DefaultConversionService implements ConversionService {
// an empty ConversionService to initiate call to register converters
}
This is to force spring container to initiate a call to:
class WebMvcConfigurerAdapter {
...
public void addFormatters(FormatterRegistry registry) {
//registry.addConverter(...);
}
}
Existing answers didn't work for me:
Customizing via WebMvcConfigurerAdapter.addFormatters (or simply annotating the converter with #Component) only works in the WebMvc context and I want my custom converter to be available everywhere, including #Value injections on any bean.
Defining a ConversionService bean (via ConversionServiceFactoryBean #Bean or #Component) causes Spring Boot to replace the default ApplicationConversionService on the SpringApplication bean factory with the custom bean you've defined, which will probably be based on DefaultConversionService (in AbstractApplicationContext.finishBeanFactoryInitialization). The problem is that Spring Boot adds some handy converters such as StringToDurationConverter to the standard set in DefaultConversionService, so by replacing it you lose those conversions. This may not be an issue for you if you don't use them, but it means that solution won't work for everyone.
I created the following #Configuration class which did the trick for me. It basically adds custom converters to the ConversionService instance used by Environment (which is then passed on to BeanFactory). This maintains as much backwards compatibility as possible while still adding your custom converter into the conversion services in use.
#Configuration
public class ConversionServiceConfiguration {
#Autowired
private ConfigurableEnvironment environment;
#PostConstruct
public void addCustomConverters() {
ConfigurableConversionService conversionService = environment.getConversionService();
conversionService.addConverter(new MyCustomConverter());
}
}
Obviously you can autowire a list of custom converters into this configuration class and loop over them to add them to the conversion service instead of the hard-coded way of doing it above, if you want the process to be more automatic.
To make sure this configuration class gets run before any beans are instantiated that might require the converter to have been added to the ConversionService, add it as a primary source in your spring application's run() call:
#SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(new Class<?>[] { MySpringBootApplication.class, ConversionServiceConfiguration.class }, args);
}
}
If you don't do this, it might work, or not, depending on the order in which your classes end up in the Spring Boot JAR, which determines the order in which they are scanned. (I found this out the hard way: it worked when compiling locally with an Oracle JDK, but not on our CI server which was using a Azul Zulu JDK.)
Note that for this to work in #WebMvcTests, I had to also combine this configuration class along with my Spring Boot application class into a #ContextConfiguration:
#WebMvcTest(controllers = MyController.class)
#ContextConfiguration(classes = { MySpringBootApplication.class, ConversionServiceConfiguration.class })
#TestPropertySource(properties = { /* ... properties to inject into beans, possibly using your custom converter ... */ })
class MyControllerTest {
// ...
}

How to change the property signUpUrl in ProviderSignInController in Spring Boot

In short
I need to change the property value of a bean defined in the auto configuration of the spring boot, which is not available to configure from application.properties
Descriptive
I want to change the signUpUrl of the bean ProviderSignInController. This is not available to change in the properties file according to the documentation.
http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
So I did somthing like this.
#Configuration
public class SomeConfig {
#Autowired
public void configureProviderSignInController(ProviderSignInController signInController){
signInController.setSignUpUrl("/register");
}
and ended up with the following error
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.social.connect.web.ProviderSignInController] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1301)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1047)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
But according to the autoconfiguration this bean should be available
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/social/SocialWebAutoConfiguration.java
Please help and guild me if I'm doing this incorrectly.
The error describes that the problem is that you have not instantiated a bean with the type of ProviderSignInController in your method signature for configureProviderSignInController. Instead, you need to instantiate and configure the controller in one of your configurations with the proper constructor signatures required by the controller:
#Configuration
#EnableSocial
public class SocialConfig implements SocialConfigurer {
...
#Bean
public ProviderSignInController providerSignInController(
ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository) {
ProviderSignInController controller = new ProviderSignInController(
connectionFactoryLocator, usersConnectionRepository,
new SimpleSignInAdapter());
controller.setSignUpUrl("/register");
return controller;
}
}
Alternatively, if you are using XML configurations:
<bean class="org.springframework.social.connect.signin.web.ProviderSignInController">
<!-- relies on by-type autowiring for the constructor-args -->
<property name="signUpUrl" value="/register" />
</bean>
For more information, consult the Spring Social docs on enabling provider sign in.

Two beans with the same name results in ConflictingBeanDefinitionException despite using #Primary

I have an application initializer class that is used to insert application specific data to database.
#Component("applicationInitializer")
public class ApplicationInitializer {
#PostConstruct
public void init(){
// some clever code here
}
}
There is also DevApplicationInitializer class that is used to initialize database with some sample data on developer machine (this class is excluded when deploying production code).
#Component("applicationInitializer")
#Primary
public class DevApplicationInitializer extends ApplicationInitializer {
#PostConstruct
#Override
public void init(){
super.init();
// even more clever code here
}
}
Until I have given a name for the beans (only the #Component annotations) - everything worked fine - when DevApplicationInitializer was available, it was instantiated instead of ApplicationInitializer. When I gave them an applicationInitializer name, the exception is being thrown:
org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'applicationInitializer' for bean class
[com.example.DevApplicationInitializer] conflicts with existing, non-compatible
bean definition of same name and class [com.example.ApplicationInitializer]
Why the #Primary annotation is not respected when beans have name? I need them to have one, because I ensure in other place that the initializer has been instantiated with #DependsOn("applicationInitializer") annotation.
#Primary has no relation to bean names. The javadoc states
Indicates that a bean should be given preference when multiple
candidates are qualified to autowire a single-valued dependency.
This only applies to a context containing two beans of some type A where a bean of type B requires an A to be injected. The A bean annotated with #Primary will have priority.
Bean ids/names for a given type must be unique. (Bean definitions with the same name can overwrite each other for the same bean type. For example, this would happen if you component scanned a class annotated with #Component but also provided a #Bean method for that same type.)

Categories

Resources