i have a maven project that has two dependencies: DependencyA and DependencyB. In each of the dependencies there is a class, lets call it FooClass.
Now there is a problem, because one class of my project needs the FooClass of DependencyA and another class needs the FooClass of DependencyB. But both classes load the FooClass of DependencyA.
Can i solve this problem with maven? Or do i have to think about the design of my project structure?
You should avoid getting two classes with same name in same package. This would lead to the idea that you have two modules of different versions of one code...
It would not be an issue if you had for instance com.yourcompany.yourproyectA.FooClass and com.yourcompany.yourproyectB.FooClass.
This scenario happens often and I have never had an issue with maven.
Regards
If two libraries need two different versions of the same library, I recommend to use a module system such as OSGi.
Related
I want to use a class and in my pom there are two dependencies that support it: dependency1 and dependency2.
Using the class with dependency1 crashed my program, so I deleted it completely from pom and left dependency2 as it was and the code was working.
How do I tell maven to build my class with dependency2 and not dependency1, without deleting dependency1 (in case dependency1 contains something that I want to use in my code later on)?
You cannot sensibly use two libraries that contain classes with the same qualified class names.
So
either restrict yourself to one of them.
or use the Maven shade plugin to relocate the packages of one of the dependencies.
when you are importing the dependency in your respective class just check for the entire address of the dependency (the whole package structure) and make sure that you are using the dependency from the dependency2.
Also, if you have removed dependency1 from the pom.xml, maven will not put the dependency1 in the target folder which will be generated while building the project.
It's very unlikely to have the same class with same package name on two different dependencies.Because artifactIds are unique for each dependency even it belongs to the same groupdId. So if you solved your issue by using the dependency2's class then that's the class you need. And as you asked if you need dependency1 for any other task keeping the dependency1 on your pom.xml won't be a problem.Only thing that you need to take care is importing the class that you need exactly from dependency2.So please check your import statements in the class and see if it's importing the class from dependency2.
Consider the following situation. I have two gradle (sub-)projects called "A" and "B". A defines some classes/interfaces that are being referenced by B. So B has a compile dependency to A. Now A is a web server that should be started with B on the classpath. How do you achieve that with gradle?
Of course it is not possible to add B as compile dependency to A because that would mean a circular dependency between A and B. Even adding B as runtime dependency to A did not work because then compile errors in B state that referenced classes from A do not exist. But why?
One solution would be to move code from B into A but I really would like to separate that code because there might be another implementation of B later that I want to swap easily in A (e.g. by exchanging the jar in runtime classpath).
Another solution I was thinking about is to separate classes from A referenced by B into a new module and make both A and B depend on that new module. This sounds valid but that would imply to move persistence layer from A to that new module which feels wrong.
Additional information: A is a Spring boot web application with persistence layer, web services etc, B produces a JAR.
Circular dependencies are a well-known problem when you try to get Dependency Injection. In this case, you have something similar but at a module level
The only way I see you can solve your issue is by creating a third module C with the common code (probably the A interfaces referenced by B)
This way you can compile C (it doesn't have any dependencies), A (it depends on C), and B (it depends on C) and launch A with B in its classpath
Everytime you end up with circular dependency you probably should introduce another entity to break the cycle.
Have a look at my explanation in this other QA article (it's dealing with packages and classes, but idea is the same): What does it mean and how to fix SonarQube Java issue "Cycles between packages should be removed" (squid:CycleBetweenPackages)
I'm having an Android Studio project with 2 modules: A and B. (I do not include here the Annotation Processor and the Annotations module)
B depends on A.
B is an Android Library Module, and A is simple Java library Module. I'm also having an Annotation Processor on module B.
The problem I'm facing is:
I want to generate some code, based on annotated files placed in both modules - A and B. The problem comes from the way the Annotation Processor works - only with source code files *.java - not with compiled *.class ones. Unfortunately, during the compilation of B, the Annotation Processor doesn't have access to those source files from A...
The only thing, I was able to think about as a kind of solution, even an ugly one, was to include the folder with the annotated classes from module A as a source set to module B. This way I give module B access to those files during compilation.
sourceSets {
main {
java {
srcDirs = ['src/main/java', '../module_A/src/main/java/path/to/annotated/classes/folder']
}
}
}
That solves the problem - now the Annotation Processor has access to all the annotated classes from both modules, but...
Unfortunately, it introduces another issue... those annotated classes from module A, are now compiled twice. And they are included in the module A's JAR file and in the module B's AAR file.
Question 1: Is there another way to access those source files of module A, from the Annotation Processor running on B??? (From what I was able to find, the answer is NO, but checking...)
Question 2: How can I exclude those compiled files (the repeated ones) from the AAR final package of module B?
Question 3: Maybe... that's an absolutely wrong approach? Any suggestions?
Thanks in advance!
Nop, you can not achieve what you want using just java.lang.model API. At least not without some additional tricks.
The issues is not with binary-vs-source. Annotation processors can use Elements#getTypeElement to interospect compiled classes as well as source-defined classes:
Elements elementUtil = processingEnvironment.getElementUtils();
TypeElement integerClass = elementUtil.getTypeElement("java.lang.Integer");
TypeElement myClass = elementUtil.getTypeElement("currently.compiled.Class");
But you still need to have class on compilation classpath to observe it, and the class must be in process of being compiled to be visible to getElementsAnnotatedWith.
You can work around later limitation by using a tool like FastClasspathScanner: it will use it's own mechanisms to find annotations in compiled bytecode, and report them to you separately from compilation process. But you can not work around the classpath issue: if you don't have some dependency in compilation classpath, it can not be processed. So you have to compile modules together — either by merging them into one (as you did) or via declaring one to depend on another. In later case you might not be able to use getElementsAnnotatedWith, but getTypeElement and FastClasspathScanner will work.
I am working on a customization for an ERP system in Java. In my customization I want to use Apache POI 3.10.1. Therefore I have integrated the jars poi-3.10.1-20140818.jar and poi-ooxml-3.10.1-20140818.jar.
However, these jars contains several classes that are already included in the core code of the ERP System, but have differences.
If the core ERP classes override the POI classes, the customization throws a Runtime exception. Possibly the same will happens with a core functionality if the POI classes override the core classes.
What is a best practice for dealing with a problem like this?
My customization is a relatively isolated functionality.
There are two approaches to solving this problem:
You can isolate the library from the ClassLoader that loads the other version of POI. for now, I assume that the ERP system is on the class path such that you need to isolate the library from the system class loader. You can do so by creating a new instance of an URLClassLoader which you then point to the jar files containing the newer version of POI. Make sure to also add all transient dependencies such as for example commons-codec to avoid class loading issues. Also, note that transient dependencies can have transient dependencies by themselves.
In order to hide the class path from a class loader, you would set the bootstrap class loader as a direct parent which is represented by null:
new URLClassLoader(new URL[]{ new URL("poi-3.10.1-20140818.jar"), ... }, null);
With this class loader, you can query for the newer version POI classes by something like
Class.forName("org.apache.poi.hssf.usermodel.HSSFWorkbook", true, urlClassLoader);
for retreiving the new version of the HSSFWorkbook. Note however that any direct reference to HSSFWorkbook by a literal would be resolved by the class loader of the executing class which would of course link the old, incompatible version of a class. Thus, you need to use reflection for all your code. Alternatively, you add a class to the URLCLassLoader which contains all your logic and only invoke this class via reflection. This is a cleaner approach, in general. For example, you could add a class that implements a bootstrap class such as Callable which you then can use from any different context as for example:
Callable<File> sub = (Callable<File>) Class.forName("pkg.Subroutine",
true,
urlClassLoader);
File convertedFile = sub.call();
Alternatively, you can repackage the second POI dependency into another name space. After doing this, the classes are not conflicting anymore as their names are not longer equal. This is probably a cleaner approach as you can then use both libraries from the same class loader and you avoid reflection.
For repackaging a dependency into another name space, there are tools like the Maven Shade plugin that can help you with this task. Alternatives are jarjar for ant or the Shadow plugin for Gradle.
If you are using Servlet 3.0 API and you can change some configuration, "web fragments" can be utilized for such kind of situation. Following is the explanation: http://www.oracle.com/technetwork/articles/javaee/javaee6overview-part2-136353.html#webfrags
i am using Maven 3 and trying to build a jar.Now there is a class which is present in two different dependent jars. Though the methods in the interface is different but maven is trying to get the method defined in the class in different jar . So how to ensure that the class is picked from another jar?
E.g the required class is xyz.class and is present in two differnet jars as:
jar1: com/mycompany/xyz.class
and jar2: com/mycompany/xyz.class
The xyz.class in jar1 is what maven is picking up i suppose but i want the one in jar2
Thanks
This is more of a Java compilation problem than Maven. Check out the answers for:
how to load same class from different jars
You'll need to define your custom class loader for this kind of situation.