I have a spring boot application with /resources/application.properties, when deployed there is a application.properties next to the jar (and the one inside it).
Somewhere in the code I use ResourceBundle.getBundle("application").getString("x") but that always return the value defined in the properties inside the jar.
My objective is to get the value from the external file if it exists, if not then I need to get the value from inside the jar. Just like the default springs behavior but I'm not able to achieve this.
edit:
You can either use the solution in the correct answer below or you can rely on springs Environment by autowiring it and using getProperty()
ResourceBundle.getBundle(String baseName) relies on the classloader and not directly the file system to find the resource.
This is equivalent to invoke the overloaded one :
getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader()),
So your result is expected.
What you look for is PropertyResourceBundle.
To create an instance of you need either a Reader or an InputStream.
You could load both external and internal files.
ResourceBundle internalProps = ResourceBundle.getBundle("application");
ResourceBundle externalProps = new PropertyResourceBundle(Files.newInputStream(Paths.get("application.properties"));
You could so use the external ResourceBundle in first intention and the second one as fallback.
Related
I try to get file resource in tomcat 7 using this code :
confFileUrl = new URL("classpath:/conf/plugins/my_app_conf.txt");
final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource(confFileUrl.getPath());
URLConnection urlc = resourceUrl.openConnection();
The WEB-INF looks like this :
WEB-INF/classes/conf/plugins/my_app_conf.txt
i need to load it and verify it exist and pass it as URL object to Thired party app ( Accepes only URL object )
But the problem is that :
ClassLoader.getSystemClassLoader().getResource(confFileUrl.getPath());
result allways null
Any idea why ?
Note: You're mixing file names in your question: gappFileUrl vs confFileUrl.
As you specifically check SystemClassLoader, you won't get your webapp's classloader, thus there's nothing to find.
Use this.getClass().getResourceAsStream(name) to utilize the webapp's classloader (or, to be more precise, the classloader that has loaded the current class. Hopefully it's also from within WEB-INF/lib or WEB-INF/classes. If it isn't, pick a class that can be found there.
Also note that a web application is not necessarily "exploded" (unzipped) into the file system, but can legitimately be served from a WAR file. Thus, you'll need to use stream-operations, and can't expect any file-based operations to work consistently.
Edit (after your comment): I've never used the classpath: component int the URL. From https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html (emphasis mine):
The method getResource() returns a URL for the resource. The URL (and its representation) is specific to the implementation and the JVM (that is, the URL obtained in one runtime instance may not work in another). Its protocol is usually specific to the ClassLoader loading the resource. If the resource does not exist or is not visible due to security considerations, the methods return null.
If the client code wants to read the contents of the resource as an InputStream, it can apply the openStream() method on the URL. This is common enough to justify adding getResourceAsStream() to Class and ClassLoader. getResourceAsStream() the same as calling getResource().openStream(), except that getResourceAsStream() catches IO exceptions returns a null InputStream.
...
The getResource and getResourceAsStream methods find a resource with a given name. They return null if they do not find a resource with the specified name. The rules for searching for resources associated with a given class are implemented by the class's ClassLoader. The Class methods delegate to ClassLoader methods, after applying a naming convention: if the resource name starts with "/", it is used as is. Otherwise, the name of the package is prepended, after converting all periods (.) to slashes (/).
Based on that: Try loading a resource named "/conf/plugins/my_app_conf.txt". And you don't need to go through the URL construction, but you can pass that name right to getResourceAsStream, e.g. ...getResourceAsStream("/conf/plugins/my_app_conf.txt");
I have a configuration (config.properties) something like
app.rootDir=
app.reportDir=${app.rootDir}/report
The app.rootDir is not a fixed parameter and it must be initialized by external module. I need keep the ${app.reportDir} keep dynamic reference to ${app.rootDir}.
Use pseudo code to illustrate the problem:
// Init the root dir as '/usr/app'
config.setValue('app.rootDir','/usr/app');
// I need the reportDir to be '/usr/app/report'
String reportDir = config.getValue('app.reportDir');
I can write some codes to get this feature but I'd like to know if there is any existing library do this?
I can use properties, yaml, or json as configuration file type, according to the library availability.
I am replacing the property factory which is used to the load the configuration files with spring. So technically now, my configuration files should be loaded using spring DI via Apache
commons configurations.
So far I have created an Action class and a POJO view class which has the getters and setters for Loadtime, FileModified time, File name etc. The Action has a list of configuration classes injected into the constructor and in the execute method I am looping over the configuration classes creating a simple view object for each one. Then I am setting the value to the my view object which I get from config something like this:
public final String execute() {
configViewList = new ArrayList<ConfigurationViewObject>();
if ((this.configurationList != null) && (this.configurationList.size() != 0)) {
for (PropertiesConfiguration config : configurationList) {
ConfigurationViewObject view = new ConfigurationViewObject();
view.setFileName(config.getFileName());
view.setFileModificationTime(new Date(config.getFile().lastModified()));
configViewList.add(view);
}
return SUCCESS;
} else {
addActionError("List is null.");
return Action.ERROR;
}
}
Well, now I want to find out the load time. Any idea how to find the time when the spring loads the file.I have entirely searched PropertiesConfiguration class and File class if there is any method which gets it for me, however couldn't find any. I would appreciate the much awaited help.
Its very tricky to find this because Spring will never expose this to outside world and thats correct, why would anyone want to know when config file gets loaded?
But still , here is what i would do. Spring config will be loaded when Spring creates loads a class which needs some properties to be set [This is not document officially anywhere but thats how it shld be logically]. Now next part is to find out which class instance needing properties is created first. Again no starighforward way for this but still an appox. way would be to put a System.currentTimeMillis() in Class's constructor. So this will give you an appox. time of when property file will be loaded.
For a straightforward way to do this... you can try calling long before = System.currentTimeMillis() before the call to retrieve properties, and another long after = System.currentTimeMillis() call right after the the properties are retrieved, and seeing the value of the difference, after - before.
I have a properties file (under rsources folder) in which I'm stocking a variable (key=value),
I need to update it when a user insert a new value or update the older one , so can I do it?
I have doubts because it's a web application so it' simply a war deployed in the server. So how it is possible to access the .properties file and change it directly from the code?
If it's not possible, is there another solution?
Perhaps the user could provide an overriding properties file in the filesystem, whose values would override the packaged default properties file.
Check out Apache Commons Configuration, which permits this capability.
Often you want to provide a base set of configuration values, but
allow the user to easily override them for their specific environment.
Well one way is to hard code the default values into your code, and
have then provide a property file that overrides this. However, this
is a very rigid way of doing things. Instead, with the
CompositeConfiguration you can provide many different ways of setting
up a configuration.
Instead of modifying a properties file, you can create a new table in your database (e.g T_PROPERTIES) and add/modify rows in the table.
Define the table with 2 column, key and value and change the records accordingly.
You can let the user write to a properties file, but I don't think it's very clean to do.
There is a class called "Properties" in the java.util package, you can use this class to load a representation of a physical properties file from your webapplication.
for example to load a properties file you could use following code:
public void loadProps(File pfile) throws IOException {
Properties props = new Properties();
FileInputStream fis = new FileInputStream(propsFile);
props.load(fis);
fis.close();
}
Now you can just use built in commands to manipulate the file:
-setProperty(String key, String value);
-get(Object key);
After you're done with it you can just call the save method on the properties Object.
You will need an OutputStream for that.
I want to create an auto-generated resource file similar to R from android. I know how to do the parsing and creation of the file and essentially creating a new class file. What I don't know how to do is start this auto-generation process.
So, using eclipse (although if there is a way to make this happen in an agnostic fashion, I would prefer it), how can I trigger an auto-generation session to read a properties file and create a .java file holding static variables and the "keys" from this parsed file, that I can then reference from my code?
A few examples of how to generate java source files have already been provided. It should be relatively easy to read the properties file and invoke one of these APIs.
To trigger the code generation process, you need to add a custom build step. With Ant, just add a custom task. And then hook it up to an Eclipse Builder: project Properties -> Builders -> New.
Subsequently, Eclipse should find and refresh this file on its own. If it doesn't, then check your configs: Preferences -> General -> Workspace -> find "Refresh using native hooks or polling" and similar ones and check them. (Note that I'm not 100% sure that this last part will work.)
The path of least resistance is to run this build step separately. If your properties file is not changing that often, then it shouldn't be that big a deal. This is similar to what you'd do if you use Protocol Buffers, JAXB, wsdl2java, etc. If you want everything to work magically like R.java does, then you probably have to do something a little more complicated:
- Try to use Eclipse Builder options to control when the Ant task is executed
- If you can't figure that out, then I'd check out how Eclipse hooks up to the above projects (that is, to Protocol Buffers, JAXB, wsdl2java, etc.)
- Look at the ADT custom PreCompilerBuilder class
- Check out the build-helper-plugin
It is common to use a ResourceBundle to create an object that allows you to lookup properties by key. You can learn about the ResourceBundle on the Java Trail.
The basic idea is that you have a text file with a .properties extension. You point the ResourceBundle object to that file. You can then use the getString() or getObject() method passing in the key to the property you want. That is all there is to it. You just need to load the ResourceBundle when you start your program (or sometime before you need it).
If you create you own class that has a ResourceBundle as a member value, you can use a simple bit of code like this to have a simple get() method to get the property value:
public String get(String aString)
{
String sVal = null;
try
{
sVal = (String)myProperties.getObject(aString);
}
catch (MissingResourceException e)
{
log.debug("Missing Property Value: "+aString);
}
return sVal;
}
I hope that is useful.