I want to use a small program as a dependency in my Maven project. This program is configured by a properties file which can be edited before its execution. So far I have added the dependency as JAR in a local repository.
Now I want to make that dependency's properties file accessible in my own superior classpath, i.e. in myprogram/src/main/resources/config/myprogram.properties and not in myprogram/local-repository/com/example/mydependency/mydependency.jar/mydependency.properties.
I tried to modify the part of the code where the path for the properties file is defined:
public example() {
Properties prop = new Properties();
InputStream input = example.class.getResourceAsStream("/config/myprogram.properties");
prop.load(input);
...
}
I also deleted the original properties file of the dependency before adding it to my local repository.
The whole program is working, but not as expected. Strangely, neither my new properties file in /src/main/resources/config nor the old one in the mydependency.jar is used. It seems that some kind of default properties file is put into my final fat JAR. But I cannot find its source anywhere - even when I try to debug it. That default properties file just seems to appear out of nowhere.
Now, how can I properly move the dependency's properties file to my own classpath?
And where could this default properties file appear from?
Is this an issue with Maven or with the source code itself?
Thanks in advance!
You can do something like this:
public static String getValueFromDependencyProps(ClassLoader cl, String propertiesFile, String key) throws IOException {
Properties prop = new Properties();
prop.load(cl.getResourceAsStream(propertiesFile));
String value = prop.getProperty(key);
if (value == null)
throw new NullPointerException();
else
return value;
}
And then:
String value = getValueFromDependencyProps(YourDependencyClass.class.getClassLoader(), "your.properties", key);
Tested and working. With that I'm able to access any properties file from an external Maven dependency (using one of its classes, YourDependencyClass, to reach it).
Related
I have a spring application, and i'm trying to access a json file with the following code :
try (FileReader reader = new FileReader("parameters.json")) {
Object obj = jsonParser.parse(reader);
parameterList = (JSONArray) obj;
}
I have put the parameter.json file in the project folder and I'm accesing the file data from an angular app through a rest api, and that works fine when I run the application on local machine, but when I deploy the war file on tomcat, my application can't load the file, should I put parameter.json file somewhere else on tomcat or what is the best solution for it.
Your question states you are attempting to access a file called parameter.json, while your code excerpt shows parameters.json. Perhaps that discrepancy indicates a typo in your source code?
If not, there are various ways to access a file from the classpath in Spring, with the first step for each being to ensure the file is in the project's src/main/resources directory.
You can then use one of the Spring utility classes ClassPathResource, ResourceLoader or ResourceUtils to get to the file. The easiest approach, though, may be to put your properties in a .properties file (default file name application.properties) and access the values using Spring's #Value annotation:
#Value("${some.value.in.the.file}")
private String myValue;
You can use other file names as well by utilizing #PropertySource:
#Configuration
#PropertySource(value = {"classpath:application.properties",
"classpath:other.properties"})
public class MyClass {
#Value("${some.value.in.the.file}")
private String myValue;
...
}
Make sure your parameters.josn filename is exactly same in the code.
Move you parameters.json file in the resources folder and then use the classpath with the filename.
try (FileReader reader = new FileReader("classpath:parameters.json")) {
Object obj = jsonParser.parse(reader);
parameterList = (JSONArray) obj;
}
Try to put the file under resources folder in your spring project. You should be able to access the file from that location.
FileReader is looking for a full-fledged file system like the one on your computer, but when your WAR is deployed, there just isn't one, so you have to use a different approach. You can grab your file directly from your src/main/resources folder like this
InputStream inputStream = getClass().getResourceAsStream("/parameters.json");
All our jars contain a certain file version.properties which contains specific information from the build.
When we start a jar from command line (with several jars on the class path), we would like access the version.properties from the same jar. To be more precise: We would like to write Java code that gives us the content of the properties file in the jar where the calling class file resides.
The problem is that all jars on the class path contain version.properties and we do not want to read the first on the class path but the one from the correct jar. How can we achieve that?
Funny problem. You have to find the location of a representative class of the particular jar and use the result to build the URL for the properties file. I hacked together an example using String.class as example and access MANIFEST.MF in META-INF, since the rt.jar has no properties in it (at least a quick jar tf rt.jar | grep properties resulted in zero results)
Class clazz = String.class;
String name = clazz.getName().replace('.', '/') + ".class";
System.out.println(name);
String loc = clazz.getClassLoader().getResource(name).toString();
System.out.println(loc);
if (loc.startsWith("jar:file")) {
String propertyResource = loc.substring(0, loc.indexOf('!')) + "!" + "/META-INF/MANIFEST.MF";
InputStream is = new URL(propertyResource).openStream();
System.out.println(propertyResource);
Properties props = new Properties();
props.load(is);
System.out.println(props.get("Implementation-Title"));
}
My project structure looks like below. I do not want to include the config file as a resource, but instead read it at runtime so that we can simply change settings without having to recompile and deploy. my problem are two things
reading the file just isn't working despite various ways i have tried (see current implementation below i am trying)
When using gradle, do i needto tell it how to build/or deploy the file and where? I think that may be part of the problem..that the config file is not getting deployed when doing a gradle build or trying to debug in Eclipse.
My project structure:
myproj\
\src
\main
\config
\com\my_app1\
config.dev.properties
config.qa.properties
\java
\com\myapp1\
\model\
\service\
\util\
Config.java
\test
Config.java:
public Config(){
try {
String configPath = "/config.dev.properties"; //TODO: pass env in as parameter
System.out.println(configPath);
final File configFile = new File(configPath);
FileInputStream input = new FileInputStream(configFile);
Properties prop = new Properties()
prop.load(input);
String prop1 = prop.getProperty("PROP1");
System.out.println(prop1);
} catch (IOException ex) {
ex.printStackTrace();
}
}
Ans 1.
reading the file just isn't working despite various ways i have tried
(see current implementation below i am trying)
With the location of your config file you have depicted,
Change
String configPath = "/config.dev.properties";
to
String configPath = "src\main\config\com\my_app1\config.dev.properties";
However read the second answer first.
Ans 2:
When using gradle, do i needto tell it how to build/or deploy the file
and where? I think that may be part of the problem..that the config
file is not getting deployed when doing a gradle build or trying to
debug in Eclipse.
You have two choices:
Rename your config directory to resources. Gradle automatically builds the resources under "src/main/resources" directory.
Let Gradle know the additional directory to be considered as resources.
sourceSets {
main {
resources {
srcDirs = ["src\main\config\com\my_app1"]
includes = ["**/*.properties"]
}
}
}
reading the file just isn't working despite various ways i have tried (see current implementation below i am trying)
You need to clarify this statement. Are you trying to load properties from an existing file? Because the code you posted that load the Properties object is correct. So probably the error is in the file path.
Anyway, I'm just guessing what you are trying to do. You need to clarify your question. Is your application an executable jar like the example below? Are trying to load an external file that is outside the jar (In this case gradle can't help you)?
If you build a simple application like this as an executable jar
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class Main {
public static void main(String[]args) {
File configFile = new File("test.properties");
System.out.println("Reading config from = " + configFile.getAbsolutePath());
FileInputStream fis = null;
Properties properties = new Properties();
try {
fis = new FileInputStream(configFile);
properties.load(fis);
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {}
}
}
System.out.println("user = " + properties.getProperty("user"));
}
}
When you run the jar, the application will try to load properties from a file called test.properties that is located in the application working directory.
So if you have test.properties that looks like this
user=Flood2d
The output will be
Reading config from = C:\test.properties
user = Flood2d
And that's because the jar file and test.properties file is located in C:\ and I'm running it from there.
Some java applications load configuration from locations like %appdata% on Windows or /Library/Application on MacOS. This solution is used when an application has a configuration that can change (it can be changed by manually editing the file or by the application itself) so there's no need to recompile the application with the new configs.
Let me know if I have misunderstood something, so we can figure out what you are trying to ask us.
Your question is slightly vague but I get the feeling that you want the config files(s) to live "outside" of the jars.
I suggest you take a look at the application plugin. This will create a zip of your application and will also generate a start script to start it. I think you'll need to:
Customise the distZip task to add an extra folder for the config files
Customise the startScripts task to add the extra folder to the classpath of the start script
The solution for me to be able to read an external (non-resource) file was to create my config folder at the root of the application.
myproj/
/configs
Doing this allowed me to read the configs by using 'config/config.dev.properies'
I am not familiar with gradle,so I can only give some advices about your question 1.I think you can give a full path of you property file as a parameter of FileInputStream,then load it using prop.load.
FileInputStream input = new FileInputStream("src/main/.../config.dev.properties");
Properties prop = new Properties()
prop.load(input);
// ....your code
Following code works fine on windows:
private static Properties getProps() throws FileNotFoundException, IOException {
Properties properties = new Properties();
File externalFile = new File("myProp.properties");
if(externalFile.exists()) //if an external property file exists within the same path it is prioritized
properties.load(new FileInputStream(externalFile));
else{
properties.load(CommandUtil.class.getClass().getResourceAsStream("/com/localpath/default.properties"));
}
return properties;
}
if myProp.properties exists within the same folder of the .jar, then this property file is read, otherwise default .properties file contained inside of the .jar itself will be taken.
When I move this program on a linux system it does not work anymore: even though there is a .properties file beside the .jar this is just ignored.
Why is that?
I want to read a property file from a java class file which the both are packed together as a same jar.
Project Structure:
src
--->com
------->xyz
----------->Property(foldername)
-------------------------------------->abc.properties
----------->JavaClassFileFolder
-------------------------------------->a.java
In the above structure folder, i want to read a abc.properties file from a.java file. I tried below methods in a.java file to read.
Method1:
InputStream in = this.getClass().getClassLoader().getResourceAsStream("com/xyz/Property/abc.properties");
Properties prop = new Properties();
prop.load(in);
Result: Throws NPE at prop.load(in)
Method 2:
ClassLoader cl = Constants.class.getClassLoader();
Properties prop = new Properties();
prop .load(cl.getResourceAsStream("com/xyz/Property/abc.properties"));
Result: Throws NPE at prop.load(in)
It should work. The only reason it wouldn't is that com/xyz/Property/abc.properties is not in the jar
Start the path with a /, see this.getClass().getClassLoader().getResource("...") and NullPointerException.
That said:
If you use Maven, put your property files to src/main/resources/com/xyz/property. Maven will do the necessary copying for you.
Always begin your Java package names with a lower case letter, i.e. use property instead of Property. Normally, you expect only Java classes to begin with a capital letter.
Usually, it is not necessary to work with the classloader, use Constants.class.getResourceAsStream("/com/xyz/property/abc.properties") instead.
your method one has to work as far as this refers to class a and properties file is present at the destination you mentioned
You are using a relative path (no / at the beginning), therefore getResourceAsStream starts from the package of your Object (this). Add the / at the beginning and you are searching classpath absolute and because you are in the same Classloader (your Class and your Property - File are in the same jar) here are no issues as well.
There might be an exception thrown while trying to read the InputStream object value. Try using a throws IOException class.