Properties files in JAVA

By default, the properties files are stored at the same place where other .class files exist. Can this be changed?
I want to know if it is possble to store properties files in a separate folder. My goal is to be able to modify the properties files at run  time without re-deploying the entire application. If it is possible then I also want to know what changes will I need to make in the code to access the properties files.
javaCaravan0Asked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
vkphoenixfrConnect With a Mentor Commented:
Use Spring Resource interface, with the different implementing classes :
- ClassPathResource (with a path in the class path)
- FileSystemResource (with a path)
- InputStreamResource

this should allow you to place your properties whereever you want (even on internet, with a UrlResource :) )

Phoenix

0
 
CEHJConnect With a Mentor Commented:
You can load a properties file from anywhere. Config file are often place in the home directory - always locatable and always writable, so you could do that.
File fProps = new File(System.getProperty("user.home"), "x.properties");// Now open a FileInputStream on it

Open in new window

0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
javaCaravan0Author Commented:
vkphoenixfr:

Thanks for you suggestion. I'm using SPRING MVC in my application, I'd like to test what you have explained. I'll appreciate if you can elaborate what you have explained above.

I am accessing my properties files both in JAVA classes (e.g controller) as well as in the JSP pages.
Suppose I have two properties files:
1. myApp.properties
2. myApp_fr.properties

can you please explain how will I use the spring resource interface to access the properties files?

Thanks



0
 
vkphoenixfrCommented:
First you're in a webapplication so in your web.xml you have a listener of type ContextLoaderListener (spring), which loads a context file, like this

 <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

Then in this context file, you are free to define any kind of resource you like, either by defining a resource bean with a property holding the path (see spring javadoc, really easy), or even better, you can create a list based resource loader, to load as many property files u like : (this onem mixes plain pathes with classpathes).

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config PropertyPlaceholderConfigurer">
           <property name="locations">
             <list>
                      <value>/WEB-INF/config/common.properties</value>
                      <value>classpath:com/foo/bar/dummy.properties</value>
            </list>
            </property>
    </bean>
0
 
javaCaravan0Author Commented:
Thanks for the response. Let me clarify what you have explained just to make sure I understand it correctly:

1. Defining stuff in web.xml is fine
2. Defining the properties files in the contect file:

As I mentioned above about the properties files names i.e.
1. myApp.properties
2. myApp_fr.properties

I want to put these files on the NAS, so that I could change them as needed and the web application will pick the changes without re-deploying the app.
Let's say the path to NAS is: /apps/shared/data/myApp
so will I define the path to my properties files like this:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config PropertyPlaceholderConfigurer">
           <property name="locations">
             <list>
                      <value>/apps/shared/data/myApp/myApp.properties</value>
                      <value>/apps/shared/data/myApp/myApp_fr.properties</value>
            </list>
            </property>
    </bean>

Now after defining the location for my properties file, if I type the following in my JSP:
<fmt:message key="shop.showTool1.itemLable">
will it pick the value from the property file siting on NAS?

Please confirm or correct me if I'm wrong.

Thanks
0
 
vkphoenixfrCommented:
Actually no it won't.
What it does is define a list of property placeholders you can use to, say, configure your beans or whatever.
What you really want is a "reloadable" (no restart) i18n message source, if i understood correctly.

This is different and, once again, spring helps. Here is an example of what to do :

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="cacheSeconds" value="2"/>
        <property name="defaultEncoding" value="UTF-8" />
        <property name="basenames">
            <list>
                <value>${resourcebundle.path}/myApp</value>
            </list>
        </property>
    </bean>

This is a messageSource definition by spring, reloadable (no restart needed).

Now you jus have to export it into the servlet context to allow you fmt tags to access them :

<bean id="resourceBundle"
                class="org.springframework.context.support.MessageSourceResourceBundle">
                <constructor-arg ref="messageSource" />
</bean>

