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.
Related
I am trying to read a properties folder from this path with respect to the repository root:
rest/src/main/resources/cognito.properties
I have a Class CognitoData from this path: rest/src/main/java/com/bitorb/admin/webapp/security/cognito/CognitoData.java which loads the Properties folder using this code, and it runs fine:
new CognitoProperties().loadProperties("rest/src/main/resources/cognito.properties");
#Slf4j
public class CognitoProperties {
public Properties loadProperties(String fileName) {
Properties cognitoProperties = new Properties();
try {
#Cleanup
FileInputStream fileInputStream = new FileInputStream(fileName);
cognitoProperties.load(fileInputStream);
} catch (IOException e) {
log.error("Error occured. Exception message was [" + e.getMessage() + "]");
}
return cognitoProperties;
}
}
However, when I call CognitoData from a test class located in rest/src/test/java/com/bitorb/admin/webapp/security/cognito/CognitoServiceTest.java , I get this error:
[rest/src/main/resources/cognito.properties (No such file or directory)]
Can anybody shed light on why this is happening?
File directory is not actually relative in that case. You need to provide appropriate file path for this. If you are already using spring boot, then
you can change your code to:
// this will read file from the resource folder.
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("cognito.properties");
cognitoProperties.load(inputStream);
Otherwise you need to provide the full absolute path. new CognitoProperties().loadProperties("/absolutepath/..../cognito.properties")
I don't know what you're using for testing, but I suspect that the working directory when you run tests is not the project root.
One solution is to use an absolute path instead:
/absolute/path/to/project/rest/src/main/resources/cognito.properties
Or maybe check what is the working directory during testing and see if it can be changed to the project root.
I have jar file langdetect.jar.
It has a hierarchy shown in image
There is a class LanguageDetection at com/langdetect package.
I need to access the path of the profiles.sm folder from above class while executing the jar file.
Thanks in advance.
Jars are nothing else than Zip files and Java provides support for handling those.
Java 6 (and earlier)
You can open the jar file as a ZipFile and iterate over the entries of it. Each entry has a full path name inside the file, there is no such thing as relative path names. Though you have to take care, that all entries - although being absolute in the zip file - do not start with a '/', if you need this, you have to add it. The following snippet will get you the path of a class file. The className has to end with .class, i.e. LanguageDetection.class
String getPath(String jar, String className) throws IOException {
final ZipFile zf = new ZipFile(jar);
try {
for (ZipEntry ze : Collections.list(zf.entries())) {
final String path = ze.getName();
if (path.endsWith(className)) {
final StringBuilder buf = new StringBuilder(path);
buf.delete(path.lastIndexOf('/'), path.length()); //removes the name of the class to get the path only
if (!path.startsWith("/")) { //you may omit this part if leading / is not required
buf.insert(0, '/');
}
return buf.toString();
}
}
} finally {
zf.close();
}
return null;
}
Java 7/8
You may open the JAR file using the Java7 FileSystem support for JAR files. This allows you to operate on the jar file as if it would be normal FileSystem. So you could walk the fileTree until you have found your file and the get the Path from it. The following example uses Java8 Streams and Lambdas, a version for Java7 could be derived from this but would be a bit larger.
Path jarFile = ...;
Map<String, String> env = new HashMap<String, String>() {{
put("create", "false");
}};
try(FileSystem zipFs = newFileSystem(URI.create("jar:" + jarFileFile.toUri()), env)) {
Optional<Path> path = Files.walk(zipFs.getPath("/"))
.filter(p -> p.getFileName().toString().startsWith("LanguageDetection"))
.map(Path::getParent)
.findFirst();
path.ifPresent(System.out::println);
}
Your particular Problem
The above solutions are for finding the path inside a Jar or Zip, but may possibly not be the solution to your problem.
Im not sure, whether I understand your problem correctly. As far as I see it, you'd like to have access to the path inside the classfolder for any purpose. The problem with that is, that the Class/Resource lookup mechanism doesn't apply to folders, only files. The concept that is close is a package, but that is always bound to a class.
So you always need a concrete file to be accessed via getResource() method. For example MyClass.class.getResource(/path/to/resource.txt).
If the resources are located in a profiles.sm folder relative to a class and its package, i.e. in /com/languagedetect/profile.sm/ you could build the path from the reference class, for example the class LanguageDetection in that package and derive the absolute path from this to the profiles.sm path:
String basePath = "/" + LanguageDetection.class.getPackage().getName().replaceAll("\\.", "/") + "/profiles.sm/";
URL resource = LanguageDetection.class.getResource(basePath + "myResource.txt");
If there is only one profiles.sm in the root of the jar, simply go for
String basePath = "/profiles.sm/";
URL resource = LanguageDetection.class.getResource(basePath + "myResource.txt");
If you have multiple jars with a resource in /profiles.sm, you could gain access to all of those via the classloader and then extract the Jar file from the URL of the class
for(URL u : Collections.list(LanguageDetection.class.getClassLoader().getResources("/profiles.sm/yourResource"))){
System.out.println(u);
}
In any case it's not possible without accessing the zip/jar file to browse the contents of this path or folder because Java does not support browsing for classes or resources inside a package/folder in classpath. You may use the Reflections lib for that or extend the ClassLoader example above by additionally reading the content of the detected jars using the zip example from above.
i am developping an application where i have to specify the path of a file called dao.properties it works just fine but when i execute the jar using the cmd : java -jar StockManagement.jar i get the error that the file is not found (it works fine in netbeans)
the class and the file are in the same folder.
i've tried a lot of relative paths and nothing works so this is my last hope
here is the code and the hierarchy:
thank y in advance
If your file is in your code base you should use the classLoader to load it.
If I'm not mistaken, the way you're using ClassLoader is it looking for a file path relative to where it is being called.
From the picture, it seems that you're using ClassLoader from the DAOFactory class, is that right? You're declaring the path to your file to be
stock/DAO/dao.properties
If you're calling it from DAOFactory, Java looks for the file in
<where DAOFactory is>/stock/DAO/dao.properties
If DAOFactory and dao.properties reside in the same file I think your file path should just be
dao.properties
So it looks in the same folder that DAOFactory is in.
EDIT: Use DAOFactory class to read in properties file.
Using something like the following code snippet, call this function from the DAOFactory class using just the main method to try to see if you can read the properties file without anything else. Change any classes or names you need to to work on your local machine.
public static String getProperty(String property) {
String value = "";
try (InputStream is = DAOFactory.class.getResourceAsStream("dao.properties")) {
Properties prop = new Properties();
prop.load(is);
value = prop.getProperty(property);
} catch (Exception e) {
e.printStackTrace();
}
return value;
}
What is the uniform or standard way to locate and then access files inside and outside JAR files.
I have InJarClass() defined in JAR file which contains configuration text files.
Then I extend this class in my host project which have more configurations.
Let say I have inside the JAR :
config/default.conf
Then in the host project I do :
class MyClass extends InJarClass { .... }
and also :
config/test.conf
then I run it something like this :
XENV=test java myclass
The whole configuration process happens inside InJarClass(), based on environment XENV.
As you see InJarClass() have to access both :
<jar>/config/default.conf
<host_app_dir>/config/test.conf
So to repeat my question is there uniform way to access both, if the directory structure mirror each other.
If you place both the current directory and the .jar file in your classpath:
XENV=test java -classpath .:myjarfile.jar MyClass
you can do this:
String configFile =
"/config/" +
System.getenv().getOrDefault("XENV", "default") +
".conf";
InputStream config = MyClass.class.getResourceAsStream(configFile);
if (config == null) {
throw new FileNotFoundException(
"Cannot locate " + configFile + " in classpath");
}
This works because an application resource is a resource which Java searches for within each location in the classpath. So getResourceAsStream will first search for the requested path relative to the first classpath location, .. If it does not find a file with that name, it will look at the second classpath location, myjarfile.jar, and seeing that it is a .jar file, will search for the requested file inside that .jar.
I have two classes. One is intended to be a common library and another a client that consumes from the library.
The library is structured as below:
public class Library
{
public Library()
{
String pathToResourceA="src/main/resources/A.xls";// A.xls is present within resources
String key="apples";
Resource res= loadResourceBasedOnDoc(pathToResource,key);
...//process resource
}
}
It's corresponding test class
public class LibraryTest
{
#Test
public void testLibrary()
{
new Library();// works as expected- the test passes and the resource is loaded.//ie. A.xls is found in the right place
}
}
However, when I try to access the library from my client in the following manner
import packagename.Library
public class Client{
Library lib;
public Client()
{
lib= new Library();// throws a FileNotFoundException!
}
}
I get a FileNotFoundException. I'm guessing this is something to do with defining the right value to pathToResourceA in class A but cant figure out what it is. Any thoughts would be appreciated. Thanks!
Code for loadResourcesBasedonDoc
protected Resource loadResourceBasedOnDoc(String filename,String password)
{
InputStream in = null;
try {
in = new FileInputStream(filename);
//further in is processed...
The problem is that you are using relative file paths:
String pathToResourceA="src/main/resources/A.xls";// A.xls is present within resources
This is then processed in the loadResourceBasedOnDoc method as follows:
in = new FileInputStream(filename);
This call looks for the file (src/main/resources/A.xls) on the file system. Because the path is relative, it looks for the file in a directory that is relative to the current working directory. In your unit test, the current working directory is probably the directory from which the test is launched. Assuming that is the root of your project, the test likely finds A.xls on the file system within your project.
To solve this, I recommend using full pathnames in the loadResourceBasedOnDoc as follows:
String programLaunchDir = System.getProperty("user.dir")
in = new FileInputStream(programLaunchDir + File.separator + filename);
The user.dir system property should be the current working directory. So if you can enforce that the program is launched from that dir, you are all set. Otherwise, you might want to wrap you program in a batch file or shell script that passes the directory to the program.