Spring Boot autoconfigure and its dependencies - spring

I checked the source code of module spring-boot-autoconfigure
It has configurations classes for plenty of technologies : data, redis, cassandra, JPA, LDAP etc...
How can this module can compile properly without including all theses technologies dependencies jar in its POM ?
If I take the example of HibernateJpaAutoConfiguration class :
It uses beans/classes from other Spring modules like spring-orm :
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
However spring-boot-autoconfigure has no dependency to spring-orm in its POM. So how is compilation possible ?

This is possible because they apply Maven's concept of optional dependencies:
Optional dependencies are used when it's not possible (for whatever reason) to split a project into sub-modules. The idea is that some of the dependencies are only used for certain features in the project and will not be needed if that feature isn't used. (...) However, since the project cannot be split up (again, for whatever reason), these dependencies are declared optional. If a user wants to use functionality related to an optional dependency, they have to redeclare that optional dependency in their own project.
In Maven, it would usually look like this:
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
In this example, the project is compiled with Project-A. However, Project-A is not shared as transitive dependency.
The developers of Spring Boot use Gradle instead of Maven. They wrote their own Gradle plugin to replicate this behavior. The result looks something like this:
dependencies {
...
optional("org.springframework:spring-orm")
(see spring-boot-autoconfigure/build.gradle)

Related

Resolve Library Conflicts With Maven

Starting with kotlin 1.4.30, the kotlin-compiler-embeddable dependency has included the files for the 'fastutil' library inside their main jar package. The problem it this conflicts with my local specified version of fastutil in my pom.xml file.
Is there any way I can include the 1.4.30 kotlin-compiler-embeddable dependency and ignore the /it/unimi/dsi/fastutil folder that way it will only use my version I specified?
Screenshot of kotlin-compiler-embeddable layout:
Project is here: https://gofile.io/d/9m5LiV
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap // Default imports from the kotlin-compiler-embeddable lib
fun main(args: Array<String>) {
// http://fastutil.di.unimi.it/docs/it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap.html#%3Cinit%3E(int)
// ^ this is possible when you dont have a kotlin-compiler-embeddable conflict
// Because its importing this class from the kotlin-compiler-embeddable library
// instead of the fastutil library itself
val map = Int2ObjectOpenHashMap<String>(10)
println("Hello World!")
}
Maven 2.0.9 introduced deterministic ordering of dependencies on the classpath back in 2008.
If you have 2 dependencies containing the same class, first one mentioned in the pom wins.
You can use mvn dependency:build-classpath to inspect the class path.
In your case, place fastutil before kotlin compiler.
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.2.1</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler-embeddable</artifactId>
<version>1.4.30</version>
</dependency>
Notes:
The wording of your question is puzzling. kotlin-compiler-embeddable is a regular dependency in your project, not a plugin.
I checked that kotlin-compiler also has fastlib pulled in, so using it instead of kotlin-compiler-embeddable won't help
The missing constructor problem comes from the fact that kotlin is not pulling in fastutil itself, but a repackaged version intellij-deps-fastutil-8.3.1-1. See commit: Add fastutil dependency for 202 and higher platforms
If you intend to distribute your app as an uber-jar, make sure to check your packager oprions. Maven shade plugin has powerful filtering tools.
Although relying on classpath order is fast to implement and works, it can get surprising. Consider repackaging your kotlin compiler dependency without fastlib.

Groovy Dependency management

I am quite new to groovy and need to clarify on the Groovy Dependency management.
Here is the summary according to my "Homework":
Groovy Dependency management is as simple as adding an annotation to the script. E.g.
#Grab('org.springframework:spring-orm:3.2.5.RELEASE')
Grape will then quickly add the dependencies from maven repository to your classpath
So, is adding to my groovy script the dependency annotation is all that I need, and Groovy/Grape will take care of the rest, when I run my Groovy script, right? (or there are some prerequisites, like I can't put my groovy script randomly anywhere, but has to be at a specific place like within a Groovy project, etc)
Second question, how to translate Maven dependency to Groovy/Grape dependency annotation?
For e..g., this is the Maven dependency for Opencsv:
<dependencies>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.2</version>
</dependency>
</dependencies>
Does that translate to #Grab('com.opencsv:opencsv:5.2')?
Third question,
suppose I need to import org.apache.commons.collections.primitives.ArrayIntList, how can I come up with a Groovy/Grape dependency annotation as
#Grab(group='commons-primitives', module='commons-primitives', version='1.0')
I.e., where can I found the connection between org.apache.commons.collections.primitives.ArrayIntList and commons-primitives?
And finally,
where would Groovy/Grape store the downloaded .jar files?

spring boot project as dependency inside another spring-boot project

I have a spring boot project(project-lib) which I am including as maven dependency in another spring boot project(my-project).
now the project-lib uses logback and i want to exclude the logback dependency in my-project.
Also currently project-lib is defined as dependency with classifier jar-with-dependencies
Is it possible to define project-lib as normal dependency instead of jar-with-dependencies.
I tried to define it as normal dependency assuming it will download all the required dependencies as project-lib/pom.xml has already defined the required dependencies to run project-lib but it did not work that way.
part of pom.xml of my-project
<dependency>
<groupId>com.xyz/groupId>
<artifactId>project-lib</artifactId>
<version>0.0.4-SNAPSHOT</version>
<classifier>jar-with-dependencies</classifier>
</dependency>

How to define a module being required, but not a dependency in Apache Maven

I have a Maven multi-module project, with one (or many) modules called "plugin-xx", in the main "runtime" module, I'm dynamically loading a class from a plugin module.
To avoid classloading conflicts, I'm creating a new classloader, pointing to the jar in the target directory of "plugin-xx".
So for the "runtime" module, I would like to tell Maven, that "plugin-xx" needs to produce a jar, but I don't want this jar to be in the classpath of "runtime".
Adding "plugin-xx" as a dependency would include it into the classpath.
Include plugin-xx as a dependency but use a dependency scope other than compile. I think you want this one:
<scope>provided</scope>
From the docs:
provided
This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.
I'm not totally clear on your requirements so it's possible that you want this instead:
<scope>runtime</scope>
From the docs:
runtime
This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
You can use runtime scope for your dependency. Definition looks like this:
<dependency>
<groupId>plugin-xx</groupId>
<artifactId>plugin-xx</artifactId>
<version>1.0</version>
<scope>runtime</scope>
</dependency>
You won't see the plugin on classpath in your main module during compilation time but it will be placed on classpath on runtime so you can dynamically load it with your ClassLoader.

Does Maven need to explicitly specify the dependency that Spring/Hibernate dependented?

I'm new to Maven, I try to use Maven with Spring, Hibernate in my project. After go though the Spring and Hibernate reference, I found that "there is no need to explicitly specify the dependent liberaries in POM.xml file for such Apache commons liberaries".
My questions is that : If my other parts of project refer to Apache commons liberary, such as commons-io, SHOULD I explicit specify this dependency in POM.xml file?
You should define those dependencies in Maven which your project is using. For example, even though some library depends on commons-io but if your code needs this then you should directly define commons-io in your pom.xml
You should not worry about the dependencies of the libraries you have defined in your pom.xml. Maven will do that for you.
Maven is used to avoid the issue of having to run down JAR files that are dependent on other JAR files. Of course you do not HAVE to use maven to do this, but you should. Maven will automatically download the dependent JAR files of the JAR file you require. THe hibernate-entity manager JAR file, for example, has over 100 dependencies and maven does the work for you.
Anyway,even if you do add the commons-io file to the build path/classpath of the maven project,and then update the project configuration, maven will kick it out.
You can provide a lib name on a site like mvnrepository.com to see what it depends on (e.g. take a look at a section called "This artifact depends on ..." in case of spring-webmvc library). Those dependencies (which your artifact depends on) are called transitive dependencies. You don't have to specify these in your pom.xml as maven will resolve them for you.
For the sake of readability you should only state those dependencies in your module that you rely on directly. You want JUnit to test your software, only declare JUnit; you need hibernate to use ORM, declare hibernate, and so on. Leave the rest to Maven.
And most of the time you should state what you intend to use in the very module you want to use it in. So if you want to use a dependency in more than one module, consider moving it into a dependencyManagement block in a parent pom and referencing it from there in the module you want it in.
parent pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
child pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
This guarantees you version-stability and still allows you to find out what a module uses by only looking in it's pom (and not all over the place).

Resources