<bean id="servletContextExporter"
                class="org.springframework.web.context.support.ServletContextAttributeExporter">
                <property name="attributes">
                        <map>
                                <entry
                                        key="javax.servlet.jsp.jstl.fmt.localizationContext.application">
                                        <bean
                                                class="javax.servlet.jsp.jstl.fmt.LocalizationContext">
                                                <constructor-arg ref="resourceBundle" />
                                        </bean>
                                </entry>
                        </map>
                </property>
        </bean>
                   

Here the resourcebundle.path is a property defined in a property file loaded via a propertyplaceholder, as seen above, so that you can change your resource bundle location by just changing a property file value (but needs restart :) ).
0
 
javaCaravan0Author Commented:
vkphoenixfr: Thanks for the detailed response.
I need to understand the following:
As an example, I have mentioned following properties files i.e.
1. myApp.properties
2. myApp_fr.properties
And the followiong NAS path where I would like to keep all the properties files:
/apps/shared/data/myApp
You mentioned that the resourcebundle.path is a property whose value is pulled from the properties file.
the value for the property is going to be: /apps/shared/data/
please confirm.
Also in which property file do I need to put this value? Will the value be in myApp.properties and
myApp_fr.properties?
Please clarify.

Thank you


0
 
vkphoenixfrCommented:
Yes the resourcebundle.path valie is /apps/shared/data/ in your case.
This is just an improvement i proposed, allowing path modification using properties, but youmay set it in the spring configuration directly if you prefer.
But this value is supposed (if in a property file) to be in another property file, one in which you already have some configuration properties, for example. It's not linked to your localization properties files.
0
 
javaCaravan0Author Commented:
To test what you have explained, I have added the following into my myApp-servlet.xml:

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="cacheSeconds" value="2"/>
        <property name="defaultEncoding" value="UTF-8" />
        <property name="basenames">
            <list>
                <value>C:\myProp</value>
            </list>
        </property>
    </bean>

    <bean id="resourceBundle"
                class="org.springframework.context.support.MessageSourceResourceBundle">
                <constructor-arg ref="messageSource" />
    </bean>

    <bean id="servletContextExporter" class="org.springframework.web.context.support.ServletContextAttributeExporter">
                <property name="attributes">
                        <map>
                                <entry
                                        key="javax.servlet.jsp.jstl.fmt.localizationContext.application">
                                        <bean
                                                class="javax.servlet.jsp.jstl.fmt.LocalizationContext">
                                                <constructor-arg ref="resourceBundle" />
                                        </bean>
                                </entry>
                        </map>
                </property>
        </bean>

But my JBOSS server throws the following errors during deployment:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'resourceBundle' defined in ServletContext resource [/WEB-INF/eservices-servlet.xml]: Unsatisfied dependency expressed through constructor argument with index 1 of type [java.util.Locale]: Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments?
      org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:529)
      org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:178)
      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:957)
      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:869)
      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:514)
      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:485)
      java.security.AccessController.doPrivileged(Native Method)
      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
      org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
      org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169)
      org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
      org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:170)
      org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:413)
      org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:735)
      org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:369)
      org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:332)
      org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:266)
      org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:236)
      org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
      javax.servlet.GenericServlet.init(GenericServlet.java:211)
      org.jboss.web.tomcat.security.CustomPrincipalValve.invoke(CustomPrincipalValve.java:39)
      org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:159)
      org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:59)
      org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
      org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
      org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
      org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:744)
      org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
      org.apache.tomcat.util.net.MasterSlaveWorkerThread.run(MasterSlaveWorkerThread.java:112)
      java.lang.Thread.run(Unknown Source)

Please let me know if you can figure out the problem.

0
 
vkphoenixfrCommented:
I've been too fast.
ResourceBundle requires a locale also, just add a locale bean and pass it as the second constructor-arg.
this allows it to select the good property file according to the given locale
Sorry
0
 
javaCaravan0Author Commented:
by locale bean, do you mean the following:

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>

