#EnableConfigurationProperties(MyConfig.class) generated bean name does not work in spring-integration - spring

I have a config class with #ConfigurationProperties as follows. I am able to populate systemConfigMap from application.yaml in the MyConfig class as seen below
#ConfigurationProperties(prefix = "my-config")
#ConstructorBinding
#AllArgsConstructor
public class MyConfig {
/**
* A Configuration Map of multiple Systems
*/
private Map<String, SystemConfig> systemConfigMap;
}
the main class as
#EnableConfigurationProperties(MyConfig.class)
public class SpringApp {
public static void main(String[] args) {
SpringApplication.run(SpringApp.class, args);
}
}
The problem is that the generated bean name is my-config-a.b.c.config.MyConfig, which I am not able to use in payload-expression on spring integration http inbound gateway, I guess since it has "-" in it.
How can I specify the bean name for the generated bean MyConfig?
EDIT : HTTP Gateway Config
<int:channel id="myConfigListChannel" />
<int-http:inbound-gateway request-channel="myConfigListChannel"
path="/data"
error-channel="errorChannel"
supported-methods="GET"
payload-expression="#my-config-a.b.c.config.MyConfig.getSystemConfigMap().values()"
/>
I want to load the systemConfigMap values when /data is requested to start processing the flow.

When you try to use a complex bean id like yours my-config-a.b.c.config.MyConfig in the SpEL expression, you need to wrap it into the literal. Otherwise it understands an id until the first . which is treat as method/property reference to evaluate on a possible bean evaluate before.
So, it tries to find a bean like my-config-a and then tries to get access to its b property, which is fully false in your case.
To fix your problem you need to do like this:
payload-expression="#'my-config-a.b.c.config.MyConfig'.systemConfigMap.values()"
Another trick would be like your MyConfig injection into some bean with really meaningful bean name and use that one from the expression as a delegate.

Related

Spring to Spring boot Migration - No qualifying bean of type 'java.lang.String' error

I am working on migration of a spring project to spring boot. The spring project is using xml configuration for defining beans.
I want to use the same beans while migrating to springboot instead of generating the beans automatically. So I imported the xml file in my application.java file which contains the main method. When I run the springboot application, I am getting below error for one of the beans.
Error: Error creating bean with name 'validateAuthentication': Unsatisfied dependency expressed throuth field authenticateCloudHost No qualifying bean of type 'java.lang.string' available: expected single matching bean but found2: CONNECT_TIMEOUT, READ_TIMEOUT
authenticateCloudHost in the bean is a property which is getting a value from the application.properties file inside resource folder of the project. The code sample looks like below.
applicationContext.xml:
<bean id="validateAuthentication" class = "com.abc.JAXRSValidateAuthenticateAssociateClient>
<constructor-arg index="0" value = "${api.client.id}">
<constructor-arg index="1" value = "${api.client.password}">
<property name="authenticateCloudHost" value = "${api.client.cloud.host}">
<bean>
JAXRSValidateAuthenticateClient.java:
#Named
public class JAXRSValidateAuthenticateAssociateClient {
String id;
String password;
public JAXRSValidateAuthenticateAssociateClient (String id, String password) {
this .id= id
this.password = password
}
#Inject
private String authenticateCloudHost ;
public void setAuthenticateCloudHost(String authenticateCloudHost) {
this.authenticateCloudHost = authenticateCloudHost;
}
}
Application.java:
#SpringBootApplication
#ImportResource("classpath:applicationContext.xml")
public class Application {
public static void main (String[] args){
SpringAPplication.run(Application.class, args);
}
}
Any help will be highly appreciated.
You cannot inject an object of type string unless you have one in your context. I assume you wanted to inject a value form the configuration file. In general, it looks strange that the other two strings are injected as constructor parameters and field injection is used for the third one.
If you still want to inject 'api.client.cloud.host' property from your configuration file, you should use
#Value("${api.client.cloud.host}")
private String authenticateCloudHost;
annotation instead of #Inject
Though if you can change the code, I would rather recommend to add another parameter to your constructor and use constructor injection instead. You can either use the same annotation on the constructor parameter, or create the bean manually and inject the 'api.client.cloud.host' value at the class where you call constructor of you JAXRSValidateAuthenticateAssociateClient bean

How do I #Autowire to an extended class when #Qualifier is used in Spring?

