How to make spring inject value into a static field - java

I know this may looks like a previously asked question but I'm facing a different problem here.
I have a utility class that has only static methods. I don't and I won't take an instance from it.
public class Utils{
private static Properties dataBaseAttr;
public static void methodA(){
}
public static void methodB(){
}
}
Now I need Spring to fill dataBaseAttr with database attributes Properties.Spring config is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<util:properties id="dataBaseAttr"
location="file:#{classPathVariable.path}/dataBaseAttr.properties" />
</beans>
I already done it in other beans but the problem here in this class (Utils) isn't a bean, And if I make it a bean nothing changes I still can't use the variable since the class will not be instantiated and variable always equals null.

You have two possibilities:
non-static setter for static property/field;
using org.springframework.beans.factory.config.MethodInvokingFactoryBean to invoke a static setter.
In the first option you have a bean with a regular setter but instead setting an instance property you set the static property/field.
public void setTheProperty(Object value) {
foo.bar.Class.STATIC_VALUE = value;
}
but in order to do this you need to have an instance of a bean that will expose this setter (its more like an workaround).
In the second case it would be done as follows:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Class.setTheProperty"/>
<property name="arguments">
<list>
<ref bean="theProperty"/>
</list>
</property>
</bean>
On you case you will add a new setter on the Utils class:
public static setDataBaseAttr(Properties p)
and in your context you will configure it with the approach exemplified above, more or less like:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Utils.setDataBaseAttr"/>
<property name="arguments">
<list>
<ref bean="dataBaseAttr"/>
</list>
</property>
</bean>

I've had a similar requirement: I needed to inject a Spring-managed repository bean into my Person entity class ("entity" as in "something with an identity", for example an JPA entity). A Person instance has friends, and for this Person instance to return its friends, it shall delegate to its repository and query for friends there.
#Entity
public class Person {
private static PersonRepository personRepository;
#Id
#GeneratedValue
private long id;
public static void setPersonRepository(PersonRepository personRepository){
this.personRepository = personRepository;
}
public Set<Person> getFriends(){
return personRepository.getFriends(id);
}
...
}
.
#Repository
public class PersonRepository {
public Person get Person(long id) {
// do database-related stuff
}
public Set<Person> getFriends(long id) {
// do database-related stuff
}
...
}
So how did I inject that PersonRepository singleton into the static field of the Person class?
I created a #Configuration, which gets picked up at Spring ApplicationContext construction time. This #Configuration gets injected with all those beans that I need to inject as static fields into other classes. Then with a #PostConstruct annotation, I catch a hook to do all static field injection logic.
#Configuration
public class StaticFieldInjectionConfiguration {
#Inject
private PersonRepository personRepository;
#PostConstruct
private void init() {
Person.setPersonRepository(personRepository);
}
}

As these answers are old, I found this alternative. It is very clean and works with just java annotations:
To fix it, create a “none static setter” to assign the injected value for the static variable. For example :
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class GlobalValue {
public static String DATABASE;
#Value("${mongodb.db}")
public void setDatabase(String db) {
DATABASE = db;
}
}
https://www.mkyong.com/spring/spring-inject-a-value-into-static-variables/

Related

Why #Autowired didn't work in static method

I found many solutions to this issue, and choose the below one.
But it still gets NullpointerException, what's wrong?
A Class
#Component
public class A {
private static Foo foo;
#Autowired
public void setFoo(Foo foo) {
A.foo = foo;
}
public static someFunction() {
foo.doSomething();
}
}
B Class
#Service
public class B {
public void someFunction() {
A.someFunction();
}
}
You cannot auto-wire static properties in Spring, Static fields are instantiated during class load as they are the properties of the class while auto wired attributes work after spring initializes the beans.
Although you may use MethodInvokingFactoryBeanin Spring to achieve what you wanted.
some example would be in XML as below
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Class.setTheProperty"/>
<property name="arguments">
<list>
<ref bean="theProperty"/>
</list>
</property>
</bean>
Edit :- without XML
inside your #Configuration class
do
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("MyClass.staticMethod");
return methodInvokingFactoryBean;
}
let me know in case you need more help.

Queries bean is null, how do I get it to populate?