please correct me if I'm wrong. If this is correct then I'm still getting error.
0
 
vkphoenixfrCommented:
No 'im referring to a real locale.
<bean id="locale" class="java.util.Locale">
<constructor-args....
</bean>

Either ou create this locale like this or use a SessionLocaleResolver is another point, depends on your needs.

0
 
javaCaravan0Author Commented:
I'm little confused
The constructor-args are required in "resourceBundle" bean, not in "locale" bean.... please confirm
this is what I need to add:
1. Define the bean: <bean id="locale" class="java.util.Locale">
2. in "resourceBundle" bean add the following: <constructor-arg ref="locale" />
0
 
javaCaravan0Author Commented:
I treid the way I explained above but got an error, "locale" bean is also expecting some args as you have mentioned, I changed hte "locale" bean as follows:

     <bean id="locale" class="java.util.Locale">
        <constructor-arg index="0">
            <value>"myApp_en.properties"</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>" myApp_fr.properties"</value>
        </constructor-arg>
    </bean>

I am able to deploy the application but when I access it, I am getting ??? for all the values that have been defined in the properties file. It seems that the server (on my machine)  is not able to access it from this location: C:\myProp
can you tell what went wrong?
Thanks
0
 
vkphoenixfrCommented:
You misunderstood.

Your locale bean definition above is equivalent to writing in ur code :
Locale locale = new Locale("myApp_en.properties", "myApp_fr.properties");
This country/language pair does not exist :)
Look the static locales existing, like Locale.FRANCE, Locale.FRENCH and so on, you'll get a hint on the parameters you shoud give it.

Look the Locale javadoc (or the constructor using autocompletion in your ide), it takes usually a country and a language code as constructor parameters. So define a locale bean this way.
Then u give this locale bean as the second constructor arg of the resourcebundle bean.
The resourcebundle bean uses the message source where you put your properties files names to access localized properties. It uses the second parameter (the locale) to select the correct property file.

For example, if you give two properties :
myprops_fr_FR.properties
myprops_en_US.properties

and a locale bean defined with the constructor args fr and FR (only fr is enough, don't change your properties files names :) ), then the resourcebundle bean will use the message source file ending with fr_FR.

Is it clearer?
0
 
vkphoenixfrCommented:
Btw, if you reeally can't make it work, please provide me with a link or svn link to your code (if possible) so i can try it by myself and see what's wrong.
0
 
javaCaravan0Author Commented:
This is what I understood, I only need to specify the language code:

<bean id="locale" class="java.util.Locale">
        <constructor-arg index="0">
            <value>"en"</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>" fr"</value>
        </constructor-arg>
    </bean>

If this is wrong, please correct the above code.
Thank you for your help.
0
 
vkphoenixfrCommented:
No this is wrong.
The locale bean specifies ONE locale.
It takes either only a language code or a language code plus a country code (like  in en_US, en_UK)
So what you should specify is the locale you want to use :
<bean id="locale" class="java.util.Locale">
        <constructor-arg>
            <value>en</value>   <!-- no need for double quotes -->
        </constructor-arg>
    </bean>

Or you specify the locale in a property file and build the locale by refering to it :
<bean id="locale" class="java.util.Locale">
        <constructor-arg>
            <value>${current.language.code}</value>  
        </constructor-arg>
    </bean>

Or you use a mechanism to get the local from the machine or whatever configuration.
0
 
javaCaravan0Author Commented:
I tried it the way you have explained but still getting ?? for the values that need to come from the properties file.

If you look @ my previous conversation, I have specified this:
     <property name="basenames">
            <list>
                <value>"C:\myProp"</value>
            </list>
        </property>

Is this correct?

Also, you have mentioned that I only need to specify one locale. When the user changes the language to French, will it be able to pick the correct properties file?

Thank you for your great help
0
 
mrcoffee365Commented:
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0
All Courses

From novice to tech pro — start learning today.