Java - read files from different maven modules - java

I have an application consisting of three modules: Module A, Module B and Module C (which is a web module). I am using Maven to build the application.
I have the following logic implemented: Module A is included in Module B using a maven dependency and Module B is included in Module C, also by using a dependency (I have separate pom files for each module). Module C is the one that gets deployed.
In Module C I want to have a folder called files, that would contain some content files. This particular folder would be located under the webapp folder. I want to be able to read these files in Module B.
Is there a way to do this? I have tried reading files with getClass().getResourceAsStream("files/file_name") but the returned value was null.

Most clean solution:
Create a new module D.
Put the files into D/src/main/resources/WEB-INF/
Add D as a dependency to B
That makes the files available to B as resource on the classpath while keeping them mostly separate from everything else. Note that to get the files, you have to use
getClass().getResourceAsStream("/WEB-INF/...");
otherwise Java will try to load them relative to the current class.
Be careful that you don't have file in C and D with the same names. If you do, then it can be somewhat random which file Java will pick.

You should consider to put all these files into /src/main/resources directory in order to allow these files being in the application classpath when it is deployed. So, you can consider from your B module that all those files are available in the classpath.
Obviously, you have to take in consideration to copy those files in the /src/main/resources module B's directory.

Related

How to make file from dependency JAR accessible during command line execution?

I have 2 projects:
Project A has folder/file.ext in src/main/resources. When built, it is present in a.jar.
Project B is referencing folder/file.ext somewhere in the code.
I can not change project A or B or how they're built.
When running project B from the command line with:
java -cp a.jar com.mycompany.mygroup.MainClass
I am getting a FileNotFoundException.
I'd like to know if there's a way to make this work, where folder/file.ext is made visible/available to the main class of project B without having to build a fat jar or anything like that.
Thanks.
Try adding another source folder in Project A, with the contents of Project B.
Not really sure why you would need two different projects, instead of adding all the code in one project with different packages/folders.

How to read file from file system during Maven build of module

I have a Maven project A (packaged as a pom) containing Maven module project B (packaged as a jar).
Project B is also physically in the root of project A.
When B is being built, a plugin indirectly uses my code (inside B) to access a property file in its src/main/resources location.
When I build project B directly (mvn clean install) the code can easily find that file by using new File("src/main/resources/foo.properties");
However when I try to build project A, it first will try to build the module B, and in that case it cannot find the property file.
Apart from the 'new File' variant, I have tried using
this.getClass().getClassLoader().getResourceAsStream("src/main/resources/foo.properties");
and I tried using Spring:
Resource resource = new ClassPathResource("src/main/resources/foo.properties");
Both also with a "/" prefix. But the file simply cannot be found.
Why is that? Might it be looking for the file in the root of A? Is it possible to find the file in module B when building A?
Thanks!
new File("src/main/resources/foo.properties");
This is a path relative to the working directory. The working directory is wherever you called maven. So that's why it won't work when calling maven anywhere other than the directory of module B.
this.getClass().getClassLoader().getResourceAsStream("src/main/resources/foo.properties");
This won't work because the classpath is where maven put the classes, that is, target/classes.
What you need to do is add this file as resource in the maven build, then use the getResourceAsStream idea with the correct path. Since you used the standard maven layout, you probably don't need to anything and just use
this.getClass().getClassLoader().getResourceAsStream("foo.properties");

What is the difference between modules and JAR files?