I have the following classes:
public class Service
{
#Autowired
#Qualifier(Helper.BEAN_NAME)
protected Helper helper;
...
}
#Component(Helper.BEAN_NAME)
public class Helper
{
public static final String BEAN_NAME = "Helper";
...
}
#Component(Helper.BEAN_NAME)
public class ExtHelper extends Helper
{
...
}
My goal is to not touch the Service or Helper classes. My thinking is that by giving ExtHelper the same bean name as Helper, Spring will autowire ExtHelper implementation to Service instead of Helper.
I am seeing mixed results with this. If ExtHelper is included in my pom AFTER Helper, it works ok. But before, I get a ConflictingBeanDefinitionException. I understand the exception, but not why I get it if I swap the order of dependencies in the POM.
My basic question is whether I am doing this correctly conceptually. Is #Qualifier intended to prevent this kind of override of autowiring? If not, what is the rule to make Spring resolve the conflict by choosing my extension over the base class? Am I required to extend the Service class to get what I want? I am new to Spring and don't quite get how I am supposed to be doing this.
#Qualifier is intended to be used to instruct Spring which bean should be injected in case of multiple beans of type available.
In your case you have two beans that could be injected into protected Helper helper attribute so you have to tell Spring which one should be used. You can't do it with #Qualifier as both of the beans have the same name.
If you don't want to touch those classes you could use another annotation to prioritise a bean - #Primary. Add it on ExtHelper and it will be treated as a preferred bean in case of multiple bean available for injection.
If you want to stay with #Qualifier you would need to change name of one of those beans and inject preferred bean:
#Component
public class Service
{
#Autowired
#Qualifier("extHelper")
protected Helper helper; // instance of Helper or ExtHelper could be injected here
...
}
#Component // bean will be named using default naming strategy: helper. You can obviously use your own name
public class Helper
{
...
}
#Component // bean will be named using default naming strategy: extHelper. You can obviously use your own name
public class ExtHelper extends Helper
{
...
}

No qualifying bean of type [org.springframework.mail.javamail.JavaMailSender] while deploying service into PCF [duplicate]

