Solved

Properties files in JAVA

Posted on 2010-08-16
22
758 Views
Last Modified: 2012-05-10
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.
0
Comment
Question by:javaCaravan0
22 Comments
 
LVL 86

Assisted Solution

by:CEHJ
CEHJ earned 83 total points
Comment Utility
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
 
LVL 20

Assisted Solution

by:Sathish David Kumar N
Sathish David  Kumar N earned 83 total points
Comment Utility
0
 
LVL 1

Accepted Solution

by:
vkphoenixfr earned 84 total points
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 1

Expert Comment

by:vkphoenixfr
Comment Utility
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
 

Author Comment

by:javaCaravan0
Comment Utility
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
 
LVL 26

Expert Comment

by:mrcoffee365
Comment Utility
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
count7 challenge 12 66
pairstar challenge 2 41
Requested array size exceeds VM limit 3 43
Java and GPO 11 45
An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now