I am learning about Java 9 from What's New in Java9 and one of the hot topics in the discussion is The Modular JDK.
Are JAR files modules?
How is a module different from a JAR file?
Module: A new language feature introduced in Java 9 (similar to class, interface, package, etc.) that consists of a collection of packages, similar to how a package consists of a collection of types.
JAR: An archive file format that bundles code and resources and which can be loaded by the JVM.
More specifically, a module is defined as follows:
In order to provide reliable configuration and strong encapsulation in a way that is both approachable to developers and supportable by existing tool chains we treat modules as a fundamental new kind of Java program component. A module is a named, self-describing collection of code and data. Its code is organized as a set of packages containing types, i.e., Java classes and interfaces; its data includes resources and other kinds of static information.
...
A module’s self-description is expressed in its module declaration, a new construct of the Java programming language.
...
A module declaration is compiled, by convention, into a file named module-info.class, placed similarly in the class-file output directory.
A module can be compiled into a Jar file, in which case the Jar file is labelled a modular Jar file:
Existing tools can already create, manipulate, and consume JAR files, so for ease of adoption and migration we define modular JAR files. A modular JAR file is like an ordinary JAR file in all possible ways, except that it also includes a module-info.class file in its root directory.
Some other differences between a module and a JAR:
Modules can require other modules in order to allow accessing dependent classes by the requiring module. A Jar has no such dependency concept.
A module can decide which classes and interfaces to export to other modules that require it. A Jar has no such encapsulation mechanism.
A module can be compiled into a modular Jar file, but some modules (e.g. JDK modules) are compiled into another format called JMOD.
The name of a JAR can be changed. As long as the JVM classloader finds the needed class on the classpath (which can be composed of a single JAR, multiple JARs, or a mix between directories or JARs), the name of the JAR file can be anything. However, the name of a module can be explicitly referenced in the declaration of other modules, and such the name defines it and cannot be changed freely.
Strictly speaking, a module is a run-time concept. As others have quoted from The State of the Module system:
A module is a named, self-describing collection of code and data. Its code is organized as a set of packages containing types, i.e., Java classes and interfaces; its data includes resources and other kinds of static information.
This is very similar to JARs, but...
JARs have no meaningful representation at run time
JARs are not "self-describing", which in this case means they do not have a name that the JVM cares about, can not express dependencies or define a proper API
This leaves the question, where do modules come from? There are various ways but the most prominent one for developers is the modular JAR. A modular JAR is just like a plain JAR, but it contains a module descriptor, a file module-info.class that was compiled from a module-info.java. It is that file that defines a module's name, dependencies, and APIs.
So there is a strong connection between JARs and modules: JARs are the containers from which the module system creates modules and (at the moment) each JAR can only contain a single module. It is important to note that even on Java 9 JARs do not have to be modular - plain JARs are totally fine.
Are JAR files Modules? How Module is different from JAR file?
No, a Java Archive is not a Module.
Just for an example, while classes of the same package could have been spread across JARs, the same package now can not be read from multiple modules.
A JAR is a file format that enables you to bundle multiple files
into a single archive file. Typically this contains the class files
and auxiliary resources associated with applets and applications.
on the other hand (I'd tried describing this here ~> java-module as well)
A module is a named, self-describing collection of code and data. Its
code is organized as a set of packages containing types, i.e., Java
classes and interfaces; its data includes resources and other kinds of
static information.
This also consists of the module declaration as specified with the help of module-info.java.
Each module definition is either
A module artifact, i.e., a modular JAR file or a JMOD file containing a compiled module definition, or else
An exploded-module directory whose name is, by convention, the module's name and whose content is an "exploded" directory tree corresponding to a package hierarchy.
As introduced with the module system, a modular image is composed of modules rather than JAR files.
Modularity is foreseen for with dynamic configuration in terms of Modular WAR file as well.
But for the ease of adoption of Modules a Modular JAR file, was introduced in JDK9, such that lets say for a module consisting of a module-info.java such that
module com.foo.bar { }
and other java classes as
com/foo/bar/alpha/AlphaFactory.java
com/foo/bar/alpha/Alpha.java
Existing tools can already create, manipulate, and consume JAR files. A modular JAR file is like an ordinary JAR file in all
possible ways, except that it also includes a module-info.class file
in its root directory. A modular JAR file for the above com.foo.bar
module, e.g., might have the content:
META-INF/
META-INF/MANIFEST.MF
module-info.class
com/foo/bar/alpha/AlphaFactory.class
com/foo/bar/alpha/Alpha.class
...
A modular JAR file can be used as a module, in which case its module-info.class file is taken to contain the module’s declaration.
It can, alternatively, be placed on the ordinary class path, in which
case its module-info.class file is ignored.

Path for IClasspathEntry must be absolute . Eclipse moving out project

My project has the following directory structure:
Projects
|---------A
|---B
|---C
Project C uses src files of B. In eclipse I import project A and classpath file present under A contains B's and C's source folder as classpathentry src. Thus, even when I am on any of C's java file which uses variables declared in B's java file, I am able to navigate to them using Ctrl+Click on the variable.
Now my requirement is to move out C to the level of project A:
Projects
|--------A
|---B
|--------C
Now A and C will have different classpath files. When in C's classpath file I try to give relative path of B's source folder. I get the following error in eclipse:
Illegal entry in '.classpath' of project 'B' file: Path for IClasspathEntry must be absolute
I tried out creating a jar of B's source file and giving the classpathentry of the jar in C's classpath file. But, with this approach , I loose out being able to navigate to B's java file from C's java file using Ctrl+click.
I cant give absolute path because the code is shared and different systems will have different path.
So, how do I specify my project C's dependency on B's source folder in .classpath file so that I retain the navigation through Ctrl+Click

Copy directory from another project during build

In project A I have a dependency to project B which has the CSS resources directory.
Due to some framework issues I need to copy the CSS directory to project A during the build. How to do it? The css directory is inside src/main/resources/css therefore it goes to /css inside the .jar
No need to copy because Servlet 3.0 Specs sais in part 3.6, you can place the css in META-INF/resources into the jar of your project B.
It works great except maven-tomcat-plugin.
This is where the file ends up:
<outputDirectory>${basedir}/target/blah</outputDirectory>
This is where it is copied from:
<directory>src/main/otherresources</directory>
There would be an or tag to tell the file name(s)
Multiples
You need multiple executions with different ids for multiple folders:
There are two solutions. But before you have to know the path from project A to project B.
You can use the maven resource plugin.
There's a goal to copy a resource to an output directory.
Or, you can use the maven ant plugin.
Here is an example : http://www.javacodegeeks.com/2013/07/how-to-run-ant-targets-with-maven.html

Categories