Can't get resources from jar - java

In my project i need to take jsons from folder located in resources. For it I implemented this method:
protected def getListOfJsonFromResources(path: String): List[String] = {
val source = Source.fromInputStream(Thread.currentThread().getContextClassLoader.getResourceAsStream(path))
println(source)
val list = source.getLines().map{file =>
Source.fromInputStream(Thread.currentThread().getContextClassLoader.getResourceAsStream(path + file))
.mkString
}.toList
source.close()
list
}
It's work fine in IDE but return nothing when I run my jar.
I know that problem is in val source as in jar it return empty iterator.
I tried already use this.getClass().getResourceAsStream(), this.getClass().getClassLoader().getResourceAsStream() and rewrite this method as java method.
I generate JAR in Idea (Build>Build Artifacts>Build). This files is inside JAR with correct path.
I use Apache Maven 3.6.3
My res folder: resources/folder/json/jsonFolder path:folder/json/jsonFolder/
How should I change this method to get list of jsons from given folder?
Thank, in advance.

The proper usage is actually MyClass.class.getResourceAsStream. After all, getClass().getRAS() would fail if your code is subclassed. However, I assume it isn't - so that change will improve the style of this code and future proof it, but it probably won't directly fix the issue.
What MyClass.class.getRAS does, is look in the exact same place that the MyClass.class file is at. For example, if you have a jar with:
META-INF/MANIFEST.MF
com/foo/app/MyClass.class
app-icon.png
com/foo/app/save.png
And you run MyClass, then MyClass.class.gRAS("save.png") will work out. As weill MyClass.class.gRAS("/app-icon.png") - note the leading slash.
Thus, if gRAS isn't working for you here, the conclusion is that you're either specifying the wrong path, or the file you need to be included with your app is not being included by your build tooling.
You haven't shown anything relevant from your build scripts, so there's not much to say about how to fix this. But I can give you the tools you need to debug the problem so you can fix it yourself, with this useful trick:
MyClass.class.getResource("MyClass.class")
works for any class. Print it (System.out.println the URL that falls out of the above call), and you will see the URL, which tells you exactly which of the no doubt many variants of MyClass is actually being used (by your IDE's build-on-save, by sbt's build tooling, in the jar file produced by sbt during the dist phase, and who knows how many more exist somewhere on disk!).
Now use standard computer tools (Mac: Finder, windows: Explorer, or just use the command line) to navigate to the actual location and check for the existence of this resource file. Note that jar files are just zip files; unzip -l somejar.jar is useful here.
If you see the file, well, now you know where that file is relative to MyClass.class, and now you know what to feed to the gRAS call. Note that .. is not a good idea; if it's not in the same dir as your class and not in any subdir, then use the leading slash to go off of the 'root' of the jar file or classpath root directory.
If you don't see the file, well, now you know that your build is broken. Search the web (or ask in a separate question here on SO) on how to fix that, and now you don't need to repeatedly build and run the entire app to figure it out; you can simply keep scanning the jar file produced by the build tool until the resource file shows up in the right spot.
NB: ClassLoader.getSystemCLassLoader.getResource, getThreadContext().getResource, getClass().getResource - these are all wrong. Don't do that. It'll probably also work, but it's more code and will break in various circumstances. MyClass.class.getResource does exactly what you want, is idiomatic, and is one of the shortest forms.

Related

class.getClassLoader.getResource() returns null

Previously I built single jars with ant, for each application i wanted from my project and calling the application with java -jar application-name.
I have now moved to using gradle and having a single jar and call the applications with
java -cp fullpath-to-class.
Everything works as expected for all but one application where i now get a
null pointer exception trying to load the resources required.
If I move the files into the directory of the class which is looking for the files everything is good once again , but having them in a different directory seems to be problematical.
Have you any suggestions on the best approach to
A. debugging this effectivey
B. Having the file in a separate directory
Have you any suggestions on the best approach to A. debugging this effectively
Use jar -tvf ... to check that the missing resource is actually in the JAR file, and that it has the correct pathname in the JAR.file
Use a debugger, and set a breakpoint on the code that is trying to load the resource. Single step until you get to the point where you have the absolute resource path. Check it.
B. Having the file in a separate directory
Umm. I'm not sure what your actual problem is, but my guess is that it is to do with resolving relative resource pathnames. I suggest using absolute resource pathnames instead.
I guess the problem could be in the way you are building the JAR file, but you've not provided any concrete details of how you are doing that.

Change root directory that backslash points to in Java program

