Spring Dependency Injection with anotaation in constructor with parameter - spring

I have below Spring class which I want to load with Spring DI. With default-constructor it's working as expected but can anyone tell me the annotation details and syntax with constructor with string arguments. This string arguments are run time.
I have tried with XML configuration "constrctor args" and working as expected.
public someclass(String hostName, int port, String user, String password) {
this.user = user;
this.password = password;
}

I assume your fields(hastName, port, user and password) are coming from properties file like for a server configuration.
#Component
public class SomeClass {
#Autowired
public someclass(#Value("${server.hostName}") String hostName, #Value("${server.port}") int port, #Value("${server.user}") String user, #Value("${server.passowrd}") String password ) {
this.user = user;
this.password = password;
}
}
If your params aren't static values, you would use programmatic way.
You need to autowire application context before you create instance of your bean.
#Autowired
private ApplicationContext ctx;
Then, create your bean instance and register it to application context,
BeanDefinitionRegistry registry = ((BeanDefinitionRegistry) ctx.getFactory());
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(SomeClass.class);
beanDefinition.setLazyInit(false);
beanDefinition.setAbstract(false);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setScope("singleton"); // you should deal your scope.
ConstructorArgumentValues constructor = beanDefinition.getConstructorArgumentValues();
constructor.addIndexedArgumentValue(0, hostName);
constructor.addIndexedArgumentValue(1, port);
constructor.addIndexedArgumentValue(3, user);
constructor.addIndexedArgumentValue(4, password);
String beanName = "someclass"; // give a name to your bean
BeanComponentDefinition definition = new BeanComponentDefinition(beanDefinition, beanName);
BeanDefinitionReaderUtils.registerBeanDefinition(definition, registry);
Be careful while dealing your bean scope. You may use request or session scope according your structure.
At last, you can autowire SomeClass in other classes;
#Autowired
public SomeClass someClass;

Related

AutoWired getProperty returning null

I have 2 classes in which i am getting the getProperty of autowired class as null
I will post my classes and explain the problem below
I have used autowiring but i am getting my output as null
Connection.java
#Component
public class Connection {
private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Connection.class);
Logger basiclogger = Logger.getLogger("Main");
public CloseableHttpClient httpClient;
public static String Server;
public static String service;
public static String User;
public static String Password;
#Autowired
public Connection(#Value("${Server}") String Server, #Value("${service}") String service,
#Value("${User}") String User,#Value("${Password}") String Password)
{
Connection.Server = Server;
Connection.service = service;
Connection.User = User;
Connection.Password = Password;
}
public Connection(){
}
public CloseableHttpClient getHttpClient() {
return httpClient;
}
public void setHttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient;
}
public CloseableHttpClient makeConnection() {
AuthenticatedClientBuilder builder = AuthenticatedClientBuilder.create(serviceProvider)
.addServer(Server).setUser(User)
.setPassword(Password);
httpClient = builder.build();
basiclogger.info("Connection is Established SuccessFully");
return httpClient;
}
}
}
In Spring XML
<bean id="conn" class="com.java.Connection"
scope="prototype"/>
In Main
#Autowired(required = true)
Connection connection;
new ClassPathXmlApplicationContext(new String[] {"Spring-batch-context.xml"});
Connection connection = (Connection)context.getBean("conn");
connection.getHttpClient();
System.out.println("***********"+connection.getHttpClient()+"***********");
But i am getting connection.getHttpClient() as null
Can someone please help me
Thanks in advnace!!!!!!!!
From :
Connection connection = (Connection)context.getBean("conn");
Remove #Autowired on Connection in main method and change to:
#Autowired
BeanFactory beanFactory;
Connection connection = beanFactory.getBean(Connection.class, "args");
#Scope(value = "prototype") means that Spring will not instantiate the bean right on start, but will do it later on demand.
Update:
Here is the Javadoc of beanFactory.getBean()
getBean(java.lang.Class<T> requiredType, java.lang.Object... args)
throws BeansException
Return an instance, which may be shared or independent, of the specified bean.
Allows for specifying explicit constructor arguments / factory method
arguments, overriding the specified default arguments (if any) in the
bean definition.
This method goes into ListableBeanFactory by-type lookup territory but
may also be translated into a conventional by-name lookup based on the
name of the given type. For more extensive retrieval operations across
sets of beans, use ListableBeanFactory and/or BeanFactoryUtils.
Parameters:
requiredType - type the bean must match; can be an interface or superclass
args - arguments to use when creating a bean instance using explicit arguments
Returns: an instance of the bean
Throws:
NoSuchBeanDefinitionException - if there is no such bean definition
BeanDefinitionStoreException - if arguments have been given but the affected bean isn't a prototype
BeansException - if the bean could not be created
Further, read here: BeanFactory

CacheBuilder Initialization in constructor do not use Spring annotation value

