How to find java class dependency tree - java

I am trying to pull a bunch of classes and packages from a large project and create a separate standalone module out of it. Now when I try to compile these classes, due to dependency on other classes, I end up with very large number of compiled classes which I don't intend to have in the standalone module.
e.g. if this is class dependency A -> B -> C -> D. And I compile A, I will end with A.class, B.class, C.class and D.class. I want to break the dependency on class D and refactor the code such that class D doesn't become part of the module. But for this to happen, I would have to know the dependency path(s) for given class A and class D.
I tried searching SO but without success so far.

For future stumble-upons: At least as of IntelliJ 2020.1, you can find the list of classes a class would need (or depend upon), recursively, by:
Right click on the class name
Click Analyze > Dependencies
Choose File .java
You can also specify the depth required
(For finding which classes depend on the class in question, choose Analyze > "Backward Dependencies", instead)
For other cases or alternatives: How do I get a list of Java class dependencies for a main class?

Related

Choose which dependency to use in class

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.

How to solve circular dependency in gradle multi-project build

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)

Android Annotation Processor accessing Annotated classes from different modules

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.

How to create a JAR with only the class files needed by a given class

I have a directory full of hundreds of class files that have been constructed by a previous compilation. Let's say I have a class which only depends upon a small subset of those generated class files. Is it possible to create a JAR which only has the dependencies for the given class?
EDIT: Please note that I am not speaking of the library level dependencies (i.e. JARs). When I refer to dependencies above, I am referring to the sort of dependency that results from class A calling class B. Perhaps an example would be good. Imagine I have the following classes in my project.
public class A {
B bField;
}
public class B {
C cField;
}
public class C {
B bField;
}
Now imagine I want to build a JAR with class B, then the JAR would also need to include the class file for C because the one depends upon the other. If I wanted to build a JAR from class A, then all three classes would be included. Is there a way to examine this dependency chain and build a JAR with the result?
Several products can do this, including ProGuard.
The danger is that without exhaustive run-time analysis, or a good understanding of your code and any frameworks it uses, some classes may be missed if they've instantiated via reflection. Plugin systems, dependency injection, scripting, and so on can all interfere with the accuracy of static analysis.
Yes it is possible. you can create a file with the list of classes that you do want to include and pass that file into the jar command. The details are documented here.

How do I locate a clashing class in the IntelliJ classpath?

I'm trying IntelliJ IDEA after many years as an Eclipse user. At the same time, I'm working on a project that I've inherited with many dependencies.
One class will not compile, because IDEA claims that a method in another class does not exist. I can see the method in its source. Control-clicking on the class name in the IDEA editor takes me to the source that looks OK.
My hypothesis is that the compiler isn't using the class compiled from the source within the project, but a class with the same name, somewhere among my dozens of library jars.
How can I find out where IDEA's compiler is finding the clashing class?
CTRL-N and entering the class name should show you all of the matching classes from across the classpath, and which directory/JAR they're in. If there's a clash, you should have duplicates in that list.
Another possibility is that the source you have for the referenced class doesn't match the compiled version of that class.

Categories

Resources