Spring configuration class to inject bean as property - spring

I am having a spring configuration class which I am using to read from properties file and create the beans.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#PropertySource("classpath:conf.properties")
public class ApplicationConfiguration {
#Value("${name}")
private String username;
#Value("${password}")
private String password;
#Value("${ethnicity}")
private String ethnicity;
#Bean
public Employee employee(){
Employee emp = new Employee();
ConfigParam configParam = new ConfigParam();
configParam.setEthnicity(ethnicity);
emp.setConfigParam(configParam);
return emp;
}
}
Inside the xml file
<property name="configParam">
<bean class="com.test.config.ConfigParam">
<property name="ethnicity" value="indian" />
</bean>
</property>
I am able to set the username and password properties but unable to set the configParam attribute to employee since we need to inject the ConfigParamand its a bean. Please let me know how to inject a bean inside the employee method.

Assuming that your Spring XML context that includes the configParam definition is called my-spring-context.xml and is found in a resources/spring folder, in other words in a spring folder in your classpath (name and folder are arbitrary):
Make your ApplicationConfiguration configuration class aware of that XML context file by using the #ImportResource annotation:
#Configuration
#ImportResource("classpath:spring/my-spring-context.xml")
#PropertySource("classpath:conf.properties")
public class ApplicationConfiguration {
//...
}
Then in your employee method dependency-inject the XML bean as usual. If you want to inject by name and not by type you can add the #Qualifier("myBeanName") directly prior the configParam argument definition.
#Bean
#Autowired
public Employee employee(ConfigParam configParam){
Employee emp = new Employee();
configParam.setEthnicity(ethnicity);
emp.setConfigParam(configParam);
return emp;
}

Related

Spring Boot: Autowiring app credentials within custom autoconfiguration bean returns null

I am working with a custom AWS Simple System Management client just to avoid the original from using the default AWS authentication chain, so I placed my class in /META-INF/spring.factories and excluded the original from being autconfigured in bootstrap.yml . What I'm facing right now is to get the credentials from application.yml and pass them to my new conf, but when I try to autowire them all I get is null. I wonder if there is any way to achieve it
Here is the code:
package es.example;
import lombok.*;
import org.springframework.boot.context.properties.*;
#ConfigurationProperties(prefix = "aws.credentials")
#Data
public class CustomAWSSSMAuthProperties {
private String accessKey;
private String secretKey;
}
package es.example;
import com.amazonaws.services.simplesystemsmanagement.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.context.properties.*;
#EnableConfigurationProperties(CustomAWSSSMAuthProperties.class)
public class CustomAWSSSMClient extends AWSSimpleSystemsManagementClient {
#Autowired
private CustomAWSSSMAuthProperties customProperties;
public CustomAWSSSMClient() {
String accessKey = customProperties.getAccessKey();
String secretKey = customProperties.getSecretKey();
}
}
/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
es.example.CustomAWSSSMClient
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
es.example.CustomAWSSSMClient
bootstrap.yml
spring:
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
autoconfigure.exclude: com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClient
Many thanks
#ConfigurationProperties does not create a bean like #Configuration or #Component does. In your case CustomAWSSSMAuthProperties type bean/object will not be instantiated in the Spring context.
Generally #ConfigurationProperties is used with #Configuration or #Bean to bind the some properties to the bean.
You can annotate CustomAWSSSMAuthProperties with #Configuration to fix the issue.

How to create beans dynamically in spring custom starter based on property

I am writing a custom spring starter, in which I need to register a list of beans of same type based on the property defined in the application.properties
i have following properties in application.properties
mybean.names = mybean1, mybean2
mybean1.foo = foo1
mybean2.foo = foo2
mybean1.bar = bar1
mybean2.bar = bar2
Current implementation of autoconfiguration class is below
#Configuration
#ConditionalOnClass(MyBeanFactory.class)
public class MyBeanAutoConfiguration {
#Autowire
Environemnt evn;
#Bean(name = {"mybean1"})
public MyBean getBean() {
String[] names = StringUtils.commaDelimitedListToStringArray(evn.getProperty("mybean.names"));
MyBean mybean = new Mybean(evn.getProperty(names[0] + ".foo"),
evn.getProperty(names[0] + ".bar"));
return myBean;
}
}
And i want to simply autowire with qualifer my bean in spring boot application like below
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplication {
#Autowired
#Qualifer("mybean1")
MyBean mybean;
public static void main(String[] args) {
SpringApplication.run(VaultApplication.class, args);
}
How can i change my autoconfigure class to create multiple beans with different names defined in the properties file(in this case how can I create bean mybean2) so that i can use simply autowire with qualifier ?
I am not sure that i understood you question but if you want to have several bean with different name so best way is writing multiple #Bean method in your configuration class with different name, so you can autowire each one of them by #Qualifer

#Autowired not working in spring Integration

In service implementation,with help of #Autowired i am injecting CollectInfo object in serviceImpl but i am getting NullPointerException.
package net.group.cts.service.serviceImpl;
#Service
public class EmployeeImpl implements EmployeeService {
#Autowired
CollectInfo info;
public void processData(){
info.getName();
}
}
package net.group.cts.model;
#Component
public class CollectInfo (){
String name;
public String getName(){
name = name + "Mr.";
return name;}
}
}
Xmlconfig.xml
<context:annotation-config/>
<context:component-scan base-package="net.group.cts"/>
<bean id="info" class="net.group.emp.model.CollectInfo "/>
You cannot inject a bean in a class if this class is not a Spring bean.
EmployeeImpl is not annotated with any Spring bean stereotype such as #Component or #Service.
Add one of them on EmployeeImpl and ensure that the two classes are located inside the package scanned by Spring <context:component-scan base-package="net.group.emp.service"/>
and it should be ok.
Besides, both annotating a bean with #Component :
#Component
public class CollectInfo (){...}
and configuring it in the Spring xml configuration :
<bean id="info" class="net.group.emp.model.CollectInfo "/>
is redundant. It will finally create two beans : one name collectInfo and another named info.
I advise you to favor annotation over xml configuration as it is possible (it is the very most of cases).