so I'm trying to run a sql query within this java app. I think I have the DAO set up correctly but it can't find the XML file which contains my queries. The code in question for my DAO implementation is:
private Properties queries;
public void setQueries(Properties queries) {
this.queries = queries;
}
public Boolean checkAssigned(String Id) {
String sql = queries.getProperty("CHECK_IF_ASSIGNED");
Map<String,Object> params = new HashMap<>();
List<String> assignedList;
params.put(":Id",Id);
LOG.info("Checking to see if already assigned \n" + "sql=" + sql
+ "\n" + "params=" + params);
assignedList = getNamedParameterJdbcTemplate().query(sql,params,
new assignedMapper());
if (assignedList == null || assignedList.size() == 0) {
ScreenVo.setSwitch(false);
}
else {
ScreenVo.setSwitch(true);
}
return ScreenVo.getSwitch();
}
My DAO is just:
public interface ScreenDao {
Boolean checkAssigned(String Id);
}
My queries.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<util:properties id="queries">
<prop key="CHECK_IF_ASSIGNED">
<![CDATA[
--Long query
]]>
</prop>
</util:properties>
</beans>
The bean for the dao in the applicationContext.xml is:
<bean id="screenDaoImpl" class="com.corp.apps.actionator.dao.ScreenDaoImpl">
<property name="dataSource" ref="datasource"/>
<property name="queries" ref="queries"/>
</bean>
And my declaration of the queries file in the applicationContext is:
<import resource="classpath:queries.xml"/>
It's declared in my web.xml in a similar fashion.
I tried to include everything that could possibly be relevant. I've tried autowiring the bean in ScreenDaoImpl.java but that didn't work. I'm really not sure where to go from here, or what I might have done wrong.
EDIT:
The exception I'm getting is:
javax.faces.event.MethodExpressionActionListener.processAction java.lang.NullPointerException
And my screenDaoImpl is declared before use as:
private static ScreenDao screenDao = new ScreenDaoImpl();
Spring-Bean screenDaoImpl must be created through Spring context, in this case Spring can inject required properties (dataSource and queries) in created bean.
I don't know your architecture of application. But I can offer you a couple of ways.
1 - If you want use screenDaoImpl in spring-bean which declared in spring-xml then you can do it like this:
<bean id="screenServiceImpl" class="com.corp.apps.actionator.service.ScreenServiceImpl">
<property name="screenDao" ref="screenDaoImpl"/>
</bean>
The better way is make all your application in Spring. And create (and inject) beans by spring-context xml. Do not create bean-objects by new. Spring can not inject properties in these objects.
If it is difficult then try to find examples of applications on the Spring site. Maybe try spring-boot (without xml).
2 - If you want use screenDaoImpl in non-spring object you can get screenDaoImpl from spring-context by "bridge". Create class:
package com.corp.apps.actionator.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class AppSpringBridge implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
Define bean in application-context.xml:
<bean id="springBridge" class="com.corp.apps.actionator.util.AppSpringBridge />
Spring create this bean, but method getApplicationContext() (and context property) of this bean is static. And we can use getApplicationContext() in any methods:
ScreenDao screenDao = (ScreenDao)AppSpringBridge.getApplicationContext().getBean("screenDaoImpl");
I fixed it, and for posterity's sake I'll post my solution here:
First I autowired my screenDao bean in the invoking class, and then I created a static method to set screenDao.
#Autowired
private static ScreenDao screenDao;
#PostConstruct
public static void setScreenDao(ScreenDao newScreenDao) {
screenDao = newScreenDao;
}
#PostConstruct
public ScreenDao getScreenDao() {
return screenDao;
}
I'm not really sure if getScreenDao does anything but I added it as well.
Then in my application context I created a bean I called initialize to invoke the static method.
<bean id="initialize" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.corp.apps.consolidator.backing.ScreenBean"/>
<property name="targetMethod" value="setScreenDao"/>
<property name="arguments">
<list>
<ref bean="screenDao"/>
</list>
</property>
</bean>
These two changes resolved my issue.

Invalid property of bean class is not writable or an invalid setter method

This may looks like a duplicate of this question. But this is different.
I was trying to refactor my legacy code by using method injection in spring.
I have a bean class which contains many static helper methods. My targeted method as follows:
Context.java
private static MessageSender messageSender;
//...
public static MessageSender getMessageSender(){
return messageSender;
}
Context bean
<bean id="context" class="org.abc.Context">
<property name="messageSender"><ref bean="mailMessageSender"/></property>
</bean>
MailMessageSender.java
public abstract class MailMessageSender{
protected abstract Session createSession();
//using createSession() somewhere in this class
}
MailMessageSender bean
<bean id="session" class="javax.mail.Session" scope="prototype" />
<bean id="mailMessageSender" class="org.abc.MailMessageSender">
<lookup-method name="createSession" bean="session"/>
</bean>
I'm getting invalid property error when I'm installing the project.
You can't inject static field, change your variable in Context.java become like this:
private MessageSender messageSender;
//...
public MessageSender getMessageSender(){
return messageSender;
}

What are inner beans in Spring? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am new in spring.
How to inject inner bean in spring ?
what is main purpose of inner bean in spring
Please just guide when i should go for inner bean in spring
In Spring framework, whenever a bean is used for only one particular property, it’s advise to declare it as an inner bean. And the inner bean is supported both in setter injection ‘property‘ and constructor injection ‘constructor-arg‘.
Like Inner classes are the classes which are defined inside the scope of another class. Similarly inner beans are the beans which are defined in the scope of another bean.
Injecting Inner Beans
<bean id="outer_bean" class="OuterBean">
<property name="innerbean">
<bean class="InnerBean"/>
</property>
</bean>
As you can see, instead of using ref attribute of property tag, beans are defined inside property tag. In this case an instance of InnerBean class will be created and wired in to innerbean property of OuterBean class.
We can use inner beans in constructor-arg tag as well like below
<bean id="outer_bean" class="OuterBean">
<constructor-arg>
<bean class="InnerBean"/>
</ constructor-arg>
</bean>
In this case an instance of InnerBean class will be created and will be passed as an constructor argument of OuterBean class.
Consider this example
Student class
public class Student {
private String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Room class
public class Room
{
private int roomNumber;
private Student allotedTo;
public int getRoomNumber() {
return roomNumber;
}
public void setRoomNumber(int roomNumber) {
this.roomNumber = roomNumber;
}
public Student getAllotedTo() {
return allotedTo;
}
public void setAllotedTo(Student allotedTo) {
this.allotedTo = allotedTo;
}
#Override
public String toString() {
return "Room [roomNumber=" + roomNumber + ", allotedTo=" + allotedTo.getName()
+ "]";
}
}
beans entry in beans.xml
<?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-3.0.xsd">
<bean id="room" class="Room">
<property name="roomNumber" value="101" />
<property name="allotedTo">
<bean class="Student">
<property name="name" value="joe bloggs" />
</bean>
</property>
</bean>
</beans>
TestInnerBeanDependency class
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestInnerBeanDependency {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
Room room = (Room)context.getBean("room");
System.out.println(room);
}
}
Run the TestInnerBeanDependency
Room [roomNumber=101,allotedTo=joe bloggs]
An inner bean definition does not require a defined id or name; if specified, the container does not use such a value as an identifier. The container also ignores the scope flag on creation: Inner beans are always anonymous and they are always created with the outer bean. It is not possible to inject inner beans into collaborating beans other than into the enclosing bean or to access them independently.
I hope it would make you understand the Inner beans.
Thanks.

Injection through Annotations vs injection through XML file in Spring 3. Limitations related to inheritance

I have the following abstract class, with a property called portletBaseViewName which is meant to be different for every concrete Controller extending AbstractController.
public abstract class AbstractController {
private String portletBaseViewName;
protected String getPortletBaseViewName() {
return portletBaseViewName;
}
#Required
#Value("")
public void setPortletBaseViewName(String portletBaseViewName) {
this.portletBaseViewName = portletBaseViewName;
}
}
#Controller
#RequestMapping("VIEW")
public class ReservationOfBooksViewController extends AbstractController{}
I know that is possible declaring the injections in a XML, doing so:
<bean id="abstractController" class="es.alcampo.portalweb.portlets.common.controller.AbstractController" abstract="true">
<property name="portletBaseViewName" value="" />
</bean>
<bean id="reservationOfBooksViewController" class="es.example.portalweb.portlets.reservationofbooks.controller.ReservationOfBooksViewController" parent="abstractController">
<property name="portletBaseViewName" value="reservationOfBooks" />
</bean>
<bean id="myShopViewController" class="es.example.portalweb.portlets.reservationofbooks.controller.MyShopViewController" parent="abstractController">
<property name="portletBaseViewName" value="myShop" />
</bean>
Do I need to redefine?:
#Controller
#RequestMapping("VIEW")
public class ReservationOfBooksViewController extends AbstractController{
#Value("reservationOfBooks")
public void setPortletBaseViewName(String portletBaseViewName) {
super.setPortletBaseViewName(portletBaseViewName);
}
}
I don't like the previous option, which would be the most elegant option if there is to reach the purpose of injecting one value or another depending on the concrete class through annotations?
I know inheritance and annotations sometimes conflict.
Thanks a lot.
Do you actually need #Value here?
#Value is useful when it contains some expressions evaluated by Spring at runtime. Otherwise you can replace it with explicit initialization (and keeping the setter method allows you to override this values from XML configuration):
public abstract class AbstractController {
protected String portletBaseViewName = "";
public void setPortletBaseViewName(String portletBaseViewName) {
this.portletBaseViewName = portletBaseViewName;
}
}
#Controller
#RequestMapping("VIEW")
public class ReservationOfBooksViewController extends AbstractController{
public ReservationOfBooksViewController() {
this.portletBaseViewName = "reservationOfBooks";
}
}
As shown by #axtavt in previous answer, you don't need any annotation in AbstractController. In addition, you don't need to define abstractController in XML. In case, you want to configure common properties in all of its subclasses, you can put them in abstract bean (without any class name):
<!-- define common properties in abstract bean-->
<bean id="controllerTemplate" abstract="true" />
<bean id="reservationOfBooksViewController" class="es.example.portalweb.portlets.reservationofbooks.controller.ReservationOfBooksViewController" parent="controllerTemplate">
<property name="portletBaseViewName" value="reservationOfBooks" />
In subclasses, #Value annotation is not required and you can use 'getPortletBaseViewName()' method to get view name.

Categories