I have some amount of child maven modules in parent module.
How can I get access from one module to resources of another and to have this solution stable in jar file ?
I tried something like: (resource.txt - is situated in first module, and code is executing in second)
String pathToFirstModuleResource = ClassFromFirstModule.class.getClassLoader().getResource(resource.txt).getFile();
But it points me to ...firstmodule/target/classes/resource.txt, so it works almost good, but returns not a resource folder, but target/classes. Why it returns this targets folder, though should to return ...firstmodule/resources/resource.txt?
Why it returns this targets folder, though should to return ...firstmodule/resources/resource.txt?
No.
It looks like you configured resources being threaded by your IDE as a souce folder.
Therefore the folder resources only exist in your development environment. At runtime the file is simply copied to the root of your jar, which merely is the content of target/classes.
Related
It worth to mention that I am using maven as my build management tool. I have a jar (let's call it dep.jar) which will be included into the final project (final.jar) as dependency.
dep.jar has a class with main method.
I need to have several entry points (classes with main methods) within my final.jar's top level directory so I can use entry point depending on my need. Including one from dep.jar.
I considered:
Changing META-INF/MANIFEST.MF file within jar. As Oracle stated that is not possible to reference main classes inside jar's dependencies (BOOT-INF/lib directory) -> https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html;
Uber jar - not an option, I am dependent on jar directory structure inside Java code base
Using special class loader like this one http://www.jdotsoft.com/JarClassLoader.php. But it implies changing final.jar's main method which I cannot do due to project restrictions.
Using maven-dependency-plugin but it can unpack inner jar (dep.jar) and copy classes to maven working directory target which during packaging phase will be packed to BOOT-INF/classes directory. Again, I cannot reference main classes from there. If I unpack and copy them somewhere different than target - copied classes will not appear in my final.jar
Is there any other plugin or option how to add classes from final.jar dependant jar dep.jar during JAR build to final.jar's top level?
EDIT:
final.jar project looks like this:
final.jar
|_______BOOT-INF
|_______lib
| |_______dep.jar (contains main class I want to invoke)
|_______classes
|__________dir (directory I want to copy on demand with help of CLI)
I found a solution here Spring Boot - How to specify an alternate start-class? (Multiple Entry Points). Ended up using -Dloader.main property when launching jar.
Command line looks like these: java -jar -Dloader.main=<main_class> ./final.jar
I need to get a resource from inside the root of the application when its packed into jar. My project is like this:
ProjectRoot
resource.txt //want to access from here
src
main
java
package1
package2
package3
Main.java
target
app.jar
classes
resource.txt //works when here
package1
package2
package3
Main.class
I use this code:
Path path = Paths.get("resource.txt");
When run before packaging into a jar, it finds the file just fine (inside ProjectRoot). When running the jar, it can't find it, and transforms this path to target/resource.txt.
This code:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"resource.txt")));
when run before packaging looks for the resource inside target/classes. After packaging it claims to taking the resource from .../target/app.jar!/resource.txt.
This code:
BufferedReader br = new BufferedReader(new InputStreamReader(new Main().getClass().getClassLoader().getResourceAsStream(
"/resource.txt")));
I can't understand where's looking for the resource, but it doesn't seem to be ProjectRoot.
All I want to do is to place the resource inside ProjectRoot and be able to access it from both outside jar (when running the class files from IDE) and inside (after having packaged the files into a jar file using Maven).
EDIT: I NEED THE CODE TO WORK BOTH FOR PRE- AND POST- packaging. MEANING: If I run a Main.java FROM INSIDE IDE IT WOULD GET THE RESOURCE; IF I PACKAGE EVERYTHING INTO JAR AND RUN JAR IT WOULD GET THE RESOURCE - ALL WITH THE SAME CODE.
Use: Main.class.getResource("/resource.txt").
Note that your attempt using any call to getClassLoader is strictly worse (it's more text, and will fail more often, because that class loader can in exotic cases be null (specifically, when you're part of the bootstrap loader), whereas calling getResource directly on the class always works.
The reason your snippet does not work is because when invoking getResource on the classloader, you must NOT start the resource with a slash. When invoking on a class directly, you can (if you don't, it'll be relative to the package of the class you're calling it on, if you do, it'll be relative to the root).
TL;DR: Of the forms SomeClass.class.getClassLoader().getResource, getClass().getResource and MyClass.class.getResource, only the last one is correct, the rest are strictly inferior and therefore should not be used at all.
Maven uses something called the Standard Directory Layout. If you don't follow this layout then the plugins can't do their job correctly. Technically, you can configure Maven to use different directories but 99.999% of the time this is not necessary.
One of the features of this layout is that production files go in:
<project-dir>/src/main/java
All *.java files
<project-dir>/src/main/resources
All non-*.java files (that are meant to be resources)
When you build your project the Java source files are compiled and the *.class files are put into the target/classes directory; this is done by the maven-compiler-plugin. Meanwhile, the resource files are copied from src/main/resources into target/classes as well; the maven-resources-plugin is responsible for this.
Note: See Introduction to the Build Lifecycle for more information about phases and which plugins are executed by which phase. This Stack Overflow question may also be useful.
When you launch your application from the IDE (possibly via the exec-maven-plugin) the target/classes directory is put on the classpath. This means all the compiled classes from src/main/java and all the copied resources from src/main/resources are available to use via the classpath.
Then, when you package your application in a JAR file, all the files in target/classes are added to the resulting JAR file (handled by the maven-jar-plugin). This includes the resources copied from src/main/resources. When you launch the application using this JAR file the resources are still available to use via the classpath, because they're embedded in the JAR file.
To make resource.txt available on the classpath, just move:
<project-dir>/resource.txt
To:
<project-dir>/src/main/resources/resource.txt.
Then you can use Class#getResource with /resource.txt as the path and everything should work out for you. The URL returned by getResource will be different depending on if you're executing against target/classes or against the JAR file.
When executing against target/classes you'll get something like:
file:///.../<project-dir>/target/classes/resource.txt
When executing against the JAR file you'll get something like:
jar:file:///.../<project-dir>/target/projectname-version.jar!/resource.txt
Note: This all assumes resource.txt is actually supposed to be a resource and not an external file. Resources are typically read-only once deployed in a JAR file; if you need a writable file then it's up to you to use a designated location for the file (e.g. a folder in the user's home directory). One typically accesses external files via either java.io.File or java.nio.file.*. Remember, resources are not the same thing as normal files.
Now, if you were to put resource.txt directly under <project-dir> that would mean nothing to Maven. It would not be copied to target/classes or end up in the JAR file which means the resource is never available on the classpath. So just to reiterate, all resources go under src/main/resources.
Check out the Javadoc of java.lang.Class#getResource(String) for more information about the path, such as when to use a leading / and when not to. The link points to the Javadoc for Java 12 which includes information about resources and modules (JPMS/Jigsaw modules, not Maven modules); if you aren't using modules you can ignore that part of the documentation.
Package
|
|------src/main/java
|------resources
|---- config.properties
In pom.xml, I have set resoucres directory as follows
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
I'm able to get the absolute path of the file. But When I try to read or check whether it is a file or directory, it is return false.
sample.java
File configFile = new File("config.properties");
System.out.println("PATH="+newFile.getAbsolutePath());
System.out.println("IsFile="+newFile.isFile());
System.out.println("CanRead="+configFile.canRead());
Output
PATH=D:\JCB\MyWorkSpace_LunaJEE\MessageProcessor\config.properties
IsFile=false
CanRead=false
Any help will be appreciated.
In pom.xml, I have set resoucres directory as follows
That defines the directory where resources will be stored as part of the Maven build structure - so it specifies where Maven should look for resource files to include in your program. It does not define where files can be found when running your application. It is not really a good idea to change from the Maven conventions, keep it as src/main/resources if you can. If you use external tooling on top of Maven, you may get conflicts otherwise.
What is the important part is what happens with the files when the application is built by Maven when you do for example a mvn clean install.
whatever is in src/main/java is compiled and the classes are put in the target directory, in their proper package structure. The files and directories in the src/main/resources folder are copied to that same target directory. The resources are thus made part of your Java program and are available on the classpath; if you would let Maven build your application into an executable jar at this point for example, the resources will be packaged together with the classes inside that jar.
To properly load the resource files packaged with your application, you should use Java's classloader system. This question's answer demonstrates that in detail. To change your current test code, you would rather do something like this:
InputStream is = getClass().getClassLoader().getResourceAsStream("config.properties");
if(is != null){
// yep, the file exists on the classpath! Now load it with the InputStream
}
The file is not in D:\JCB\MyWorkSpace_LunaJEE\MessageProcessor\config.properties, but in the resources folder there, so it does not exist and thus is neither file nor directory. I would suggest putting it in /src/main/resources and then accessing it via getResourceAsStream( name );
I am busy writing an integration test for a custom annotation processor. In order to do this I have a specific set of .java source files that I am running through javac in order to test my implementation. These are loaded by my test as a resource. This means that my source tree looks something like the following:
/src
/test [test source root]
/java
MyIntegrationTest.java [actual source code]
/resources
MyIntegrationClassFile.java [should be treated as plain text]
With IntelliJ, it is possible to filter what files are copied as resources using the Compiler Settings. So I removed the filter for .java files.
However, for resources to be copied, they need to be in a marked source tree. I also have my resources folder marked as test sources (yes, this is weird).
This is where the problem comes in: If the .java files are in a source tree (in order to be copied as resources), they are automatically compiled. I do not want to compile these files (they may not compile).
I have tried adding the resources to the compiler exclude list (NOT excluding it from the project), but this also results the resources not being copied.
You cannot mark a .java file as plain text, as far as I know, even though this feature is documented for other file types.
How can one mark a .java file as plain content that should be copied and not compiled?
For me it worked when I added the resource folder to the Compiler Exclude List.
Initial setup:
Rebuild project gives me this output:
Now I add the src/test/resources to the Compiler Exclude List:
After rebuild I have this in my output folder:
Using Idea 2016.3.3, go to Project Structure>src>test>resources then right click on it and select TestResources.
Then add an exclusion rule to Settings>Build, Execution, Deployment> Compiler> Excludes for your resources folder.
Also remove .java extension from Settings>Build, Execution, Deployment> Compiler>Resource patterns (you've already done this as I can see).
It works!
Using maven for a project say myproject
it has the following myproject\src and myproject\target, and all the class and resources are copied to myproject\target\classes.
However i found the user.dir or current dir is still myproject, why not myproject\target\classes, how to change the current dir to myproject\target\classes?
Because maven always runs things in the working directory of the pom.xml, unless you configure it differently (which i think you can do in the surefire plugin which is what runs test cases).
If you want to get class folder path,you can following this code :
String path = YourClassName.class.getResource("").getPath();