getResourceAsStream returns null when reading properties file - java

I want to load application.properties file form maven resource folder but getResourceAsStream returns null. here is my code:
static {
Properties props = new Properties();
InputStream in = Configuration.class.getResourceAsStream("application.properties");
props.load(in);
}
but InputStream is null. Configuration class is located at org.elasticsearch.utils package and application.properties is located at src/main/resources. What is wrong?

You're trying to read a classpath resource relative to the Configuration class.
If you want to do this, the resource must be on the same relative path, i.e. your property file must be in src/main/resources/org/elasticsearch/utils.
Or you can instead use absolute path: /application.properties.

From what I am seeing, your setup is just right. Having the maven resource folder and the java folder both under "main" is totally fine.
I had a problem with the filename of the properties file. I still do not understand why, but as soon I changed the name from application.properties to whateverYouWant.properties it suddenly works.
And have you enabled filtering for maven resources in the pom.xml?
<build>
<!--Allows access to maven resources-->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
Here is a guide from Alex Miller Retrieve version from maven pom.xml in code
And here is the full code example for accessing the properties in java code (I know you posted already nearly all of it, but just in case if somebody stumbles upon this post)
public String getVersionNumber() {
String version = "";
ClassLoader classLoader = getClass().getClassLoader();
final Properties properties = new Properties();
try {
properties.load(classLoader.getResourceAsStream("main.properties"));
version = properties.getProperty("application.version");
} catch (IOException ioException) {
log.log(Level.WARNING, "Version number could not be retrieved from maven resources.");
} catch (NullPointerException nullPointerException) {
log.log(Level.WARNING, "Cannot find .properties file to read version number");
}
return version;
}

This is what I have tried and working:
#Jiri's answer is also correct.
PS: "/config.properties" also works in my example. But if the this was inside ElasticTest class, then you should have to use just "config.properties".

you need to either add a / at the beginning of the rsource location string or move it to match the package structure or use the classloader rather than the class.
When looking for a resource via a class the assumption is that the resource directory structure mirrors your class structure.
so your code is looking for the resource under
src/main/resources/org/elastic...

If the file "application.properties" is under "src/main/resources", use full path (in the sense of class loader):
getResourceAsStream("/application.properties")
If you move your file to the same package as your class, you can use relative path:
getResourceAsStream("application.properties")
If you move your file to the same other packages, use full path:
getResourceAsStream("/my/package/name/application.properties")

Related

How to specify the path for getResourceAsStream() method in java

