Announcement Announcement Module
Collapse
No announcement yet.
getting messages from the message source Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • getting messages from the message source

    I have the message source configured and I can access the messages with the <spring:message /> tag from within jsps however I would like to access messages from within controllers or other application classes. I have tried a few ways of getting at the messages and I would think they would be exposed in fairly striaght-forward manner. Therfore rather than beat my head to a bloody pulp I figured I would ask the group.

    Therefore how do you access messages from the message source from within application classes?

    Thank you for your help.
    -Derrick

  • #2
    I would think this needs to be wired into my bean. I tried this and I get a null pointer exception when I get a local instance of the ReloadableResourceBundleMessageSource class.

    I cannot find any reference on this topic and even in my 'Spring in Action' book there is no documentation. However, I am hopeful someone has done this.

    Comment


    • #3
      Hi

      Shucks, I hate saying 'but it works here for me', but... I can successfully wire in a reference to a ReloadableMessageSource bean in my little stub project here at home.

      Try posting the relevant snippet of your config file (the MessageSource bean definition) and the class definition of the bean definition that is being injected with said MessageSource.

      You could also use the MessageSourceAware callback interface if you are running in an ApplicationContext.

      Ciao
      Rick

      Comment


      • #4
        Code:
        	<bean id="webManager">
        		<property name="target">
                 	<bean class="com.cportfolios.map.web.WebManager">
                        <property name="messageSource" ref="messageSource"/>
                    </bean>
                </property>
        	</bean>
        Code:
        	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            	<property name="basenames">
              		<list>
              			<value>classpath&#58;messages</value>
                		<value>classpath&#58;cptheme</value>
                		<value>classpath&#58;theme</value>
              		</list>
            	</property>
          	</bean>
        Finally in the WebManager class I have a setter method for the message source as an instance of ReloadableResourceBundleMessageSource. I call msgSource.getMessage(key, null, Locale.ENGLISH); only to find that msgSource is null.

        Thanks again for your help... I do appreciate it !

        Comment


        • #5
          Just a small point, but your setter is called messageSource, but you are calling msgSource.....

          Comment


          • #6
            Good catch. Still does not work.... here is the complete code for the class;
            Code:
            package com.cportfolios.map.web;
            
            import java.util.Locale;
            
            import javax.servlet.http.HttpSession;
            
            import org.apache.commons.logging.Log;
            import org.apache.commons.logging.LogFactory;
            import org.springframework.context.support.ReloadableResourceBundleMessageSource;
            
            import com.cportfolios.map.domain.util.UserPreference;
            
            public class WebManager
            &#123;
                private static WebManager instance;
                private Log log = LogFactory.getLog&#40;WebManager.class&#41;;
                private ReloadableResourceBundleMessageSource messageSource;
            
                /**
                 * Default constructor
                 */
                public WebManager&#40;&#41;
                &#123;
                    super&#40;&#41;;
                &#125;
            
                /**
                 * Return the instance of this class
                 *
                 * @return - The one and only instance of WebManager
                 */
                public static WebManager instance&#40;&#41;
                &#123;
                    if&#40;instance == null&#41;
                    &#123;
                        synchronized&#40;WebManager.class&#41;
                        &#123;
                            if&#40;instance == null&#41;
                            &#123;
                                instance = new WebManager&#40;&#41;;
                            &#125;
                        &#125;
                    &#125;
            
                    return instance;
                &#125;
            
                /**
                 * @return Returns the messageSource.
                 */
                public ReloadableResourceBundleMessageSource getMessageSource&#40;&#41;
                &#123;
                    return messageSource;
                &#125;
            
                /**
                 * @param messageSource The messageSource to set.
                 */
                public void setMessageSource&#40;ReloadableResourceBundleMessageSource messageSource&#41;
                &#123;
                    this.messageSource = messageSource;
                &#125;
            
                public UserPreference getUserPreference&#40;HttpSession session&#41;
                &#123;
                    UserPreference up = new UserPreference&#40;&#41;;
                    up = &#40; UserPreference &#41; session.getAttribute&#40;getMessage&#40;"USER_PREF"&#41;&#41;;
            
                    return up;
                &#125;
            
                private String getMessage&#40;String key&#41;
                &#123;
                    String message="";
            		if&#40;messageSource==null&#41;
            		&#123;
            			log.error&#40;"The messageSource is null"&#41;;
            		&#125;
            		else
            		&#123;
            			message = messageSource.getMessage&#40;key, null, Locale.ENGLISH&#41;;
            	        log.info&#40;"RETURNING MESSAGE&#58; " + message&#41;;	
            		&#125;
                    return message;
                &#125;
            &#125;
            The MessageSource wiring:
            Code:
            	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
                	<property name="basenames">
                  		<list>
                  			<value>classpath&#58;messages</value>
                    		<value>classpath&#58;cptheme</value>
                    		<value>classpath&#58;theme</value>
                  		</list>
                	</property>
              	</bean>
            And the WebManager wired with the MessageSource:
            Code:
            	<bean id="webManager">
            		<property name="target">
                     	   <bean class="com.cportfolios.map.web.WebManager">
                                  <property name="messageSource" ref="messageSource"/>
                               </bean>
                             </property>
            	</bean>
            Thanks again.
            -Derrick

            Comment


            • #7
              Hi Derrick

              Why does your WebManager class have a static instance() method?

              I'm reaching here, but are other parts of your code using the aforementioned method? If so, then that is why the messageSource property is null. The WebManager instance that your other code is accessing is not the same instance as the one that Spring is creating and injecting into other objects.

              Basically, Spring goes off and instantiates an instance of your WebManager class (which it can do since the WebManager class exposes a public constructor), and it duly sets the messageSource property. Your other code then uses the static instance() method to access another, totally distinct instance of the WebManager class. The instance pulled from the static instance() method will not have a messageSource, hence the NullPointerException.

              You have some options...

              Get rid of the static instance() method. Spring is designed to do away with such lookup code. The fact that the WebManager has a public constructor implies that you don't mind if many instances of the WebManager class are created, and that you are using the static instance() method as a lookup method. The fact that you have a comment saying that this is the only instance of the WebManager class that can ever be created is all very well, but unfortunately, doesn't make it so. To wit, this code creates three distinct WebManager instances...

              Code:
              new WebManager&#40;&#41;; new WebManager&#40;&#41;; WebManager.instance&#40;&#41;;
              Use dependency injection to inject the singleton instance of the WebManager class that Spring creates into all of those objects that need it, and the messageSource property will be set on the instance that Spring creates.

              Alternatively... if you really need to keep the static instance() method because the classes / objects that use it cannot (for whatever reason) have their dependency on a WebManager instance injected into them, then do actually use the static instance() method to get the WebManager instance; to wit...

              Code:
              <bean class="com.cportfolios.map.web.WebManager" factory-method="instance">
                  <property name="messageSource" ref="messageSource"/>
              </bean>
              The Spring container will not use the constructor get a reference to a WebManager, but rather call the static instance() method. It will then set the messageSource property, and all of your other code that uses the static instance() method to get at the singleton WebManager instance will be cool... no more NullPointerException. You can then change the access modifier of the WebManager class from public to private.

              Of course, be sure not to access the static instance() method before Spring has had a chance to step in there first and actually set the messageSourceProperty.

              Darn. Long post. Whew. Apologies if I am doing that whole egg-sucking-granny-teaching thing.

              Ciao
              Rick

              Comment


              • #8
                OK, so now I have a little test in place. Tell me where I am wrong, I must be missing something fundamental.
                Here is the 'test' class:
                Code:
                import org.springframework.beans.factory.InitializingBean;
                
                
                /**
                 * @author dkittler
                 * Sep 26, 2005
                 *
                 */
                public class DerrickTestWire implements InitializingBean
                &#123;
                    private Log log = LogFactory.getLog&#40;DerrickTestWire.class&#41;;
                    private ISystemLoginManager systemLoginManager;
                
                    /**
                     *
                     */
                    public DerrickTestWire&#40;&#41;
                    &#123;
                        super&#40;&#41;;
                
                        // TODO Auto-generated constructor stub
                    &#125;
                
                    /**
                     * @param systemLoginManager The systemLoginManager to set.
                     */
                    public void setSystemLoginManager&#40;ISystemLoginManager systemLoginManager&#41;
                    &#123;
                        this.systemLoginManager = systemLoginManager;
                    &#125;
                
                    public void test&#40;&#41;
                    &#123;
                        if&#40;systemLoginManager == null&#41;
                        &#123;
                            log.info&#40;"SystemLoginManager is null"&#41;;
                        &#125;
                        else
                        &#123;
                            log.info&#40;"SystemLoginManager is NOT null"&#41;;
                        &#125;
                    &#125;
                
                    /* &#40;non-Javadoc&#41;
                     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet&#40;&#41;
                     */
                    public void afterPropertiesSet&#40;&#41; throws Exception
                    &#123;
                        // TODO Auto-generated method stub
                    &#125;
                &#125;
                Here is the wiring of a class into this above class:
                Code:
                    <bean id="derrickTestWire" class="com.cportfolios.map.web.controller.DerrickTestWire">
                    	<property name="systemLoginManager" ref="systemLoginManager"/>
                    </bean>
                Here is how I am referencing the test class...
                Code:
                DerrickTestWire d  = new DerrickTestWire&#40;&#41;;
                d.test&#40;&#41;;
                And finally, the output in the log file:
                [INFO,DerrickTestWire,http8080-Processor25] SystemLoginManager is null
                Where am I wrong here? I would think that since this test class is wired with the setter method for the systemLoginManager that it would be set when the test() method is invoked. Rather, when the test() method is invoked the systemLoginManager is null which means Spring didn't set the instance variable.

                What is going on here?

                Thanks for you help.
                -Derrick

                Comment


                • #9
                  Spring has *no* control of objects that *you* instantiate

                  You need to create an applicationContext based on your specified xml files and call
                  Code:
                  DerrickTestWire d = DerrickTestWire&#41; &#40;appContext.getBean&#40;"derrickTestWire"&#41;;
                  Another point, your "test" method logic should really do into afterPropertiesSet., It probably makes sense to throw a BeanInitialisationException if it is null.

                  Comment


                  • #10
                    OK, I got the problem fixed... thanks for your help. Appears I had a bit of confusion on how Spring managed class instances.

                    I have the MessageSource properly wired into the ApplicationContext and all appears to work OK.

                    A question that came up is how can you get a handle to your bean instances without having them wired meaning just getting them throught the AplplicationContext? So for example, I want to get a handle to the instance of a class that is wired into Spring but is not wired in the class that I am working in? Put another way, I assume I have to do something like:
                    Code:
                    String&#91;&#93; xml = new String&#91;&#93; &#123;"wire1.xml", "wire2.xml"&#125;; 
                    ApplicationContext ctx = new ClassPathXmlApplicationContext&#40;xml&#41;;
                    MyBeanFromCtx thisBean = &#40;MyBeanFromCtx&#41;ctx.getBean&#40;"myBeanFromCtx"&#41;;
                    thisBean.doSomething&#40;&#41;;
                    Assuming the above is correct, I am curious how folks implement this. I would think this could be a static method in a Singelton utility class that is not wired into the appContext.

                    Thoughts?

                    Thanks again for all your help.
                    -Derrick

                    Comment


                    • #11
                      Derrick,

                      It looks like you found a solution but to address your original question of how to get messages out of the message source from any of the controller classes in Spring, they basically have to be made aware of their application context. This is done by implementing the ApplicationContextAware interface which the ApplicationObjectSupport class does. This class is a extended by all the controllers in spring so they are all aware of the application context. The ApplicationObjectSupport exposes the message source accessor via the application context with a get method.

                      A simple message could be retrievd from the message source like so

                      Code:
                      String foo = getMessageSourceAccessor&#40;&#41;.getMessage&#40;msgKey, locale&#41;;

                      Comment

                      Working...
                      X