Page 1 of 3 123 LastLast
Results 1 to 10 of 22

Thread: Configuring static variables

  1. #1
    Join Date
    Aug 2004
    Location
    Carlisle, UK
    Posts
    184

    Default Configuring static variables

    I have a class with a number of static variables, which hold non-volatile configuration informiation which will always be the same for all instances.

    In order to configure these in the Spring configuration file, I instantiate a bean of the class (with no id, because I'm never going to use it) and use instance setters to set the static properties.

    This invoves several things which seem rather kludgy:
    1. The class needs to have instance setter methods defined for these static variables.
    2. I have to have a no-arg constructor just for this purpose (the 'real life' constructor would throw an exception with null arguments).
    3. Spring has to instantiate an object that I don't want.

    Am I missing something? Is there a better way to do this?

    TIA
    Chris Harris
    Carlisle, UK

  2. #2
    Join Date
    Aug 2004
    Posts
    1,905

    Default

    Hmm, maybe no more elegant, but could you not do this in an ApplicationContextListener? Alternatively you could user a FactoryBean which simply sets the static variables.

    Even better, get rid of the static variables

  3. #3
    Join Date
    Aug 2004
    Location
    Carlisle, UK
    Posts
    184

    Default

    Thanks for the suggestions.
    I couldn't find ApplicationContextListener in the Spring javadoc. Can you give more details?

    As for a FactoryBean, well I don't actually want to return an object.

    I'm beginning to think a BeanFactoryPostProcessor might be the best bet. That would work as long as they didn't need to be set for any initialization going on in setting up other beans in the ApplicationContext, which is true in this case.

    I'm aware that static variables get a bad press . . . they seem the obvious choice in this case, where as I say they are holding non-volatile configuration information which will always be the same for all instances.
    Are there reasons why that's not a good idea?
    Chris Harris
    Carlisle, UK

  4. #4
    Join Date
    Aug 2004
    Posts
    1,905

    Default

    Yeah, my bad. I was thinking of ApplicationListener listening for a ContextRefreshedEvent.

    You're right, a post processor would be a better suit

  5. #5
    Join Date
    Aug 2004
    Location
    Carlisle, UK
    Posts
    184

    Default

    The BeanFactoryPostProcessor does seem to be run before any beans are instantiated.

    I have written a StaticInitializerBeanFactroyPostProcessor, which can initialize an arbitrary number of static fields in an arbitrary number of classes, provided the fields have a static setter.

    I will post the code if anyone is interested.
    Chris Harris
    Carlisle, UK

  6. #6
    Join Date
    Jul 2005
    Posts
    108

    Default

    i'm interested in your post processor which initializes static variables,
    can you post code?

    thanks!

  7. #7
    Join Date
    Aug 2004
    Location
    Carlisle, UK
    Posts
    184

    Default

    ok, here goes:
    Code:
    public class StaticInitializerBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        private Map classes;
        private BeanWrapperImpl bri;
    
    	public StaticInitializerBeanFactoryPostProcessor() {
            bri = new BeanWrapperImpl();
    	}
    
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            for (Iterator classIterator = classes.keySet().iterator(); classIterator.hasNext(); ) {
                String className = (String)classIterator.next();
                //System.out.println("Class " + className + ":");
                Map vars = (Map)classes.get(className);
                Class c = null;
                try {
                    c = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    throw new StaticInitializerBeansException("Class not found for " + className, e);
                }
                Method[] methods = c.getMethods();
                for (Iterator fieldIterator = vars.keySet().iterator(); fieldIterator.hasNext(); ) {
                    String fieldName = (String)fieldIterator.next();
                    Object value = vars.get(fieldName);
                    Method method = findStaticSetter(methods, fieldName);
                    if (method == null) {
                        throw new StaticInitializerBeansException("No static setter method found for class " +
                                className + ", field " + fieldName);
                    }
                    //System.out.println("\tFound method " + method.getName() + " for field " + fieldName + ", value " + value);
                    Object newValue = bri.doTypeConversionIfNecessary(value, getPropertyType(method));
                    try {
                        method.invoke(null, new Object[] {newValue});
                    } catch (Exception e) {
                        throw new StaticInitializerBeansException("Invocation of method " + method.getName() +
                                " on class " + className + " with value " + value + " failed.", e);
                    }
                }
            }
        }
    
        private Class getPropertyType(Method setter) {
            Class params[] = setter.getParameterTypes();
            if (params.length != 1) {
                throw new StaticInitializerBeansException("bad write method arg count: " + setter);
            }
            return  params[0];
        }
    
        /**
         * Look for a static setter method for field named fieldName in Method[].
         * Return null if none found.
         * @param methods
         * @param fieldName
         * @return
         */
        private Method findStaticSetter(Method[] methods, String fieldName) {
            String methodName = setterName(fieldName);
            for &#40;int i=0; i<methods.length; i++&#41; &#123;
                if &#40;methods&#91;i&#93;.getName&#40;&#41;.equals&#40;methodName&#41; &&
                                                    Modifier.isStatic&#40;methods&#91;i&#93;.getModifiers&#40;&#41;&#41;&#41; &#123;
                    return methods&#91;i&#93;;
                &#125;
            &#125;
            return null;
        &#125;
    
        /**
         * return the standard setter name for field fieldName
         * @param fieldName
         * @return
         */
        private String setterName&#40;String fieldName&#41; &#123;
            String nameToUse = null;
            if &#40;fieldName.length&#40;&#41; == 1&#41; &#123;
                if &#40;Character.isLowerCase&#40;fieldName.charAt&#40;0&#41;&#41;&#41; &#123;
                    nameToUse = fieldName.toUpperCase&#40;&#41;;
                &#125; else &#123;
                    nameToUse = fieldName;
                &#125;
            &#125; else &#123;
                if &#40;Character.isLowerCase&#40;fieldName.charAt&#40;0&#41;&#41; && Character.isLowerCase&#40;fieldName.charAt&#40;1&#41;&#41;&#41; &#123;
                    nameToUse = fieldName.substring&#40;0,1&#41;.toUpperCase&#40;&#41; + fieldName.substring&#40;1&#41;;
                &#125;  else &#123;
                    nameToUse = fieldName;
                &#125;
            &#125;
            return "set" + nameToUse;
        &#125;
    
        public void setClasses&#40;Map classes&#41; &#123;
            this.classes = classes;
        &#125;
    &#125;
    
    class StaticInitializerBeansException extends BeansException &#123;
         StaticInitializerBeansException&#40;String msg&#41; &#123;
             super&#40;msg&#41;;
         &#125;
         StaticInitializerBeansException&#40;String msg, Throwable e&#41; &#123;
             super&#40;msg, e&#41;;
         &#125;
    &#125;
    To use it, the xml is like this, where the key of the top level map is the class you want to configure, and the second level map are the static fields you want to assign values to:

    Code:
        <bean class="org.stl.utils.StaticInitializerBeanFactoryPostProcessor">
            <property name="classes">
                <map>
                    <entry key="org.stl.images.WebImages">
                        <map>
                            <entry key="LARGEMAXWIDTH"       value="200"/>
                            <entry key="LARGEMAXHEIGHT"      value="500"/>
                            <entry key="SMALLMAXWIDTH"       value="100"/>
                            <entry key="SMALLMAXHEIGHT"      value="250"/>
                            <entry key="SPSTANDARDMAXHEIGHT" value="10000"/><!-- unlimited -->
                            <entry key="SPSTANDARDMAXWIDTH"  value="148"/>
                            <entry key="SPMEDIUMMAXHEIGHT"   value="10000"/><!-- unlimited -->
                            <entry key="SPMEDIUMMAXWIDTH"    value="75"/>
                            <entry key="SPTHUMBMAXHEIGHT"    value="52"/>
                            <entry key="SPTHUMBMAXWIDTH"     value="10000"/><!-- unlimited -->
                        </map>
                    </entry>
                </map>
            </property>
        </bean>
    Chris Harris
    Carlisle, UK

  8. #8
    Join Date
    Jul 2005
    Posts
    108

    Default

    nice work chris!

    this looks like just what the doctor ordered,
    i'll give it a whirl and let you know how it works out for me.

    thanks again, ciao...

  9. #9

    Default

    I don't get it. Are you that concerned about a few setters being called?

    Is it common to use spring's framework just to configure primitive properties? Maybe I haven't yet sampled the kool-aid but dependency injection seems more useful for established relationships between objects. That way implementations can be swapped but the software contract is maintained.

    For example, your problem could be solved by introducing a WebImageProperties bean. Where and how that bean obtains its properties is transparent to WebImages. It could use spring's xml files, properties files, db, web service, whatever. For you, you could simply use a singleton bean whose properties are set by spring (and still perhaps loaded from a spring loaded properties file).

    <bean id="webImageProperties" class="blah.blah.blah.WebImageProperties"
    singleton="true"
    >
    <property name="LARGEMAXWIDTH" value="20"/>
    <snip>
    </bean>

    <bean id="webImage" class="blah.blah.blah.WebImage"
    singleton="false"
    >
    <property name="properties" ref="webImageProperties"/>
    </bean>

    I'm brand spanking new to spring (2 days), so there could be other ways to do this, or maybe I need to drink more kool-aid.

  10. #10
    Join Date
    Aug 2004
    Location
    Carlisle, UK
    Posts
    184

    Default

    I don't get it. Are you that concerned about a few setters being called?
    No, I'm not. Not sure I understand where this is coming from.

    Is it common to use spring's framework just to configure primitive properties?
    The reason I want to use Spring for this is because it's configuration information; these values could conceivably change, and I want to be able to change them without recompiling. Of course that can be done without Spring; but spring provides a consistent way to do configuration. And while I haven't done it in this instance, more usually I would use a PropertyPlaceholderConfigurer and abstract these out of the XML into a properties file, where they are easy to get at and change if required.
    And yes, I believe it's common to use Spring for this sort of configuration.

    For example, your problem could be solved by introducing a WebImageProperties bean. Where and how that bean obtains its properties is transparent to WebImages. It could use spring's xml files, properties files, db, web service, whatever.
    Yes, I guess it could. And if I might want to use some of these other sources to get the values, it might be a better approach. However in this instance, my approach does exactly what I want, it is simple, and it seems to me, approriate for the task. If there are reasons why it's not a good idea, I'll be happy to consider them.
    Chris Harris
    Carlisle, UK

Similar Threads

  1. Replies: 5
    Last Post: Jan 23rd, 2008, 04:30 PM
  2. How to access Static variables
    By charusheel in forum Architecture
    Replies: 1
    Last Post: Oct 20th, 2005, 12:08 AM
  3. static initialization block
    By sleyzerzon in forum Container
    Replies: 1
    Last Post: Sep 25th, 2005, 01:28 PM
  4. Replies: 3
    Last Post: Jun 22nd, 2005, 11:01 AM
  5. Questioning the core component
    By Martin Kersten in forum Swing
    Replies: 6
    Last Post: Feb 21st, 2005, 03:45 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •