Add class files to maven as a dependency [duplicate] - java

I have two modules, A and B, they are under the same parent. Now A is requiring for B as dependency. I can't just use jar as dependency type because module B is using spring-boot-maven-plugin, so I was wondering how can I set A's pom configuration to make A depend on B's compiled classes not jar?
- root
- A
- src # module A's source code
- target
- classes # module A's compiled classes
- A.jar # module A's compiled jar output
- pom.xml # module A's mvn config
- B
- src # module B's source code
- target
- classes # module B's compiled classes, HOW CAN I IMPORT THESE TO A?
- B.jar # module B's mvn config
- pom.xml # module B's mvn config
- pom.xml # parent mvn config
parent mvn config
...
<modules>
<module>A</module>
<module>B</module>
</modules>
...
module A mvn config
...
<parent>
<!- pointed to parent ->
</parent>
<dependencies>
<dependency>
<groupId></groupId>
<artifactId>B</artifactId>
<scope>??????????????</scope> # WHAT SHOULD I PUT HERE?
<type>???????????????</type> # WHAT SHOULD I PUT HERE?
</dependency>
<dependencies>
...

First of all: When A depends on the classes of some other module, it necessarily depends on the jar. You cannot depend on parts of a module or just the classes.
So let me sketch a solution:
If B is of <packaging>jar</packaging> (standard, also true if no packaging is given), then you can just use it as dependency. You do not need a scope or type entry.
If B is of some other packaging (including spring-defined packaging types, which I am no expert of), then you should not define a dependency from A on B. Instead, you define a third module C, which includes the classes that are used from A and from B and let both of them have a dependency on C.
Don't try to construct dependencies to non-jars. If you need classes, define a module with these classes and use it when the classes are needed.

Here is good information about maven dependency scope and type.
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
This should work fine for you. (Not tested)
<scope>compile</scope>
<type>jar</type>

Related

How to test within the same module?

In this project I have a modular setup. There is a parent with two modules in it.
Here's a snippet from the parent-pom.xml:
<modules>
<module>moduleA</module>
<module>moduleB</module>
</modules>
Both modules have a module-info.java. Here is the module-info.java for moduleB:
module moduleB {
requires spring.web;
requires static lombok;
requires java.validation;
requires swagger.annotations;
requires slf4j.api;
exports com.example.service
}
Within moduleB there is the main folder and the test folder, like any regular java project. Within the test-folder there is a JUnit5 test, which is trying to test a service within the same package, but in the src-folder.
While trying to attempt this, I get the following error-message:
module moduleB does not "opens com.example.service" to unnamed module #67205a84
As I understand, all of the dependencies which are not part of the module will be packaged in an 'unnamed' module. In this case module #67205a84. Things I expect to be in this module are stuff like Mockito, which I only use for testing. Please correct me if I'm wrong about this assumption.
When I open up my moduleB (by adding the word 'open' before the moduledecleration), the test runs smoothly. But obviously this is not what I want.
So my question really is: can I open up to the unnamed module so that my tests can run, but my module stays closed for anything other than the test?
Here's a simplified overview of the directory structure.
- parent
|
-> - pom.xml
- moduleA
- moduleB
|
-> - pom.xml
- src
|
-> - main
|
-> - java
|
-> - module.info
- com.example.service
|
-> - ModuleBService.java
- test
|
-> - java
|
-> - com.example
|
-> - Application.java
- com.example.service
|
-> - ModuleBServiceTest.java
As it turns out, the location of the Application.class is relevant. The module I am trying to test does not have a class annotated with #SpringbootApplication, because it's just a library. To test it's functionality, I have to start a SpringbootApplication in test. When the Application.java is in the same package as the ModuleBServiceTest.java, all is well. When I move it out in another package the error-message from above occurs. Why is that?
What you can do is to configure the surefire plugin to open the module to the unnamed modules in the POM of your moduleB
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
<!-- Allow access to the tests during test time -->
--add-opens moduleB/com.example.service=ALL-UNNAMED
<!-- Add export to test-util classes to moduleC if it wants to reuse these -->
--add-exports moduleB/com.example.service.test.util=moduleC
<!-- Prevent any illegal access to modules -->
--illegal-access=deny
</argLine>
</configuration>
</plugin>
</plugins>
</build>
I've also added a sample where you can explicitly export some test utility classes to a further module in case it wants to access these
As it turns out, the location of the Application.class is relevant. The module I am trying to test does not have a class annotated with #SpringbootApplication, because it's just a library. To test it's functionality, I have to start a SpringbootApplication in test. When the Application.java is in the same package as the ModuleBServiceTest.java, all is well. When I move it out in another package the error-message from above occurs. Why is that?
AFAIK Spring Boot will scan its package and any sub-packages for components, services and the like and will add these automatically to its configuration. If the application is not directly in an ancestor path it might not be able to find your test class, though the information given is a bit limited to be honest.

Java how to use methods from another module in Intellij

I have added two projects as modules in empty intellij project.
Then I added in pom of module B following dependency to first project(module A):
<dependency>
<groupId>Tests</groupId>
<artifactId>Group</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
This allows me to import classes from module A into module B.
But I can't see any method from that module (it looks like classes are empty or they have only private fields/methods).
What am I missing? What should I do to see all public methods/fields from A module?
Thanks
Kamil
If you are adding one of them as a dependency, you can avoid to join them as modules. For local purposes, you can build(mvn clean package) one of them and add that as a dependency to another one. You can check relevant .class file to see the access levels of the class members.
For multi-module projects, please, see: https://www.jetbrains.com/help/idea/creating-and-managing-modules.html