I'm working on a functionality which works with google reCaptcha. During tests there is something wrong with CacheBuilder: expireAfterWrite value is always set = 0 (14400 is declared in anntoation and in application-test.properities as well). As i suppose something is wrong becouse it is initialized in constructor. Is there any other way to initialize it?
public class RecaptchaService {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final RestTemplate restTemplate;
#Value("${recaptcha.url:}")
private String recaptchaUrl;
#Value("${recaptcha.secret:#{null}}")
private String recaptchaSecret;
#Value("${recaptcha.fail.silent:false}")
private boolean recaptchaFailSilent;
#Value("${recaptcha.failAttempts.expire:14400}")
private int recaptchaAttemptExpire;
#Value("${recaptcha.failAttempts.max:4}")
private int maxAttempts;
private LoadingCache<String, Integer> attemptsCache;
private int attempts;
public RecaptchaService(final RestTemplate restTemplate) {
this.restTemplate = restTemplate;
attemptsCache = CacheBuilder.newBuilder()
.expireAfterWrite(recaptchaAttemptExpire, TimeUnit.SECONDS)
.build(new CacheLoader<String, Integer>() {
#Override
public Integer load(final String key) {
return 0;
}
});
}
}
Sounds like RecaptchaService isn't being managed by spring. I don't see a #Component annotation. I'm surpised the #Value annotations work at all in an un-managed bean!
If you let spring manage the life-cycle of RecaptchaService then those values will be available in the constructor.
We will assume that there is an #Component, or equivalent, annotation on your service.
In fact during the construction of your object, values are not yet injected. Then in your constructor recaptchaAttemptExpire equals to 0 (even if you set a default injection value).
As it seems to be a Service, then try to intialize your attemptsCache field during a #PostConstruct method maybe?

Bean initialization with no-default constructor and final fields in Spring Boot

In ConfigurationProperties class I have a Map like this:
#ConfigurationProperties(prefix = "some")
public class SomeConfigurationProperties {
private Map<String, SomeClass> map = new HashMap<>();
...
}
And I want in mentioned SomeClass all fields to be final, so I had to implement no-default constructor and I am fine with that. The one who is not, is spring initializer, so before starting application, I got this error:
Caused by: java.lang.NoSuchMethodException: some.package.SomeClass.<init>()
I can't set default constructor in SomeClass cause I will get final fields uninitialized:
The blank final field somefield may not have been initialized
How I should setup initialization of bean SomeClass with no-default constructor, but if it can be without XML Spring configuration, because I am using Spring Boot and don't want to mess up with that.
UPDATED: Example of SomeClass:
public class SomeClass {
private final int field1;
private final String field2;
// no default constructor
public SomeClass(field1, field2) {
this.field1 = field1;
this.field2 = field2;
}
// getters & setters
}

Spring autowired using constructor

I want to create a object using few properties, how can I achieve that using Spring #Autowired ?
E.g.-
public class Person{
private String fname;
private String lname;
public Person(String fname, String lname){
this.fname = fname;
this.lname = lname;
}
}
How can I create a object using #Autowired of Person class by passing these properties at runtime.
Atul
Do you really want to autowire the variables? Or do you want to set them explictly when getting the bean?
In the later case, you can simply call ApplicationContext.getBean(Class<T> clz, Object ... arguments), in your case...
Person person = context.getBean(Person.class, "Henry", "Miller");
Obviously that doesn't have anything to do with #Autowired. Or do you want to autowire some strings into it? In that case you normally would use the #Value annotation. Autowired is used to inject beans, which you can do via field injection...
#Autowired
private MyService service;
...via constructor injection...
#Autowired
public Person(MyService service) { ... }
...via setter injection...
#Autowired
public void setMyService(MyService service) {..}
But normally you only autowire beans that way. Strings are no beans, so you have to use #Value...
#Autowired
public Person(#Value('${app.some.property}') final String firstName) {...}
This would inject the configured property of app.some.property into that bean. Of course, this only is good if you actually want to inject something from the application context. If you want to create the Person dynamically, you can use the method above.

Correct scope for spring beans on Rest Service

I'm creating a REST service using RestEasy and Spring 4.
The service is basically an endpoint for a complex batch process. So clients call the service passing a bunch of parameters and then the processing is triggered.
As there are many parameters that are initially passed to the service, and those parameters are used pretty much everywhere in the system, I've chosen to create a 'helper' bean that will hold the parameters, then every other bean can autowire the 'parameter bean' and use it.
example:
the url called by the client would be: http://localhost/rest/service/execute?processType=A&initialDate=20141220&finalDate=20141231......
The REST Service endpoint would be something like:
#Path("/service")
public class RESTService {
#Autowired
private RequestParams params;
#Autowired
private ProcessOrchestrator orchestrator;
#POST
#Path("/execute")
#Produces(MediaType.TEXT_PLAIN)
public Response executa(
#NotNull #QueryParam("processType") String processType,
#NotNull #QueryParam("initialDate") String initialDate,
#NotNull #QueryParam("finalDate") String finalDate,
...
) {
params.setProcessType(processType);
params.setInitialDate(initialDate);
params.setFinalDate(finalDate);
orchestrator.triggerBatchProcess();
}
}
The RequestParams bean will only hold the parameters values:
#Component
public class RESTService {
private String processType;
private String initialDate;
private String finalDate;
...
// getters and setters
}
And the other beans would #Autowire the params bean and use its parameters:
#Component
public class DataProcessor {
#Autowire
private RequestParams params;
//...
}
#Component
public class DataConverter {
#Autowire
private RequestParams params;
//...
}
#Component
public class FileWritter {
#Autowire
private RequestParams params;
//...
}
The design looks correct, right? Now, my concern is: how do I make sure that a new RequestParams instance is created every time the service is called? Do I need to declare a scope ("request" for instance) for all my beans?

Resources