Unable to load the file from filesystem using ResourceBundle - java

public static void loadFilters() throws MalformedURLException {
File filtersFile = new File(CONFIG_DIR + "/" + FILTERS_FILE);
URL[] urls = {filtersFile.toURI().toURL()};
ClassLoader loader = new URLClassLoader(urls);
ResourceBundle bundle = ResourceBundle.getBundle(FILTERS_BASE, Locale.getDefault(), loader);
if (StringUtils.isNotBlank(getStringValue(bundle, ALLOW_TYPE_PATTERN_KEY))) {
ALLOWED_TYPES = Pattern.compile(getStringValue(bundle, ALLOW_TYPE_PATTERN_KEY));
}
if (StringUtils.isNotBlank(getStringValue(bundle, DENY_TYPE_PATTERN_KEY))) {
DENIED_TYPES = Pattern.compile(getStringValue(bundle, DENY_TYPE_PATTERN_KEY));
}
ALLOWED_MIME_TYPES = getListValue(bundle, ALLOW_MIME_PATTERN_KEY);
DENIED_MIME_TYPES = getListValue(bundle, DENY_MIME_PATTERN_KEY);
}
I am trying to load properties file using resource bundle kept outside the code in a separate directory. But when I try to do this way(above code) I am getting error as
ERROR [main] Can't find bundle for base name filters, locale en_US
And If I am keeping this file filters.properties in src/main/resources folder then this code is working fine... but when I keep it outside it doesn't works.. Don't know why..
And CONFIG_DIR contains \my\dir\conf and FILTERS_FILE contains filters.properties file.
FILTERS_FILE has value filters.properties and FILTERS_BASE has value filters and urls got the value as [file:/C:/my/dir/conf/filters.properties]
And filters.properties file is in /my/dir/conf/filters.properties

Try having the file point to the directory rather than the actual properties file. So just change the first statement of that method to
File filtersFile = new File(CONFIG_DIR + "/");
If FILTERS_BASE contains filters, that should be enough. You don't need the full filters.properties name since the .properties prefix is appended by the getBundle method.

Related

Java path in Linux

I have a bit problem, and i dont seem to understand what is causing it.
i have a folder in my project, and in that folder i have a class, and i have a resource file (in this case jasper report).
but the only way i can access file is with absolute path or some path that starts from root of my project.
String path = "src/main/java/Views/LagerMain/lager.jrxml";
^^this works, both my class LagerController and lager.jrxml are under LagerMain folder, but when i try to do this :
String path = "lager.jrxml";
i have an error that file is not found.
I tried googling this to have a better understanding but i found nothing.
Bottom line, why cant i access my file, from class when they are both on same place, why does not relative path work.
If the main class is in a different directory, then the program will try to accesslager.jrxml there instead of the directory of the regular class.
For regular-class directory:
String path = new String(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.getPath() + System.getProperty("line.separator") + "lager.jrxml");
If that doesn't work, try this:
// your directory
File f = new File("src");
File[] matchingFiles = f.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("lager") && name.endsWith("jrxml");
}
});
If you have more than one file with the name lager.jrxml, then this method will return both of them and you will need to use a for to cycle through them. Otherwise, you can just use
String path = new String(matchingFiles[0].getAbsolutePath())
For main-class directory:
String path = new String(System.getProperty("user.dir")
+ System.getProperty("line.separator") + "lager.jrxml");

Retrieving resources for a subpackage class