Please explain the following about NoSuchBeanDefinitionException exception in Spring:
What does it mean?
Under what conditions will it be thrown?
How can I prevent it?
This post is designed to be a comprehensive Q&A about occurrences of NoSuchBeanDefinitionException in applications using Spring.
The javadoc of NoSuchBeanDefinitionException explains
Exception thrown when a BeanFactory is asked for a bean instance for
which it cannot find a definition. This may point to a non-existing
bean, a non-unique bean, or a manually registered singleton instance
without an associated bean definition.
A BeanFactory is basically the abstraction representing Spring's Inversion of Control container. It exposes beans internally and externally, to your application. When it cannot find or retrieve these beans, it throws a NoSuchBeanDefinitionException.
Below are simple reasons why a BeanFactory (or related classes) would not be able to find a bean and how you can make sure it does.
The bean doesn't exist, it wasn't registered
In the example below
#Configuration
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
ctx.getBean(Foo.class);
}
}
class Foo {}
we haven't registered a bean definition for the type Foo either through a #Bean method, #Component scanning, an XML definition, or any other way. The BeanFactory managed by the AnnotationConfigApplicationContext therefore has no indication of where to get the bean requested by getBean(Foo.class). The snippet above throws
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.Foo] is defined
Similarly, the exception could have been thrown while trying to satisfy an #Autowired dependency. For example,
#Configuration
#ComponentScan
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
}
}
#Component
class Foo { #Autowired Bar bar; }
class Bar { }
Here, a bean definition is registered for Foo through #ComponentScan. But Spring knows nothing of Bar. It therefore fails to find a corresponding bean while trying to autowire the bar field of the Foo bean instance. It throws (nested inside a UnsatisfiedDependencyException)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.Bar] found for dependency [com.example.Bar]:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
There are multiple ways to register bean definitions.
#Bean method in a #Configuration class or <bean> in XML configuration
#Component (and its meta-annotations, eg. #Repository) through #ComponentScan or <context:component-scan ... /> in XML
Manually through GenericApplicationContext#registerBeanDefinition
Manually through BeanDefinitionRegistryPostProcessor
...and more.
Make sure the beans you expect are properly registered.
A common error is to register beans multiple times, ie. mixing the options above for the same type. For example, I might have
#Component
public class Foo {}
and an XML configuration with
<context:component-scan base-packages="com.example" />
<bean name="eg-different-name" class="com.example.Foo />
Such a configuration would register two beans of type Foo, one with name foo and another with name eg-different-name. Make sure you're not accidentally registering more beans than you wanted. Which leads us to...
If you're using both XML and annotation-based configurations, make sure you import one from the other. XML provides
<import resource=""/>
while Java provides the #ImportResource annotation.
Expected single matching bean, but found 2 (or more)
There are times when you need multiple beans for the same type (or interface). For example, your application may use two databases, a MySQL instance and an Oracle one. In such a case, you'd have two DataSource beans to manage connections to each one. For (simplified) example, the following
#Configuration
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
System.out.println(ctx.getBean(DataSource.class));
}
#Bean(name = "mysql")
public DataSource mysql() { return new MySQL(); }
#Bean(name = "oracle")
public DataSource oracle() { return new Oracle(); }
}
interface DataSource{}
class MySQL implements DataSource {}
class Oracle implements DataSource {}
throws
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.example.DataSource] is defined:
expected single matching bean but found 2: oracle,mysql
because both beans registered through #Bean methods satisfied the requirement of BeanFactory#getBean(Class), ie. they both implement DataSource. In this example, Spring has no mechanism to differentiate or prioritize between the two. But such mechanisms exists.
You could use #Primary (and its equivalent in XML) as described in the documentation and in this post. With this change
#Bean(name = "mysql")
#Primary
public DataSource mysql() { return new MySQL(); }
the previous snippet would not throw the exception and would instead return the mysql bean.
You can also use #Qualifier (and its equivalent in XML) to have more control over the bean selection process, as described in the documentation. While #Autowired is primarily used to autowire by type, #Qualifier lets you autowire by name. For example,
#Bean(name = "mysql")
#Qualifier(value = "main")
public DataSource mysql() { return new MySQL(); }
could now be injected as
#Qualifier("main") // or #Qualifier("mysql"), to use the bean name
private DataSource dataSource;
without issue. #Resource is also an option.
Using wrong bean name
Just as there are multiple ways to register beans, there are also multiple ways to name them.
#Bean has name
The name of this bean, or if plural, aliases for this bean. If left
unspecified the name of the bean is the name of the annotated method.
If specified, the method name is ignored.
<bean> has the id attribute to represent the unique identifier for a bean and name can be used to create one or more aliases illegal in an (XML) id.
#Component and its meta annotations have value
The value may indicate a suggestion for a logical component name, to
be turned into a Spring bean in case of an autodetected component.
If that's left unspecified, a bean name is automatically generated for the annotated type, typically the lower camel case version of the type name. For example MyClassName becomes myClassName as its bean name. Bean names are case sensitive. Also note that wrong names/capitalization typically occur in beans referred to by string like #DependsOn("my BeanName") or XML config files.
#Qualifier, as mentioned earlier, lets you add more aliases to a bean.
Make sure you use the right name when referring to a bean.
More advanced cases
Profiles
Bean definition profiles allow you to register beans conditionally. #Profile, specifically,
Indicates that a component is eligible for registration when one or
more specified profiles are active.
A profile is a named logical grouping that may be activated
programmatically via
ConfigurableEnvironment.setActiveProfiles(java.lang.String...) or
declaratively by setting the spring.profiles.active property as a JVM
system property, as an environment variable, or as a Servlet context
parameter in web.xml for web applications. Profiles may also be
activated declaratively in integration tests via the #ActiveProfiles
annotation.
Consider this examples where the spring.profiles.active property is not set.
#Configuration
#ComponentScan
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
System.out.println(Arrays.toString(ctx.getEnvironment().getActiveProfiles()));
System.out.println(ctx.getBean(Foo.class));
}
}
#Profile(value = "StackOverflow")
#Component
class Foo {
}
This will show no active profiles and throw a NoSuchBeanDefinitionException for a Foo bean. Since the StackOverflow profile wasn't active, the bean wasn't registered.
Instead, if I initialize the ApplicationContext while registering the appropriate profile
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("StackOverflow");
ctx.register(Example.class);
ctx.refresh();
the bean is registered and can be returned/injected.
AOP Proxies
Spring uses AOP proxies a lot to implement advanced behavior. Some examples include:
Transaction management with #Transactional
Caching with #Cacheable
Scheduling and asynchronous execution with #Async and #Scheduled
To achieve this, Spring has two options:
Use the JDK's Proxy class to create an instance of a dynamic class at runtime which only implements your bean's interfaces and delegates all method invocations to an actual bean instance.
Use CGLIB proxies to create an instance of a dynamic class at runtime which implements both interfaces and concrete types of your target bean and delegates all method invocations to an actual bean instance.
Take this example of JDK proxies (achieved through #EnableAsync's default proxyTargetClass of false)
#Configuration
#EnableAsync
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
System.out.println(ctx.getBean(HttpClientImpl.class).getClass());
}
}
interface HttpClient {
void doGetAsync();
}
#Component
class HttpClientImpl implements HttpClient {
#Async
public void doGetAsync() {
System.out.println(Thread.currentThread());
}
}
Here, Spring attempts to find a bean of type HttpClientImpl which we expect to find because the type is clearly annotated with #Component. However, instead, we get an exception
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.example.HttpClientImpl] is defined
Spring wrapped the HttpClientImpl bean and exposed it through a Proxy object that only implements HttpClient. So you could retrieve it with
ctx.getBean(HttpClient.class) // returns a dynamic class: com.example.$Proxy33
// or
#Autowired private HttpClient httpClient;
It's always recommended to program to interfaces. When you can't, you can tell Spring to use CGLIB proxies. For example, with #EnableAsync, you can set proxyTargetClass to true. Similar annotations (EnableTransactionManagement, etc.) have similar attributes. XML will also have equivalent configuration options.
ApplicationContext Hierarchies - Spring MVC
Spring lets you build ApplicationContext instances with other ApplicationContext instances as parents, using ConfigurableApplicationContext#setParent(ApplicationContext). A child context will have access to beans in the parent context, but the opposite is not true. This post goes into detail about when this is useful, particularly in Spring MVC.
In a typical Spring MVC application, you define two contexts: one for the entire application (the root) and one specifically for the DispatcherServlet (routing, handler methods, controllers). You can get more details here:
Difference between applicationContext.xml and spring-servlet.xml in Spring Framework
It's also very well explained in the official documentation, here.
A common error in Spring MVC configurations is to declare the WebMVC configuration in the root context with #EnableWebMvc annotated #Configuration classes or <mvc:annotation-driven /> in XML, but the #Controller beans in the servlet context. Since the root context cannot reach into the servlet context to find any beans, no handlers are registered and all requests fail with 404s. You won't see a NoSuchBeanDefinitionException, but the effect is the same.
Make sure your beans are registered in the appropriate context, ie. where they can be found by the beans registered for WebMVC (HandlerMapping, HandlerAdapter, ViewResolver, ExceptionResolver, etc.). The best solution is to properly isolate beans. The DispatcherServlet is responsible for routing and handling requests so all related beans should go into its context. The ContextLoaderListener, which loads the root context, should initialize any beans the rest of your application needs: services, repositories, etc.
Arrays, collections, and maps
Beans of some known types are handled in special ways by Spring. For example, if you tried to inject an array of MovieCatalog into a field
#Autowired
private MovieCatalog[] movieCatalogs;
Spring will find all beans of type MovieCatalog, wrap them in an array, and inject that array. This is described in the Spring documentation discussing #Autowired. Similar behavior applies to Set, List, and Collection injection targets.
For a Map injection target, Spring will also behave this way if the key type is String. For example, if you have
#Autowired
private Map<String, MovieCatalog> movies;
Spring will find all beans of type MovieCatalog and add them as values to a Map, where the corresponding key will be their bean name.
As described previously, if no beans of the requested type are available, Spring will throw a NoSuchBeanDefinitionException. Sometimes, however, you just want to declare a bean of these collection types like
#Bean
public List<Foo> fooList() {
return Arrays.asList(new Foo());
}
and inject them
#Autowired
private List<Foo> foos;
In this example, Spring would fail with a NoSuchBeanDefinitionException because there are no Foo beans in your context. But you didn't want a Foo bean, you wanted a List<Foo> bean. Before Spring 4.3, you'd have to use #Resource
For beans that are themselves defined as a collection/map or array
type, #Resource is a fine solution, referring to the specific
collection or array bean by unique name. That said, as of 4.3,
collection/map and array types can be matched through Spring’s
#Autowired type matching algorithm as well, as long as the element
type information is preserved in #Bean return type signatures or
collection inheritance hierarchies. In this case, qualifier values can
be used to select among same-typed collections, as outlined in the
previous paragraph.
This works for constructor, setter, and field injection.
#Resource
private List<Foo> foos;
// or since 4.3
public Example(#Autowired List<Foo> foos) {}
However, it will fail for #Bean methods, ie.
#Bean
public Bar other(List<Foo> foos) {
new Bar(foos);
}
Here, Spring ignores any #Resource or #Autowired annotating the method, because it's a #Bean method, and therefore can't apply the behavior described in the documentation. However, you can use Spring Expression Language (SpEL) to refer to beans by their name. In the example above, you could use
#Bean
public Bar other(#Value("#{fooList}") List<Foo> foos) {
new Bar(foos);
}
to refer to the bean named fooList and inject that.

autowire byType according to Spring 4.1.6 to Documentation

Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set. - FROM SPRING REFERENCE GUID 4.1.6
<bean id="person" class="autowire.Person" autowire="byType" />
<bean id="invisible" class="autowire.Ability" >
<property name="skill" value="Invisible" />
</bean>
<bean id="invisible2" class="autowire.Ability" >
<property name="skill" value="Invisible" />
</bean>
Class Definitions:
package autowire;
public class Person
{
private Ability ability;
//...
}
package autowire;
public class Ability {
private String skill;
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
I was able to define 2 beans of same type of class "autowire.Ability". I didnt get the Fatal exception. Is my understanding correct ?
You're almost there (to get the error). You need to tell spring which class attributes need to be autowired. Annotate Person.ability with #Autowired and you should get the error.
import org.springframework.beans.factory.annotation.Autowired;
public class Person
{
#Autowired
private Ability ability;
//...
}
Or even better create a constructor and autowire it, as injecting attributes is considered a bad practice.
public class Person
{
private Ability ability;
#Autowired
public Person(Ability ability) {
this.ability = ability;
}
//...
}
Spring doesn't assume which attributes need to be injected (autowired) so you need to specify which ones you want to inject.
The behavior you're seeing is correct, you can define as many beans of the same type as you want, problem arises when an Autowired bean(Component, Service, etc), expects a dependency of certain type and it cannot resolved because there are many that matches the field definition, for example:
If Person is declared as a #Component and declare an #Autowired field of type Ability, for example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class Person {
#Autowired
private Ability ability;
}
Having the two beans invisible and invisible2 would cause the expected exception because Spring won't be able to know which of the two beans need to be injected in Person.
To run this example you will need to enable a Scan application context.
Hope this helps,
José Luis

Spring 3 Autowire Bean which uses an Interface

I have an Bean configured in my dispatcher-servlet.xml. In a class i can successfully inject this bean with the autowired annotation e.g.
class test {
#Autowired
TestBean testBean;
}
But as soon i add an interface with the "implements" keyword to the testbean, i get an IllegalArgumentException:
java.lang.IllegalArgumentException: Can not set com.test.TestBean field com.test.myclass.testBean to com.sun.proxy.$Proxy26.
When in remove the "implements" keyword, including the name of the interface, all works fine again.
You would need to provide more details, like the interface type and your context configuration, but the reason is the following. Spring, by default, uses JDK proxies to add AOP or decorator behavior, for example, for #Transactional or #Async.
JDK proxies only work with interface types, not with class types. Take this example
public class Driver {
public static void main(String[] args) throws Exception {
final Example example = new Example();
Proxied proxy = (Proxied) Proxy.newProxyInstance(Driver.class.getClassLoader(), example.getClass().getInterfaces(), new InvocationHandler() {
Example target = example;
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("intercepted");
return method.invoke(example, args);
}
});
proxy.execute();
System.out.println(proxy.getClass());
System.out.println(proxy.getClass().getSuperclass());
System.out.println(Arrays.toString(proxy.getClass().getInterfaces()));
}
static class Example implements Proxied {
#Override
public void execute() {
System.out.println("Example executing.");
}
}
static interface Proxied {
void execute();
}
}
which prints
intercepted
Example executing.
class com.spring.$Proxy0
class java.lang.reflect.Proxy
[interface com.spring.Driver$Proxied]
For the purpose of this example, Spring will take the Example bean (declared in a context), decide that it needs to proxy it, use the Example class' interfaces, and create whatever InvocationHandler it needs by referring to the bean as the target to invoke the method on.
What you need to take note of is that the object that is returned by Proxy.newProxyInstance(..) is not of type Example. It is of type Proxy and of whatever type the interfaces of Example are. That is why Spring cannot use the proxy object to set a field (through reflection) of type Example, or TestBean in your case.
Two ways to make it work. First, extract an interface from your class, if it doesn't have one already and use a field of the interface type.
Second, you can instead configure your context to use CGLIB proxies which can proxy by class type.
in XML:
<bean id="test" class="your.package.Test"/>
make sure Test is in your spring bean XML, you then can do
#Autowired
Test test;
test.testBean.doAnything();
thing to notice here is that you HAVE to intatiate your Test class.

Resources