<Maven>How to add class files as dependency (not jar) in maven project?

I have two modules, A and B, they are under the same parent. Now A is requiring for B as dependency. I can't just use jar as dependency type because module B is using spring-boot-maven-plugin, so I was wondering how can I set A's pom configuration to make A depend on B's compiled classes not jar?
- root
- A
- src # module A's source code
- target
- classes # module A's compiled classes
- A.jar # module A's compiled jar output
- pom.xml # module A's mvn config
- B
- src # module B's source code
- target
- classes # module B's compiled classes, HOW CAN I IMPORT THESE TO A?
- B.jar # module B's mvn config
- pom.xml # module B's mvn config
- pom.xml # parent mvn config
parent mvn config
...
<modules>
<module>A</module>
<module>B</module>
</modules>
...
module A mvn config
...
<parent>
<!- pointed to parent ->
</parent>
<dependencies>
<dependency>
<groupId></groupId>
<artifactId>B</artifactId>
<scope>??????????????</scope> # WHAT SHOULD I PUT HERE?
<type>???????????????</type> # WHAT SHOULD I PUT HERE?
</dependency>
<dependencies>
...
First of all: When A depends on the classes of some other module, it necessarily depends on the jar. You cannot depend on parts of a module or just the classes.
So let me sketch a solution:
If B is of <packaging>jar</packaging> (standard, also true if no packaging is given), then you can just use it as dependency. You do not need a scope or type entry.
If B is of some other packaging (including spring-defined packaging types, which I am no expert of), then you should not define a dependency from A on B. Instead, you define a third module C, which includes the classes that are used from A and from B and let both of them have a dependency on C.
Don't try to construct dependencies to non-jars. If you need classes, define a module with these classes and use it when the classes are needed.
Here is good information about maven dependency scope and type.
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
This should work fine for you. (Not tested)
<scope>compile</scope>
<type>jar</type>

Maven dependencies sharing class loader

I have a 3 maven projects with different groupIds/ArtifactIDs. Project A has depedencies on projects B and C. and I'm using maven-failsafe-plugin in order to run B's and C's integration tests from A during build:
(In project A) :
<dependency>
<groupId>com.group.b</groupId>
<artifactId>artifactB</artifactId>
</dependency>
<dependency>
<groupId>com.group.c</groupId>
<artifactId>artifactC</artifactId>
</dependency>
But for some reason, when I run this line in Project C -
URL path = ThisClass.class.getResource("/someResource");
It gives me the jar location of Project B, as in the classloader is in projectB
Both B and C have a resource directory called /someResource and thats why its failing. When I do the same call but to a resource that exists ONLY in C, then the class loader is correct:
(Code written in Project C)
URL path1 = SomeClass.class.getResource("/directory1");
System.out.println(pathA.getPath()); // .m2/../ProjectB.jar!/directory1
URL path2 = SomeClass.class.getResource("/directory2");
System.out.println(pathB.getPath()); // .m2/../ProjectC.jar!/directory2
Since directory1 exists in B and C, then A gives me B's class loader (the first depedency), and when its a directory that exists only in C, then I get the correct class loader
If I comment out the dependency to B, then all works good.
I've also added <useSystemClassLoader>false</useSystemClassLoader> to maven-failsafe and that didn't help
I've also tried <useManifestOnlyJar>false</useManifestOnlyJar> which didn't change anything
======UPDATE=======
If anyone has a suggestion as to how I can run test jars externally (jenkins, maven, doesn't matter) without having their class loader mixed up

Maven Cyclic reference when root pom has plugin which is common to two or more child modules

So i have a project with the structure as follows-:
pom.xml
\
---Module A (Child)
---Module B (Maven child plugin with Dependency on A)
---Module C (Child Dependency on A)
---Plugin B
the parent pom looks like the following
<modules>
<module>A</module>
<module>B</module>
<module>C</module>
</modules>
<plugins>
<plugin>
B
</plugin>
</plugins>
POM for A has no dependencies and has just the parent-:
parent
POM for B has
<parent>parent</parent>
<dependencies>
<dependency>A</dependency>
</dependencies>
POM for C also has
<parent>parent</parent>
<dependencies>
<dependency>A</dependency>
</dependencies>
With the above,maven gives me the following error-:
org.apache.maven.ProjectCycleException: The projects in the reactor contain a cyclic reference:
Edge between 'B' and 'A' introduces to cycle in the graph A->parent->B->A
What am i doing wrong and how should i structure the project?I want to keep everything in one place.
You should move your plugin declaration inside of the parent into the pluginManagement tag so that you can set the version (but not actually use it), and then in individual projects that need the plugin, simply name the plugin in your plugins tag.
Additionally, A cannot use plugin B if B depends upon A. Sorry, can't be done; You'll need to find a way to make one do without the other. Additionally I don't think B can use itself as a plugin, since that has to resolve before it can even begin to build B. C and any other modules (D, E, etc.) can use B though.

Categories