70

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.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Osama FelFel
  • 1,511
  • 2
  • 15
  • 17

3 Answers3

112

You have two possibilities:

  1. non-static setter for static property/field;
  2. 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>
Tomislav Nakic-Alfirevic
  • 10,017
  • 5
  • 38
  • 51
Francisco Spaeth
  • 23,493
  • 7
  • 67
  • 106
  • I didn't try 1st solution since I didn't understand it well. I tried 2nd solution and it worked great. – Osama FelFel Jul 04 '12 at 08:58
  • 5
    Definitely prefer the second of these choices over the first. Setting static fields every time an instance is created is a really weird pattern. – Patrick May 30 '14 at 19:28
  • You can also just send a simple property like so: – Paul Gregoire Sep 04 '14 at 13:34
  • it would be nice for some annotation to solve this issue – hudi Feb 06 '15 at 08:44
  • I don't understand this answer. What is `staticMethod`? Which one of the 2 code blocks to use for the 2nd choice? – sebnukem Dec 16 '15 at 01:30
  • 1
    `staticMethod` is a property of `MethodInvokingFactoryBean` and is configured with the fully qualified static method name, wish will be invoked with the arguments provided to the property `argument`. – Francisco Spaeth Dec 23 '15 at 16:25
  • @FranciscoSpaeth what will be the value in arguments. Can you plz add example for that. And also one more thing setting staticMethod how the non satic method of class will get selected. foo.bar.Utils.setDataBaseAttr here setDataBaseAttr is the non static method. This method is not getting selected in the setStaticMethod(). Please help on this. – Kamini Jul 28 '17 at 10:32
22

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);
    }
}
Abdull
  • 26,371
  • 26
  • 130
  • 172
  • 1
    How is it possible you are able to access this from a static method ? I don't believe this is possible at all! Shouldn't it be Person.personRepository = personRepository ? – Jonas Geiregat May 08 '15 at 08:39
  • 3
    @JonasGeiregat it is possible as the method is static and it is accessing static variable – Anuj Acharya Nov 26 '15 at 19:19
  • 4
    I am wondering how someone reference a static variable through 'this' in a static context? – Kripz Apr 28 '16 at 19:02
  • It works, but it's bad practice and it's the same like you would use the class name instead of this. Eclipes would mark it with a warning. – Kani Jun 22 '18 at 15:40
  • You could have done this with a constructor injection and then wouldn't need the field or the postconstruct method – smac89 Jul 04 '19 at 03:24
2

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/

Carlos Andres
  • 417
  • 4
  • 13