I am having issue running a Java program.
There's a line of code in a jar file that opens the FileInputStream to some file from "/apps/somefile" location,
however I do not have access to the root directory.
The issue is that I am unable to change the code since it is provided in a jar file, as such is there anyway to change to root directory that "/" points to when running the java program?
Here's the line for reference:
FileInputStream fileInputStream = new FileInputStream("/apps/somefile");
The line of code you present does not do anything directly. It is Java source code, and Java is ordinarily compiled to bytecode and presented in that form to the JVM. It sounds like your jar may contain source files along with the compiled class files, which is sometimes done. If that's the case then you can simply unpack the Java sources from the jar, modify them, recompile, and make a new jar from the results.
If you don't have source then you could try decompiling, as another answer suggests. That's a bit nasty, but it probably would work.
Alternatively, what you actually ask is
is there anyway to change to root directory that "/" points to when running the java program?
In fact, there may be, depending on the system on which the code is running. You could conceivably run your program under chroot, which has precisely that effect. That's a distinctly non-trivial exercise, however, and if you don't have access to the root directory (though I'm not sure how you can do anything in that case) then you very likely do not have sufficient access to set up or use a chroot environment, either.
you need to do a decompiler to that jar. You can use : http://jd.benow.ca/
Then you need to change that class that have the InputStream and then compile again and make the Jar file.

How to correctly import files in a maven project structure?

I have a configuration file in xml format, that I need to load into my java code. While testing, I have imported it through it's absolute URL, but now I am about to compile and deploy the project as a jar, and that won't work anymore.
From previous experience, I think the right way to do this, is to use the ClassLoader, but I'm having some difficulties. Maybe because of my project setup, I do not know. I think I would be able to make this work, as I ahve done in the past, but I really want to make sure I do it the standard, conventional and/or correct way, so that I do not need to experiment every single time this comes up.
Here is the code I've tried to implement: http://www.mkyong.com/java/java-read-a-file-from-resources-folder/
However, this code:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
I could not use, due to needing the file in a static method of an abstract class. Therefor I switched it out with the following code:
ClassLoader classLoader = XmlConfigLoader.class.getClassLoader();
File file = new File(classLoader.getResource("configuration.xml").getFile());
The XmlConfigLoader is the containing Class. "configuration.xml" is located in the src/main/resources-folder, just as "file/test.xml" is in the example
I've run the code in debug-mode, and found that the file has the wrong path. Instead of looking in src/main/resources, it points to target/classes
Is there a setting option for default resource folder that I need to set?
Is src/main/resources the conventional place to store files like this?
Is my way of loading the ClassLoader correct in this setting?
As an additional info, this is a Maven project.
UPDATE:
My Current code actually works perfectly, apart from a single bug. The file is automatically transferred to the target/classes folder at compile time. However, whitespaces in the url are replaced by %20, and I have to manually change them back in order to make the system find the file. I am sure there is a better solution to this. Anyone?
It makes sense that the file has the path "target/classes", as this is the Class-Path in your jar's manifest file. If you want to get it to look somewhere else, edit the manifest file and append the resource classpath to it.
There are more details on how to alter your jar's classpath over at Setting classpath for a JAR
As you are using maven, the easiest thing to do is to put you resource file into the src/main/resources/META-INF directory, and maven will sort it out for you. See http://maven.apache.org/guides/getting-started/index.html#How_do_I_add_resources_to_my_JAR

Java library function to find shadow file in different directory

I often have code where I loop over a directory (including subdirectories) and need to move / copy the file to a different directory. What I find tedious is the process of identifying where the file will go. I have often done that, usually like this:
File shadow = new File(sourceFile.getAbsolutePath()
.replace(
sourceFolder.getAbsolutePath(),
targetFolder.getAbsolutePath()
)
);
My question: is there a standard routine to do this or something similar in any major open source library? I didn't find one in Commons IO anyway...
I am not looking for complete move / copy solutions, I know tons of those. I just want the equivalent of the above code.
An Example, as requested:
Source folder:
src/main/resources
Target folder:
target/classes
Source file:
src/main/resources/com/mycompany/SomeFile.txt
Target file (the one I'm looking for):
target/classes/com/mycompany/SomeFile.txt
(I usually do stuff like this in a maven context, hence these folders but they could be non-maven folders, as well, the question has nothing to do with maven)
What you are looking for I have never found either but it will exist soon when JDK 7 (eventually) crawls out the door.
Path.relativize(Path) (Java 7 API)
For now I would stick to your current solution (or roll your own equivalent of the above).
Have you seen the org.apache.commons.io.FilenameUtils concat method? It takes a base directory (your target) and file-name to append. You would need to calculate the sourceFolder prefix ("src/main/resources".length()) and do a substring. Something like:
File shadow = new File(FilenameUtils.concat(targetFolder.getAbsolutePath(),
sourceFile.getAbsolutePath().substring(prefixLength));
Not much better than rolling you own though.
Apache's org.apache.commons.io.FileUtils also has functionality that you might use although I don't see a specific solution to your question:
FileUtils.moveFileToDirectory()
FileUtils.copyDirectory()
FileUtils.moveDirectory()
You could use copyDirectory with a FileFilter to choose which files to move over:
FileUtils.copyDirectory(File, File, FileFilter)

lambdaj installation

we have downloaded jar files for lambdaj and its dependencies which are again jar files.
we do not know how to go about it. we have copied these files in the
C:\Program Files\Java\jre6\lib\ext
have set the class path in environment variales as:
variable: classpath
path: C:\Program Files\Java\jre6\lib\ext
but we do not know how to go further. we want to run some lambdaj programs.
can anyone suggest how to run lambdaj programs?
You would run a Java program that requires lambdaj in exactly the same way you'd run any other java program with an external dependency, i.e. by invoking the java executable passing in the fully-qualified name of the Main class, or the JAR with an appropriate manifest, or by deploying it in a servlet container, etc. Additionally you should be putting the LambdaJ JAR on the classpath for this invocation, not in the lib folder for your entire JVM.
What have you tried so far and why/how is it not working? Your question at the moment is a bit analogous to "I want to use Microsoft Word to view some Word documents, how do I do this?".
Update for comment 1: You said "it's not working". That doesn't help anyone address your problem as it gives no clue what you expected to happen and what you observed, only that they were different. As for where JAR files can be stored - you can put them in any directory, so long as that directory is on the classpath (or you add it to the classpath) of the Java application that runs. The canonical place to put external dependencies is in a folder called lib below the root of your project, but the important thing is that you choose somewhere consistent and sensible.
It sounds like you don't quite grok Java and classpaths yet. If you have followed some tutorials and are still stuck, ask for help to let you understand. Adding more detail to your question, including the layout of your files, the commands you issued, and the response that came back would be useful too.
If you are using Netbeans create a project and right click on the Libraries folder within the desired project. Click Add JAR/Folder...

Categories