Solved

Properties files in JAVA

Posted on 2010-08-16
22
770 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
22 Comments
 
LVL 86

Assisted Solution

by:CEHJ
CEHJ earned 83 total points
ID: 33448300
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
ID: 33448329
0
 
LVL 1

Accepted Solution

by:
vkphoenixfr earned 84 total points
ID: 33452940
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
SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.

 

Author Comment

by:javaCaravan0
ID: 33454127
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
ID: 33455252
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
ID: 33457798
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
ID: 33462329
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
ID: 33469439
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
ID: 33472649
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
ID: 33476423
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
 
LVL 1

Expert Comment

by:vkphoenixfr
ID: 33477063
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
ID: 33477509
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
ID: 33477660
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
ID: 33479348
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
ID: 33479577
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
ID: 33480104
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
ID: 33480116
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
ID: 33486200
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
ID: 33486354
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
ID: 33486896
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 27

Expert Comment

by:mrcoffee365
ID: 37061334
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Java can be integrated with native programs using an interface called JNI(Java Native Interface). Native programs are programs which can directly run on the processor. JNI is simply a naming and calling convention so that the JVM (Java…
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
This video teaches viewers about errors in exception handling.
Suggested Courses

751 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