3

Disclaimer: I understand that trying to use Spring to inject static variables is considered bad practice (and I know there are ways around it, e.g. here). So ultimately I plan to redesign, but am curious about possible solutions or workarounds.

I am using Jakarta's Unstandard tag library (particularly useConstants) to easily expose public static final objects to my JSP pages. I want these static objects to initialize themselves from my database, which means I need to inject a JDBC Template or Data Source. So I want something like:

public class MyGroup {

    // @Autowire or inject somehow?
    private static /*final?*/ NamedParameterJdbcTemplate jdbcTemplate;

    public static final MyGroup GROUP_A = new MyGroup("GROUP_A");
    public static final MyGroup GROUP_B = new MyGroup("GROUP_B");
    public static final MyGroup GROUP_C = new MyGroup("GROUP_C");

    // Instance fields
    private int id;
    private String name;
    private String description;

    /**
     * Construct a group
     */
    public MyGroup() {}

    /**
     * Construct a group using information from the database
     * @param key the key to match
     */
    public MyGroup(String key) {
        // Do DB stuff using injected JDBC template
        this.id = id_from_DB;
        this.name = name_from_DB;
        this.description = desc_from_DB;
    }
}

In my JSP, I could simply do ${MyGroup.GROUP_A.id} and anywhere else in the Java code I could just MyGroup.GROUP_B.getName().

So the problem is that these groups must be final for the Jakarta library to pick them up, but I can't static initialize them via Spring. Thoughts?

Community
  • 1
  • 1
lebolo
  • 2,120
  • 4
  • 29
  • 44
  • check this answer: http://stackoverflow.com/questions/11392692/autowired-in-static-classes.. not the accepted one.. – gipinani Apr 22 '14 at 14:54
  • Thanks @mserioli. I don't think the `factory-method` approach will work since these static objects must be `final`. The second approach is too vague for me ("loading the beans from a Spring context in a static initializer block"), perhaps you can provide an example? – lebolo Apr 22 '14 at 15:06
  • Check this answer :) : http://stackoverflow.com/questions/11324372/how-to-make-spring-inject-value-into-a-static-field – gipinani Apr 22 '14 at 15:09
  • @Rembo No, not really. At this point, it's just a curiosity. I have a Spring-managed JDBC template bean that I use for database access, but no other restrictions. – lebolo Apr 22 '14 at 15:11

1 Answers1

2

This isn't a problem with spring so much as with a conflict between what you want and what java allows. You cannot delay the assignment of a static final property. It has to be set when the class is loaded. Therefore, by the time spring could inject, it is too late.

If you don't have to have it be final, you can open up some options.

Another possibility is it might be possible to create an aspect when intercepts the access of the property, and returns the value you want rather than the stored value. You could then inject the desired value into the aspect.

I've never done it before specifically with static properties, but I presume it is possible. It is not possible to use constant fields (static final fields bound to a constant string object or primitive value) as a JoinPoint since java requires those to be inlined, but since you are pointing to a non-String object, I think using an aspect could work.

To make sure spring injects into your aspect, make sure you tell spring about it via via something like this:

<bean id="someId" class="com.yourdomain.YourAspect" factory-method="aspectOf"/>
DavidA
  • 3,984
  • 5
  • 25
  • 38