How to pass a Map<String, String> with application.properties

I have implemented some authorization in a webservice that needs be configured.
Currently the user/password combo is hardcoded into the bean configuration. I would like to configure the map with users and passwords into the application.properties so the configuration can be external.
Any clue on how this can be done?
<bean id="BasicAuthorizationInterceptor" class="com.test.BasicAuthAuthorizationInterceptor">
<property name="users">
<map>
<entry key="test1" value="test1"/>
<entry key="test2" value="test2"/>
</map>
</property>
</bean>
you can use #Value.
Properties file:
users={test1:'test1',test2:'test2'}
Java code:
#Value("#{${users}}")
private Map<String,String> users;
You can use #ConfigurationProperties to have values from application.properties bound into a bean. To do so you annotate your #Bean method that creates the bean:
#Bean
#ConfigurationProperties
public BasicAuthAuthorizationInterceptor interceptor() {
return new BasicAuthAuthorizationInterceptor();
}
As part of the bean's initialisation, any property on BasicAuthAuthorizationInterceptor will be set based on the application's environment. For example, if this is your bean's class:
public class BasicAuthAuthorizationInterceptor {
private Map<String, String> users = new HashMap<String, String>();
public Map<String, String> getUsers() {
return this.users;
}
}
And this is your application.properties:
users.alice=alpha
users.bob=bravo
Then the users map will be populated with two entries: alice:alpha and bob:bravo.
Here's a small sample app that puts this all together:
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) throws Exception {
System.out.println(SpringApplication.run(Application.class, args)
.getBean(BasicAuthAuthorizationInterceptor.class).getUsers());
}
#Bean
#ConfigurationProperties
public BasicAuthAuthorizationInterceptor interceptor() {
return new BasicAuthAuthorizationInterceptor();
}
public static class BasicAuthAuthorizationInterceptor {
private Map<String, String> users = new HashMap<String, String>();
public Map<String, String> getUsers() {
return this.users;
}
}
}
Take a look at the javadoc for ConfigurationProperties for more information on its various configuration options. For example, you can set a prefix to divide your configuration into a number of different namespaces:
#ConfigurationProperties(prefix="foo")
For the binding to work, you'd then have to use the same prefix on the properties declared in application.properties:
foo.users.alice=alpha
foo.users.bob=bravo
A java.util.Properties object is already a Map, actually a HashTable which in turn implements Map.
So when you create a properties file (lets name it users.properties) you should be able to load it using a PropertiesFactoryBean or <util:properties /> and inject it into your class.
test1=test1
test2=test2
Then do something like
<util:properties location="classpath:users.properties" id="users" />
<bean id="BasicAuthorizationInterceptor" class="com.test.BasicAuthAuthorizationInterceptor">
<property name="users" ref="users" />
</bean>
Although if you have a Map<String, String> as a type of the users property it might fail... I wouldn't put them in the application.properties file. But that might just be me..
I think you are looking for something similar
http://www.codejava.net/frameworks/spring/reading-properties-files-in-spring-with-propertyplaceholderconfigurer-bean
You can pick values from .properties similarly and assign it to your map.

Where to store config info for spring mvc 3.x

Where is a good place to store custom config info in spring mvc 3.x and how would I access that info globally via any controller?
Is there a built in config manager?
I assume 'custom config' means a configuration file the code reads / you / your operations team can update?
One easy solution is to use spring beans xml configuration file and deploy your war in exploded fashion.
Create a configuration java class:
// File: MyConfig.java ------------------------------------
public class MyConfig {
private String supportEmail;
private String websiteName;
// getters & setters..
}
Configure the class as a Spring bean and set its properties on your spring beans xml file (can also create a new file and use <import resource="..."/>):
// File: root-context.xml ----------------------------------------
<beans ...>
...
<bean class="com.mycompany.MyConfig">
<property name="supportEmail" value="support#mycompany.com"/>
<property name="websiteName" value="Hello Site"/>
</bean>
...
</beans>
Inject your configuration class (eg: in a controller)
// File: HelloController.java ------------------------------------
#Controller
#RequestMapping("/hello")
public class HelloController {
#Autowired MyConfig config;
// ...
}
However updates to the configuration would require re-deploy / server restarts
You can also use <context:property-placeholder>.
It looks like this.
myapp.properties:
foo=bar
spring beans xml:
<context:property-placeholder location="classpath:myapp.properties"/>
Or
<context:property-placeholder location="file:///path/to/myapp.properties"/>
Controller:
import org.springframework.beans.factory.annotation.Value;
...
#Controller
public class Controller {
#Value("${foo}")
private String foo;
If you want to get properties programmatically, you can use Environment with #PropertySource.
Configuration:
#Configuration
#PropertySource("classpath:myapp.properties")
public class AppConfig {
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Controller:
#Controller
public class Controller {
#Value("${foo}")
private String foo;
#Autowired
private Environment env;
#RequestMapping(value = "dosomething")
public String doSomething() {
env.getProperty("foo");
...
}
Hope this helps.

Resources