I haven't been working with java for long, so I'm not sure as what else to look for. I hope somebody can point me in the right direction.
Goal:
I want to use a look up table, stored as a text file. But I don't want to use absolute paths, as in the end I'd like to pack a release and be able to call it from any location (the text file will be included int the packed release).
Current setup:
I put the text file in a folder called "resources" (because from reading tutorials about java, I got the impression, this is where I'm supposed to put it to maintain a better structured project).
In the root package folder I have a class (MainClass.java) that is calling another class (LookUpClass.java) in a subpackage.
The folder setup is as followed:
src
java
main.package.com
subpackage
LookUpClass.java
PlotterClass.java
MainClass.java
resources
LookUpTables
LookUpTable1.txt
LookUpTable2.txt
I wrote a method in LookUpClass.java that is retrieving a certain line from my lookup tables in resources. To retrieve the file and read out a certain line, I used
// Gets respective line from LUT
private static String getLineFromLUT(int line) {
URL url = LookUpClass.class.getClass().getResource("/LookUpTables/LookUpTable1.txt");
File file = new File(url.toURI());
BufferedReader br = new BufferedReader(new FileReader(file));
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine;
}
In my project structure the "java" folder is marked as "source", while "resources" is marked as, well, "resources".
My test setup is very simple:
public static void main(String[] args) throws URISyntaxException, IOException {
String c = LookUpClass.getLineFromLUT(5);
System.out.println("Color of line 5: " + c);
}
Output:
Color of line 5: 0 0 38
(Which is correct.)
I added the exact same lines to PlotterClass.java and it works fine, too.
Problem:
Now, If I try the same in MainClass.java I get an error with url being null. It seems the resource/resource folder can't be found.
I read through various postings on SO already and tried out several proposed solutions, which all failed so far:
If using LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt") both callings from MainClass.java and LookUpClass.java fail (url is null).
I tried using following paths (all not working in either of the classes):
"LookUpTables/LookUpTable1.txt" (removing starting "/")
"/subpackage/LookUpTables/LookUpTable1.txt"
"../subpackage/LookUpTables/LookUpTable1.txt"
Since using Idea IntelliJ, I checked "Settings > Build, Execution, Deployment > Compiter > Resource patterns" and added "*.txt" to the patterns. Nothing changed.
If adding Class c = LookUpClass.class.getClass();, in Debug mode c is "class.java.lang.Class". I was expecting something like "main.package.com.subpackage.LookUpClass".
At some point I tried using getResourceAsStream(), but I didn't understand how to get my (e.g.) 5th line, so I discarded it. I'm willing to read up on this, if it solves my problem though.
I have no idea how to solve this problem. And I realize that at this point I'm just trying out things, not even understanding why it could or could not work.
For me, it just seems LookUpClass.java is run from a different location than MainClass.java. But the "resources"-folder and respective text file location never change. How can the file be found in one case, but not in the other?
Maven has a standard directory layout. The directory src/main/resources is intended for such application resources. Place your text files into it.
You now basically have two options where exactly to place your files:
The resource file belongs to a class.
An example for this is a class representing a GUI element (a panel) that needs to also show some images.
In this case place the resource file into the same directory (package) as the corresponding class. E.g. for a class named your.pkg.YourClass place the resource file into the directory your/pkg:
src/main
+-- java/
| +-- your/pkg/
| | +-- YourClass.java
+-- resources/
+-- your/pkg/
+-- resource-file.txt
You now load the resource via the corresponding class. Inside the class your.pkg.YourClass you have the following code snippet for loading:
String resource = "resource-file.txt"; // the "file name" without any package or directory
Class<?> clazz = this.getClass(); // or YourClass.class
URL resourceUrl = clazz.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
Note: You can also load the resource via the class' class loader:
String resource = "your/pkg/resource-file.txt";
ClassLoader loader = this.getClass().getClassLoader(); // or YourClass.class.getClassLoader()
URL resourceUrl = loader.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
Choose, what you find more convenient.
The resource belongs to the application at whole.
In this case simply place the resource directly into the src/main/resources directory or into an appropriate sub directory. Let's look at an example with your lookup file:
src/main/resources/
+-- LookupTables/
+-- LookUpTable1.txt
You then must load the resource via a class loader, using either the current thread's context class loader or the application class loader (whatever is more appropriate - go and search for articles on this issue if interested). I will show you both ways:
String resource = "LookupTables/LookUpTable1.txt";
ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
URL resourceUrl = ctxLoader.getResource(resource); // or sysLoader.getResource(resource)
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
As a first suggestion, use the current thread's context class loader. In a standalone application this will be the system class loader or have the system class loader as a parent. (The distinction between these class loaders will become important for libraries that also load resources.)
You should always use a class loader for loading resource. This way you make loading independent from the place (just take care that the files are inside the class path when launching the application) and you can package the whole application into a JAR file which still finds the resources.
I tried to reproduce your problem given the MWE you provided, but did not succeed. I uploaded my project including a pom.xml (you mentioned you used maven) here: http://www.filedropper.com/stackoverflow
This is what my lookup class looks like (also showing how to use the getResourceAsStream method):
public class LookUpClass {
final static String tableName = "resources/LookUpTables/LookUpTable1.txt";
public static String getLineFromLUT(final int line) {
final URL url = LookUpClass.class.getResource(tableName);
if (url.toString().startsWith("jar:")) {
try (final URLClassLoader loader = URLClassLoader
.newInstance(new URL[] { url })) {
return getLineFromLUT(
new InputStreamReader(
loader.getResourceAsStream(tableName)), line);
} catch (final IOException e) {
e.printStackTrace();
}
} else {
return getLineFromLUT(
new InputStreamReader(
LookUpClass.class.getResourceAsStream(tableName)),
line);
}
return null;
}
public static String getLineFromLUT(final Reader reader, final int line) {
try (final BufferedReader br = new BufferedReader(reader)) {
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine();
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
}

Inquiry about ResourceBundle in java

Directly from this API:
Otherwise, getBundle attempts to locate a property resource file using
the generated properties file name. It generates a path name from the
candidate bundle name by replacing all "." characters with "/" and
appending the string ".properties". It attempts to find a "resource"
with this name using ClassLoader.getResource.
What do they mean with replacing all "." characters with "/" What would be an example?
PS:I am ok with appending .properties at the end.
Say you have a package named
com.yourgroup.bundles
containing a file named
hello_en_US.properties
you would have to specify either of the following to load a bundle
ResourceBundle bundle = ResourceBundle.getBundle("com.yourgroup.bundles.hello");
ResourceBundle bundle = ResourceBundle.getBundle("com/yourgroup/bundles/hello");
Basically the javadoc is telling you how it translates the argument you pass to the getBundle method to find the resource on your classpath. For me, the default Locale is en_US, so
com.yourgroup.bundles.hello
translates to
com/yourgroup/bundles/hello_en_US.properties
It can then use the ClassLoader to find that resource.
The ResourceBundle implementation it returns might actually be a custom class, if you map its name correctly. Follow the javadoc for that. Otherwise, it's just a Properties resource bundle.
The magic happens in ResourceBundle#newBundle(...)
String bundleName = toBundleName(baseName, locale); // baseName being 'com.yourgroup.bundles.hello' in my example above
...
final String resourceName = toResourceName(bundleName, "properties");
and that is simply
public final String toResourceName(String bundleName, String suffix) {
StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
return sb.toString();
}
....
URL url = classLoader.getResource(resourceName);
...
bundle = new PropertyResourceBundle(stream); // stream comes from url

How can I access a folder inside of a resource folder from inside my jar File?

I have a resources folder/package in the root of my project, I "don't" want to load a certain File. If I wanted to load a certain File, I would use class.getResourceAsStream and I would be fine!! What I actually want to do is to load a "Folder" within the resources folder, loop on the Files inside that Folder and get a Stream to each file and read in the content... Assume that the File names are not determined before runtime... What should I do? Is there a way to get a list of the files inside a Folder in your jar File?
Notice that the Jar file with the resources is the same jar file from which the code is being run...
Finally, I found the solution:
final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if(jarFile.isFile()) { // Run with JAR file
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(path + "/")) { //filter according to the path
System.out.println(name);
}
}
jar.close();
} else { // Run with IDE
final URL url = Launcher.class.getResource("/" + path);
if (url != null) {
try {
final File apps = new File(url.toURI());
for (File app : apps.listFiles()) {
System.out.println(app);
}
} catch (URISyntaxException ex) {
// never happens
}
}
}
The second block just work when you run the application on IDE (not with jar file), You can remove it if you don't like that.
Try the following.
Make the resource path "<PathRelativeToThisClassFile>/<ResourceDirectory>" E.g. if your class path is com.abc.package.MyClass and your resoure files are within src/com/abc/package/resources/:
URL url = MyClass.class.getResource("resources/");
if (url == null) {
// error - missing folder
} else {
File dir = new File(url.toURI());
for (File nextFile : dir.listFiles()) {
// Do something with nextFile
}
}
You can also use
URL url = MyClass.class.getResource("/com/abc/package/resources/");
The following code returns the wanted "folder" as Path regardless of if it is inside a jar or not.
private Path getFolderPath() throws URISyntaxException, IOException {
URI uri = getClass().getClassLoader().getResource("folder").toURI();
if ("jar".equals(uri.getScheme())) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
return fileSystem.getPath("path/to/folder/inside/jar");
} else {
return Paths.get(uri);
}
}
Requires java 7+.
I know this is many years ago . But just for other people come across this topic.
What you could do is to use getResourceAsStream() method with the directory path, and the input Stream will have all the files name from that dir. After that you can concat the dir path with each file name and call getResourceAsStream for each file in a loop.
I had the same problem at hands while i was attempting to load some hadoop configurations from resources packed in the jar... on both the IDE and on jar (release version).
I found java.nio.file.DirectoryStream to work the best to iterate over directory contents over both local filesystem and jar.
String fooFolder = "/foo/folder";
....
ClassLoader classLoader = foofClass.class.getClassLoader();
try {
uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
throw new FooException(e.getMessage());
} catch (NullPointerException e){
throw new FooException(e.getMessage());
}
if(uri == null){
throw new FooException("something is wrong directory or files missing");
}
/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
/** jar case */
try{
URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
//jar.toString() begins with file:
//i want to trim it out...
Path jarFile = Paths.get(jar.toString().substring("file:".length()));
FileSystem fs = FileSystems.newFileSystem(jarFile, null);
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
for(Path p: directoryStream){
InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
performFooOverInputStream(is);
/** your logic here **/
}
}catch(IOException e) {
throw new FooException(e.getMessage());
}
}
else{
/** IDE case */
Path path = Paths.get(uri);
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
for(Path p : directoryStream){
InputStream is = new FileInputStream(p.toFile());
performFooOverInputStream(is);
}
} catch (IOException _e) {
throw new FooException(_e.getMessage());
}
}
Another solution, you can do it using ResourceLoader like this:
import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;
#Autowire
private ResourceLoader resourceLoader;
...
Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
load(fi.next())
}
If you are using Spring you can use org.springframework.core.io.support.PathMatchingResourcePatternResolver and deal with Resource objects rather than files. This works when running inside and outside of a Jar file.
PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver();
Resource[] resources = r.getResources("/myfolder/*");
Then you can access the data using getInputStream and the filename from getFilename.
Note that it will still fail if you try to use the getFile while running from a Jar.
As the other answers point out, once the resources are inside a jar file, things get really ugly. In our case, this solution:
https://stackoverflow.com/a/13227570/516188
works very well in the tests (since when the tests are run the code is not packed in a jar file), but doesn't work when the app actually runs normally. So what I've done is... I hardcode the list of the files in the app, but I have a test which reads the actual list from disk (can do it since that works in tests) and fails if the actual list doesn't match with the list the app returns.
That way I have simple code in my app (no tricks), and I'm sure I didn't forget to add a new entry in the list thanks to the test.
Below code gets .yaml files from a custom resource directory.
ClassLoader classLoader = this.getClass().getClassLoader();
URI uri = classLoader.getResource(directoryPath).toURI();
if("jar".equalsIgnoreCase(uri.getScheme())){
Pattern pattern = Pattern.compile("^.+" +"/classes/" + directoryPath + "/.+.yaml$");
log.debug("pattern {} ", pattern.pattern());
ApplicationHome home = new ApplicationHome(SomeApplication.class);
JarFile file = new JarFile(home.getSource());
Enumeration<JarEntry> jarEntries = file.entries() ;
while(jarEntries.hasMoreElements()){
JarEntry entry = jarEntries.nextElement();
Matcher matcher = pattern.matcher(entry.getName());
if(matcher.find()){
InputStream in =
file.getInputStream(entry);
//work on the stream
}
}
}else{
//When Spring boot application executed through Non-Jar strategy like through IDE or as a War.
String path = uri.getPath();
File[] files = new File(path).listFiles();
for(File file: files){
if(file != null){
try {
InputStream is = new FileInputStream(file);
//work on stream
} catch (Exception e) {
log.error("Exception while parsing file yaml file {} : {} " , file.getAbsolutePath(), e.getMessage());
}
}else{
log.warn("File Object is null while parsing yaml file");
}
}
}
Took me 2-3 days to get this working, in order to have the same url that work for both Jar or in local, the url (or path) needs to be a relative path from the repository root.
..meaning, the location of your file or folder from your src folder.
could be "/main/resources/your-folder/" or "/client/notes/somefile.md"
Whatever it is, in order for your JAR file to find it, the url must be a relative path from the repository root.
it must be "src/main/resources/your-folder/" or "src/client/notes/somefile.md"
Now you get the drill, and luckily for Intellij Idea users, you can get the correct path with a right-click on the folder or file -> copy Path/Reference.. -> Path From Repository Root (this is it)
Last, paste it and do your thing.
Simple ... use OSGi. In OSGi you can iterate over your Bundle's entries with findEntries and findPaths.
Inside my jar file I had a folder called Upload, this folder had three other text files inside it and I needed to have an exactly the same folder and files outside of the jar file, I used the code below:
URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);
URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);
URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

