Spring autowire byName not working as expected - java

Spring autowire byName not working as expected.
public class SpellChecker {
public SpellChecker() {
System.out.println("Inside SpellChecker constructor." );
}
public void checkSpelling() {
System.out.println("Inside checkSpelling." );
}
}
public class TextEditor {
private SpellChecker spellChecker1;
private String name;
public void setSpellChecker( SpellChecker spellChecker1 ){
this.spellChecker1 = spellChecker1;
}
public SpellChecker getSpellChecker() {
return spellChecker1;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void spellCheck() {
System.out.println(" TextEditor name is " +name);
spellChecker1.checkSpelling();
}
}
public class TextEditorMain {
public static void main(String args[]) throws InterruptedException{
ApplicationContext context = new
ClassPathXmlApplicationContext("Beans.xml");
TextEditor tEditor = (TextEditor) context.getBean("textEditor");
tEditor.spellCheck();
}
}
Spring beans configuration:
<bean id = "spellChecker1" class = "com.spring.beans.SpellChecker">
</bean>
<bean id = "textEditor" class = "com.spring.beans.TextEditor" autowire="byName">
<property name = "name" value = "text1"/>
</bean>
When I give spellChecker1 as bean id it is not working. Below are the console o/p,
Inside SpellChecker constructor.
TextEditor name is text1
Exception in thread "main" java.lang.NullPointerException
at com.spring.beans.TextEditor.spellCheck(TextEditor.java:26)
at com.spring.main.TextEditorMain.main(TextEditorMain.java:15)
Bean id and reference name both are same spellChecker1 but still not working. But the strange thing is if I change the bean id in xml from spellChecker1 to spellChecker the code is working and giving below o/p,
Inside SpellChecker constructor.
TextEditor name is text1
Inside checkSpelling.
So why dependency is not added when I am using spellChecker1 ?

It actually works as designed. Your property is named spellChecker not spellChecker1. You have a field named spellChecker1.
The name of the field is not the same as the name of a property. A name of the property is defined by the get and set methods available on a class. As you have a setSpellChecker (and the corresponding getter) there is a property named spellChecker.
All of this is written down in the JavaBeans Specification (which was written somewhere in 1998!)
Basically properties are named attributes associated with a bean that can be read or written by calling appropriate methods on the bean. Thus for example, a bean might have a foreground property that represents its foreground color. This property might be read by calling a Color getForeground() method and updated by calling a void setForeground(Color c) method.
Source the JavaBeans Specification.

Related

How to create a bean and autowire at run time dynamically based on user input param

How to create Student class object at run time dynamically based on the parameters received in the URL and inject in to WebapplicationContext so the IoC container can auto wire it automaticallly to Access class?
I need to create a bean at run time based on user parameters.
#RestController
public class FunRestController {
#GetMapping("/{id}/{name}")
public String welcomeToBoot(#PathVariable int id, #PathVariable String name) {
// How to create Student class object at run time dynamically based
// on the param received in the URL and can auto wire it dynamically to ***Access*** class below ?
return "Welcome " + name;
}
}
I need to Autowire a run time bean created
public class Access {
#Autowired
Student s;
void print() {
System.out.println(s.name);
}
}
POJO:
public class Student {
public int id;
public String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
I would suggest not to #Autowired the Student object but instead, pass it as a parameter to a function. Something as follows:
public class Access {
void print(Student s) {
System.out.println(s.name);
}
}
Now you just need to call print() method with the given Student. If you need Access to be a Spring-managed Bean so that you can inject it into your Controller, you would need to annotate it with #Component.
Instead of creating bean, you can create a thread local variable and initialise it as the first thing. Then it'll be available throughout the request / response scope

Spring : how to get values from properties file in Model class

I am using Spring MVC for project. I have some constant values which is stored in properties file and I want to fetch from properties file. Question I am unable to fetch values in Model Classes from properties file. It is getting null.
I have set property file location in servlet-context.xml
<context:property-placeholder location="classpath:myproperties.properties" />
Now by using #Value annotation I inject value from properties file.
#Component
class ModelTest {
#Value("${fname}")
private String fname;
// Default Constructor
public ModelTest(){
Sysout(fname); // getting null here
}
#PostConstruct
public void initMembers(){
Sysout(fname) // Prints fname value properly
}
public void setFname(String fname){
this.fname=fname;
}
public String getFname(){
return fname;
}
#Override
public String toString() {
Sysout(fname);
return "ModelTest [variableFirst=" + variableFirst + "]";
}
}
Here is ServiceTest class.
#Service
class ServiceTest(){
#Value("${fname}")
private String fname;
public String printTest(){
sysout(fname); // Prints fname value
return new ModelTest().toString() // Prints null
}
}
Here is ControllerHome Class :
#Controller
public class ControllerHome {
#Value("${fname}")
private String fname;
#Autowired
private ServiceTest service;
#RequestMapping("/")
public #ResponseBody String printData(){
sysout(fname); // Prints fname value
return service.printTest(); // Print null
}
}
In model class fname is getting null while In controller and service class value is coming properly.
is anyone face such issue?
When you say model class, do you mean the value passed to a controller method indicated by #ModelAttribute?
If so, that class is created by ordinary constructor invocation through reflection. It is not a spring bean, and thus #Value does nothing.
Addressing your edit, I think there is some fundamental misunderstanding about how Spring works.
#Service
class ServiceTest(){
#Value("${fname}")
private String fname;
public String printTest(){
sysout(fname); // Prints fname value
// Calling new here means Spring does nothing
// ModelTest is not a Spring bean
// `#Component`, `#PostConstruct` and `#Value` in ModelTest mean nothing.
return new ModelTest().toString() // Prints null
}
}
Instead, you have to do something like this:
#Service
class ServiceTest(){
#Value("${fname}")
private String fname;
#Autowired
private ModelTest modelTest;
public String printTest(){
sysout(fname); // Prints fname value
// modelTest is now a Spring bean
return modelTest.toString() // Should not print null
}
}
Now, Spring will create ModelTest, and #Component, #PostConstruct and #Value will be honored by Spring.
However, #Component by itself has a default singleton scope. So, you will have the same modelTest always.
So, you have to do something like this:
#Component
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
class ModelTest {
// ...
}
Now, while the modelTest reference in ServiceTest will remain constant, the use of a proxy will divert the method calls to a new instance of ModelTest, created by Spring, per request.
This is how I do it :
#Component
#PropertySource("classpath:myproperties.properties") // <-Add this.
class ModelTest {
#Autowired
private Environment env;
public void test(){
String name = env.getProperty("name"); //Assuming you have a 'name' key in your myproperties.property
}
}

Spring autowiring behaviour

I have the next simple application(class Message has only one method which prints incoming message and has no interest for the question):
package messager.spring;
public class User {
private Messenger misiger;
private String name;
public User(String name) {
this.name = name;
}
public void setMessenger(Messenger messinger) {
this.misiger = messinger;
}
public void send(String mess) {
String message = name + " sent message " + "'" + mess + "'";
misiger.send(message);
}
// public String getname() {
// return name;
// }
}
Main class:
package messager.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
user.send("testing3...");
}
}
Spring configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="user" class="messager.spring.User" autowire="byName">
<constructor-arg type="java.lang.String" value="Vova2"/>
</bean>
<bean id="messenger" class="messager.spring.MobileMessenger"/>
</beans>
I used autowiring for class User autowiring Messanger class. According to documentation :
When ByName is used, it then tries to match and wire its properties with the beans defined by the same names in the configuration file. If matches are found, it will inject those beans otherwise, it will throw exceptions.
This configuration works but I dont understand why((( I dont have property with name messenger inside User class((( I changed it on purpose to misiger. And it still works. It seems that bean id directly depends not on property name, but on setter name!!! Is it so?
YES, you are right. As described here :
Spring will lowercase the first letter after “set” in the method name and use the rest of the method name as-is for deducing the property name.
So not the member variable but the setter defines the property name.
That's how JavaBeans work, by looking at naming conventions.
The underlying reference isn't necessarily relevant.
The name of your property is messenger because there's a getter called that.

How can I understand whether a bean exists in runtime?

For example, I have a class
public class Car{
private Motor motor;
public void setMotor(Motor motor){
this.motor = motor;
}
}
My bean looks like
<bean id="car" class="Car">
<property name="motor" ref="${motorProvider.getAvailableMotor()}"/>
</bean>
This method: motorProvider.getAvailableMotor() returns a bean name(string), of which motor I should use.
But there can be a situation when such bean(with such name) is not created. How can I check it?
There are several patterns how to do this. Here is one I often use:
public class Car{
private Motor motor;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void init() {
try {
motor = applicationContext.getBean( Motor.class );
} catch( NoSuchBeanDefinitionException e ) {
motor = new DefaultMotor();
}
}
}
Note you could also call applicationContext.containsBeanDefinition(name) but that would search your context twice (once in containsBeanDefinition() and then second time when you call getBean()) so catching the exception is usually faster.
Since we catch a specific exception that says "bean doesn't exist", using if/else has almost no advantage anymore.
SPeL; something like:
<property name="motor" value="#(if(${motorProvider} != null) ${motorProvider.getAvailableMotor()})"/>
I think it was discussed also here: Spring - set a property only if the value is not null . As they said before for more information see: http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/expressions.html

Injecting property into bean

i am trying to decalre a spring bean on a xml (Mule config file), and i've created a bean like that:
<bean id="IsActiveFilter" class="com.TimeLineListener.IsActiveFilter">
<property name="isChatActive" value="${chatListener.isActive}"/>
</bean>
Now, my question is - how can i get tothe value of isChatActive from within the actual bean class? i mean, can i just create a variable (private int isChatActive) with the name isChatActive and it will get whatever value the placeholder gives it? i mean something like:
public class IsActiveFilter{
{
private int isChatActive;
}
Will that work? if not, how do i use it?
thanks in advance
Create a getter and setter and you are fine:
public class IsActiveFilter{
private int isChatActive;
public int getIsChatActive() {
return this.isChatActive;
}
public void setIsChatActive(int isChatActive) {
this.isChatActive = isChatActive;
}
}
public class IsActiveFilter {
private int chatActive;
public boolean isChatActive() {
return chatActive;
}
public void setChatActive(boolean chatActive) {
this.chatActive = chatActive;
}
}

Categories