Having hard time to describe this and I bet this is something very simple, but I just can't google sollution.
I am using many modules in my project. For simple argument let's say I have modules A and B.
B depends on A.
When I add dependency to external library (using implementation keyword) in module A to use some of it's code in the module, I cannot access library's code in project B. How can I achieve that? I would like A to be my "base" project with all dependencies in that place rather than having to repeat myself in other modules, that depend on it.
The implementation configuration means the dependencies are internal (implementation specific) for the project and should not be exposed on the compilation classpath of other dependent projects. This helps encapsulate dependencies and speeds up the build as you don't need to recompile dependent projects if you only change internal dependencies.
If you want to expose them, you need to use the api configuration instead, along with the java-library plugin.
Related
I want to publish a common build script which i will include across various projects in my application.
This will contain only the common set of dependencies, i.e dependencies with particular versions that will be common across all the artifacts in my enterprise application..
My applications will refer to this file from the url.
How can i achieve this?
EDIT1: my exploration in this direction is based on this answer on SO:
How to share a common build.gradle via a repository?
There are a few different options for this.
One is to publish a project with the dependencies you want to share defined as API dependencies. Projects that depend on this will inherit the dependencies.
Or you could write and publish a Gradle plugin that will configure your projects with the common dependencies. Projects can apply the plugin, and will automatically be configured in a certain way. (You don't need to publish a plugin to do this - first try creating a project-local buildSrc convention plugin.)
I would actually recommend neither of these approaches.
It's easy to get into a tangled web of dependency hell when transitive dependencies are inherited. It's likely that at some point some dependency will clash, and excluding dependencies can be a big headache, and will easily cancel out any benefit in trying to reduce a little duplication.
Additionally, it's nice when a project is explicit about its dependencies. Being able to look at a build.gradle.kts and understand exactly what dependencies are set is very convenient.
Instead, what I would recommend is controlling the versions of common dependencies in a central location. This can be achieved with the Java Platform plugin. This plugin can be applied to a single build.gradle.kts file, and it lists all versions of all possible dependencies. (It can also import existing Maven BOMs, like the Spring Boot BOM).
Now, all subprojects can add a platform dependency on the 'Java Platform' project.
dependencies {
// import the platform from a Maven repo
implementation(platform("my.company:my-shared-platform:1.2.3"))
// or import a platform from a local project
implementation(platform(":my-project:version-platform"))
// no need to define a version, if it's defined in the platform
implementation("com.fasterxml.jackson.core:jackson-databind")
}
This is the best of both worlds. Projects can be explicit about their dependencies, retain autonomy, while the versions can be aligned across independent projects.
I inherited a large codebase built with maven multi modules.
I want to explicitly reference dependencies used in the source code itself, categorize by compile/test
and delete dependencies that are not used at test/runtime.
Is there a tool/plugin that does this for me or do I need to write it myself?
The dependency plugin offers mvn dependency:analyze which allows you to find out which dependencies are actually used in your source code. It furthermore tells you if you use transitive dependencies directly in your source code.
I do not know whether you can do something like that for test code as well.
I have the following Java projects structure:
Util
|
-- Core
|
-- Services
|
-- Tools
The projects: Tools and Services references to Core and Util projects, the thing is that I ended up writing the same dependency over each project, there must be a better way to inherit the dependencies of the referenced projects and add new ones if needed.
I know about multi projects in Gradle, but this is not like a multi project, since I can basically take the Core library, compile it (which will then contain Core + Util libs) and use it in another project.
I wonder what would be the best way to approach this?
Repeating the same dependencies in every project is usually reasonable because in a bigger project you'll never know when they become different, and you don't want to deal with compilation/runtime problems when someone changes common dependencies list.
I believe that it is more pragmatic to add dependency analyser plugin to your build. It will help you to remove unnecessary dependencies and explicitly add transitive dependencies. And if you add this plugin to your build chain, it will help you to keep your dependencies healthy in the future. Pick this plugin here gradle-dependency-analyze, or maybe there is a better fork or equivalent somewhere.
You are actually out of options in your case because there are only two kinds of dependencies: (1) external (some other jar artefact) or (2) internal (another module in a multimodule build).
2.1 When you use an external maven-like dependency it will come to you with own dependencies (they are named "transitive dependencies"). It means that if you do compile 'yourgroup:Core:1.0' then you will get Util as a transitive dependency. But as I mentioned above, it is better to list transitive dependencies explicitly if they are used during compilation or to prevent them from being accidentally removed and crash your application in runtime.
2.2. If your projects live in the same version control repository and usually change and build together, then the multimodule layout is your best choice. In this case, you will refer to Core dependency like compile project(':Util:Core') and it will grab Util as a transitive dependency as well. And you will be able to do what you asked for and define dependencies for Services and Tools once - inside subprojects {} closure in the Core/build.gradle.
Having multimodule built doesn't limit you from using Core library elsewhere. No matter if it is a multimodule build or not, you can always add maven-publish plugin to Core/build.gradle, execute publishToMavenLocal task and reference to Core.jar from another project the same way you do for external dependencies.
You can always put your common code (like the one which will add common dependencies) in the external gradle file or custom plugin and apply it in Services and Tools.
I am trying to prevent dependency checking in java compiler, I use command line compilation,is there any way to tell javac compiler not to check dependency while compiling a java file ?
... is there any way to tell javac compiler not to check dependencies while compiling a java file ?
The simple answer is No.
Suppose you have some class A that wants to call some method m defined by class B. In order to successfully compile A, the compiler needs to know that B is a real class, that it defines the method m, that it has the expected number and type of arguments, what checked exceptions it throws, and what type of value it returns. Without this information about B, the compiler cannot compile A.
And this propagates to the project level. If a class in project P depends on a class in project Q, the compiler must have that class (at least) in order to compile the class in P.
In short, no such compiler option exists, and it is hard to see how it could be implemented it it did.
If you're two projects are dependent on each other then they are really one project and must be built together. If the relationship is a one-way relationship then you will still need to build the dependent project first and then have the results of the project on the classpath when building the second project.
Most IDEs have capabilities to manage this. In Eclipse you can mark that one project depends on another project and the dependent project's output files will be added to the classpath of the other. Typically all dependencies are built and packaged as jars and those jar files are placed onto the classpath when compiling parent projects.
Building code without having access to the dependencies is very difficult and not recommended. In some cases it can be possible. Eclipse has built their own incremental Java compiler so that they do not have to recompile the entire project each time a single file is modified. You can read more about it here but in order to use such a compiler you will likely have to do a lot of work.
UPDATE to reflect your new edit:
In order to build a common library that common library must not depend on any classes in your platform-specific sections. As Peter Rader has mentioned the typical way of doing that is by using interfaces. For example, your common library can have an EventListener interface which receives events. In your platform specific libraries you can implement that interface and process the events according to the specific platform. Since your common library only depends on the EventListener class and not the specific implementations it does not need those specific classes when it compiles.
If you have dependencies, they will always be checked and give warnings, but your classes will be compiled anyway.
Often frameworks offer an api.jar that contains interfaces and enums.
I have a project called 'talktome', with no runtime dependencies.
Also I have project 'talktome-tools', which depends on 'talktome'.
No problems, until I realize that the unit-tests in 'talktome' depends on 'talktome-tools'.
What solutions are there?
If talktome is a general project where other (e.g talktome-tools) depends on, it should not be depend on the more specific projects. Then, it would be wise to get rid of dependency from talktome to talktome-tools.
Otherwise, you would create a more higher level project (e.g parent) and put necessary interfaces, classes that can be used by both talktome and talktome-tools to the new project.
You may move the tests to another maven module like talktome-tests that will do the integration testing. It makes sense especially it seems that talktome shouldn't depend on specific project like talktome-tools.
And, test dependencies like talktome-tools should be included with test scope.