I know this question has been asked several times but I still can't get it work by those solutions.
I have a maven project. And one Config.java file located in consumer/src/main/java. Here's the content:
import java.util.Properties;
public class Config {
Properties configFile;
public Config() {
configFile = new Properties();
try {
configFile.load(this.getClass().getClassLoader().
getResourceAsStream("property_table.config.txt"));
} catch(Exception e) {
e.printStackTrace();
}
}
public String getProperty(String key) {
String value = this.configFile.getProperty(key);
return value;
}
public static void main(String[] args) {
Config config = new Config();
System.out.println("URL: " + config.getProperty("URL"));
System.out.println("PASSWORD: " + config.getProperty("PASSWORD"));
}
}
I kept getting nullpointer exception. I know that's because it can't find the file property_table.config.txt.
At first I put the property_table_config.txt file in the same folder(consumer/src/main/java/) as Config.java file. And tried use /property_table_config.txt and 'property_table_config.txt`. Neither of them work.
And then I tried using absolute path, not working. And tried using /main/java/property_table_config, not working either.
Then I saw this solution: https://stackoverflow.com/a/2103625/8159477.
So I make a directory called resources and put it under main folder (i.e. the path of the folder is consumer/src/main/resources, and create a sub-folder config under resources. After putting the property_table_config.txt file there, I changed the code into this:
configFile.load(this.getClass().getClassLoader().getResourceAsStream("/config/property_table.config.txt"));
But this still didn't work. Can anyone give some hint on this? Any suggestions will be appreciated!!
According to Class.getResourceAsStream:
This method delegates to this object's class loader. If this object was loaded by the bootstrap class loader, the method delegates to ClassLoader.getSystemResourceAsStream.
Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:
If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
Otherwise, the absolute name is of the following form:
modified_package_name/name
Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').
This is how I understand the comments:
If you use ClassLoader.getResourceAsStream, send the absolute path from package root, but omitting the first /.
If you use Class.getResourceAsStream, send either a path relative the the current Class object (and the method will take the package into account), or send the absolute path from package root, starting with a /.
But in addition to this, you need to be cognizant of your build system. With maven, resource files are stored under src/main/resources.
So, in your case, I believe making the following changes should resolve the issue:
Put the file in src/main/resources.
Change the code to
this.getClass()
.getResourceAsStream("/property_table.config.txt")
//or `Config.class.getResource...
Alternatively, use
this.getClass().getClassLoader()
.getResourceAsStream("property_table.config.txt")`
I've tried this with a similar setup, and it works as expected.
ClassLoader().getResourceAsStream() is looking files only in classpath.
What you need is to have your config file in directory which is in classpath.
So, you have options:
when you run your java application from command line you can set path to directory in -cp parameter or CLASSPATH system variable. point there is: directory from where you need to get config file must be in class path - not a file. (e.g. if file location is c:\my_projects\test-project\config\my_config.properties and c:\my_projects\test-project\ is in classpath then getResourceAsStream call will be ClassLoader().getResourceAsStream("config/my_config.properties")
you can package your file into jar file and root of jar file is starting point for getResourceAsStream("config/my_config.properties")
If your Maven project is a jar project you need to use Maven resource plugin to put additional resource(s) into jar.
BTW: Maven does not put anything into jar file from src/main/java/ directory (if you do not explicitly specify it for resource plugin)
If you use IDE like Eclipse with your Maven project src/main/resources is a part of build classpath. Double check is it there and if it is not - do "Update Maven Project" or add it manually.
Still ClassLoader will see your properties file from src/main/resources folder only when you run project in IDE not from standalone Jar file - if you did not package your file or provide location in classpath.
hi can you try this one
String dirBase = new ClassPathResource("property_table.config.txt").getURI().getPath().replace("property_table.config.txt", "");
Can you try following code.
Config.class.getResourceAsStream("property_table.config.txt")
Update:
This is the code I tried.
package test;
import java.util.Properties;
public class Config
{
Properties configFile;
public Config()
{
configFile = new Properties();
try
{
configFile.load(Config.class.getResourceAsStream("property_table.config.txt"));
}
catch (Exception e)
{
e.printStackTrace();
}
}
public String getProperty(String key)
{
String value = this.configFile.getProperty(key);
return value;
}
public static void main(String[] args)
{
Config config = new Config();
System.out.println("URL: " + config.getProperty("URL"));
System.out.println("PASSWORD: " + config.getProperty("PASSWORD"));
}
}
And I placed property_table.config.txt file withn test package and it worked.

NPE When Getting File. Works on IDE Run but Not Jar Launch [duplicate]

I have a simple java application that loads a properties file from the current package.
this.getClass().getResourceAsStream("props.properties");
This works fine when the property file I want is in the current package. However, I want to package this application as a JAR and define and override with a new properties file where I use it. Is there a way to load the first resource named "props.properties" that is on the classpath?
I want it to be as easy to override the properties file via command line:
java.exe -classpath props.properties;myJar.jar com.test.MyApp
I don't want to have to unpack the JAR and modify the properties file to change something. I feel like I'm missing something obvious...
The javadoc for Class.getResourceAsStream() documents the lookup logic:
If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
Otherwise, the absolute name is of the following form:
modified_package_name/name
Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').
So in other words, the resource name passed to the method should look like /com/package/p2/props.properties if the props.properties is stored in the com.package.p2 package instead of the current class's.
I'm sure it's too late for the answer but it could be interesting for googlers
this small code snippet helpers to load a properties file from any where in the Classpath.
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
URL url = cl.getResource(CONF_PROPERTIES);
if (url == null) {
url = cl.getResource("/" + CONF_PROPERTIES);
}
if (url != null) {
try {
InputStream in = url.openStream();
props = new Properties();
props.load(in);
} catch (IOException e) {
// Log the exception
} finally {
// close opened resources
}
}
}
If all else fails you could use two different file names, say props-default.properties inside myJar.jar and props.properties to override on the command-line. In your code, you'd try loading the props.properties file first and fallback to props-default.properties if it wasn't found.
I'm not sure, but maybe: ClassLoader.getResourceAsStream()
EDIT:
I don't think this is significantly different to this.getClass().getResourceAsStream() from the question, since as mentioned you still have to get the ClassLoader you want to use to load the resource.
Since you provide the resource in the -classpath in your example, it should be available from the same class loader as your "main" class (in the SUN JVM, that's sun.misc.Launcher$AppClassLoader, not sure if this can/does vary for other JVM implementations).

writing to file in maven project

Hi i am using maven web project and want to write something to file abc.properties. This file in placed in standard /src/main/resource folder. My code is:
FileWriter file = new FileWriter("./src/main/resources/abc.properties");
try {
file.write("hi i am good");
} catch (IOException e) {
e.printStackTrace();
} finally {
file.flush();
file.close();
}
But it does not work as path is not correct. I tried many other examples but was unable to give path of this file.
Can you kindly help me in setting path of file which is placed in resources folder.
Thanks
I think you're confusing buildtime and runtime. During buildtime you have your src/main/java, src/main/resources and src/main/webapp, but during runtime these are all bundled in a war-file. This means there's no such thing as src/main/resources anymore.
The easiest way is to write to a [tempFile][1] and write to that file. The best way is to configure your outputFile, for instance in the wqeb.xml.
[1]: http://docs.oracle.com/javase/6/docs/api/java/io/File.html#createTempFile(java.lang.String, java.lang.String)
If your file is dropped under src/main/resources, it will end up under your-webapp/WEB-INF/classes directory if you project is package as a Web application i.e. with maven-war-plugin.
At runtime, if you want to files that are located under the latter directory, which are considered as web application resources, thus are already present in the application classpath, you can use the getResourceAsStream() method either on the ServletContext or using the current class ClassLoader:
From current thread context:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream is = classLoader.getResourceAsStream("abc.properties");
FileWriter file = new FileWriter(new File(new FileInputStream(is)));
// some funny stuff goes here
If you have access to the Servlet context:
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream("/abc.properties");
FileWriter file = new FileWriter(new File(new FileInputStream(is)));
// some funny stuff goes here
Notice the leading slash in the latter example.

Why would ClassLoader.getResourceAsStream() return null?

Having the following code broken deliberately to identify the source of a NullPointerException in something that should have been very simple but turns out to drive me nuts:
Properties properties = new Properties();
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
InputStream propertiesStream = contextClassLoader.getResourceAsStream("resource.properties");
if (propertiesStream != null) {
properties.load(propertiesStream);
// TODO close the stream
} else {
// Properties file not found!
}
I get the "Properties file not found!" error, i.e. contextClassLoader.getResourceAsStream("resource.properties"); returns null.
This is a CXF-based client and I verified that the "resource.properties" file is in the current directory in which the client's jar resides (and runs).
I also verified the absolute path by including the following diagnostic code:
File file = new File("resource.properties");
System.out.println(file.getAbsolutePath());
The absolute path points to where the client's jar is.
I also tried finding out the context of the class loader, using:
System.out.println(Thread.currentThread().getContextClassLoader());
but instead some directory structure as demonstrated here, all I get is:
com.simontuffs.onejar.JarClassLoader#1decdec
Why would ClassLoader.getResourceAsStream() return null?
What am I missing?
I solved the mystery.
The key to solving was embedding some diagnostic logging when propertiesStream is null:
String classpath = System.getProperty("java.class.path");
LOG.info("CLASSPATH: " + classpath);
ClassLoader loader = MyClientMain.class.getClassLoader();
System.out.println("ClassLoader resource path: " + loader.getResource("resource.properties"));
So when I run with the original
contextClassLoader.getResourceAsStream("resource.properties")
I receive the null pointer condition, printing:
INFO: CLASSPATH: myproj.one-jar.jar
ClassLoader resource path: null
.
I then started suspecting something related to the "jar within a jar" as this is what the com.simontuffs.onejar essentially does (i.e. wrapping my project's jar inside a jar that contains all other library jars), so I opened myproj.one-jar.jar with 7-Zip and noted the full (absolute) path of "resource.properties":
myproj.one-jar.jar\main\myproj.jar\webapp\WEB-INF\classes\resource.properties
.
So I modified getResource("resource.properties") to:
getResource("/main/myproj.jar/webapp/WEB-INF/classes/resource.properties")
which didn't fix the problem but printed the following upon the null pointer condition:
INFO: CLASSPATH: myproj.one-jar.jar
ClassLoader resource path: jar:file:/myproj.one-jar.jar!/main/myproj.jar!//main/myproj.jar/webapp/WEB-INF/classes/resource.properties
.
Then... divine intervention fell upon me and I had the insight (not reading any documentation that could even hint this, I swear!) that I should be using this path instead:
getResource("/webapp/WEB-INF/classes/resource.properties")
And Voila! It works.
Whew.
As EJP pointed out, it means that the resource isn't available via the classpath for this particular classloader (different classloaders can have different classpaths).
Since the classloader is a JarClassLoader, it will only be able to load resources that are included inside the jar file. It won't see files that are in the same directory as the jar file.

Can't read in pom.xml file from webapp

So my tomcat webapps directory looks like this:
C:/tomcat/webapps/myApp/
myApp/
resources/...
META-INF/
MANIFEST.MF
maven/
my.package.name/
myApp/
pom.properties
pom.xml
WEB-INF/
classes/...
lib/...
web.xml
I have an AppConfig.java (java spring config) where I am trying to get the pom.xml file so I can get certain things out of it. I have tried many things but have been unsuccessful in getting the file. I have a bean that I have just been putting a breakpoint in and trying different things to get the file.
#Bean
public String clientVersion()
{
BufferedReader reader = new BufferedReader(new InputStreamReader(ClassLoader.class.getResourceAsStream("/pom.xml")));
return "";
}
I have tried ClassLoader.class.getResourceAsStream() with many different paths though from what I have been able to find in other posts and forums ClassLoader.class.getResourceAsStream("META-INF/maven/my.package.name/myApp/pom.xml") should work, but I get null no matter what I do. Any suggestions?
To load resource you have to provide full path not only filename. Eg /maven/mypackage/myapp/pom.xml
Try with opening stash.
Change the code to:
#Bean
public String clientVersion()
{
BufferedReader reader = new BufferedReader(new InputStreamReader(ClassLoader.class.getResourceAsStream("/META-INF/maven/my.package.name/myApp/pom.xml")));
return "";
}
Depending on how it's stored on you file system, the my.package.name might need to actually be my/package/name.
Don't use the ClassLoader class, because you're probably picking up the wrong classloader (confusing, right?!).
Instead use my.package.name.MyClass.class.getResourceAsStream("/META-INF/maven/my.package.name/myApp/pom.xml")));, this way you can ensure both files (the class and the pom.xml) are available with the same classloader, since the are in the same archive.
I do this to get it as a String (inside a class called ServerResource.java, so swap in your class name):
InputStream is = ServerResource.class.getResourceAsStream("/META-INF/maven/org.buffalo/platform/pom.xml");
String pom = getStringFromInputStream(is);
if you extract your war/jar, you can confirm the path to the pom (for me it's META-INF/maven/org.buffalo/platform_ws/pom.xml)
Class::getResourceAsStream loads resources from the classpath; in a web application, that means files inside WEB-INF/classes, or inside one of the JAR files inside WEB-INF/lib. Your POM file isn't in either of those places, so it's not on the classpath.
Rather, being somewhere under the WAR root, it's a web resource, rather than a classpath resource. You can load web resources using ServletContext::getResourceAsStream.
Your code should look like:
#Bean
public String clientVersion(ServletContext servletContext) throws IOException {
String pomPath = "/META-INF/maven/my.package.name/myApp/pom.xml";
try (InputStream pomStream = servletContext.getResourceAsStream(pomPath)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(pomStream));
return "";
}
}

Categories