How to reference files in a Java Pacakage

I have MyClassin package X, Also in package X there are packages Y and Z like this:
X - MyClass
X - Y - Some Files
X - Z - Some Files
How do I get a list of all the files in packages Y and Z from MyClass?
Java packages mirror directory structure. You can use the File class. In particular, see the listFiles() method.
EDIT
You can dynamically find your executing location. Here is code from a project I've recently worked on; I wanted to be able to find the directory I'm running the JAR from (if I'm running the JAR), or else the directory of the JAR if I'm running from the class files. In my case, my JAR is in <project root>/bin and my classes are in <project root>/classes.
final URL location;
final String classLocation = JavaPlanner.class.getName().replace('.', '/') + ".class";
final ClassLoader loader = JavaPlanner.class.getClassLoader();
if(loader == null)
{
try { throw new ClassNotFoundException("class loaded with bootstrap loader"); }
catch (ClassNotFoundException cnfe) { throw new InitializationException(cnfe); }
}
else
{
location = loader.getResource(classLocation);
}
if(location.toString().startsWith("file:/")) // Line 14
{
// Running from .class file
String path;
try { path = URLDecoder.decode(location.toString().substring(6), "UTF-8"); }
catch(UnsupportedEncodingException uee) { throw new InitializationException(uee); }
// Move up package folders to root, add /bin/
File package_ = new File(path).getParentFile();
binPath = package_.getParentFile().getParentFile().getParentFile().getParentFile() + File.separator + "bin" + File.separator;
}
else // Line 25
{
// Running from .jar file
String jarURL = JavaPlanner.class.getResource("/" + JavaPlanner.class.getName().replaceAll("\\.", "/") + ".class").toString();
jarURL = jarURL.substring(4).replaceFirst("/[^/]+\\.jar!.*$", "/");
try
{
File dir = new File(new URL(jarURL).toURI());
jarURL = dir.getAbsolutePath();
}
catch(MalformedURLException mue) { throw new InitializationException(mue); }
catch(URISyntaxException use) { throw new InitializationException(use); }
binPath = jarURL;
}
At line 14, I've found that I'm running the application from a class file. String path initially is set to the file path of JavaPlanner (the class containing my main method). I know the package structure JavaPlanner is in, so I use getParentFile an appropriate number of times to find the project root, and then append bin/.
At line 25, I've found that I'm running the application from a JAR. The block simply gets the path to the folder containing that executable JAR.
Obviously, this code is not 100% adapted to your purpose (most specifically, I'm calling getParentFile a specific number of times for my package structure), but I think it should help.
The entire purpose of the above code was to be able to find the correct resource files for my application. In the production version, only the JAR would be available to the user, but I didn't want to have to rebuild the JAR every time I needed to test some code, and I didn't want to duplicate my resource files, and I didn't want to pollute my bin/ folder with the class files (because everything in bin/ was meant to be sent to the user).
It depends on the source of the class. If they are from a JAR file, then you can use the JarFile class to get a list of entries.
If you're only looking for classes in the package, consider
Package.getPackage(String name)
Package.getPackages()
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Package.html#getPackage%28java.lang.String%29
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Package.html#getPackages%28%29

Categories

Resources