7

From my understanding Gradle will carry over all compile dependencies as runtime dependencies.

What is an instance when you should only use runtime? All child dependencies are grabbed from compile and pulled into the compilation when gradle build is called.

For example, when I do a diff on what is printed when I call

> gradle -q dependencies

The list printed out for compile and runtime are identical. Example output may show following for both:

+--- org.springframework.boot:spring-boot-starter-web: -> 1.5.4.RELEASE
|    +--- org.springframework.boot:spring-boot-starter:1.5.4.RELEASE
|    |    +--- org.springframework.boot:spring-boot:1.5.4.RELEASE
|    |    |    +--- org.springframework:spring-core:4.3.9.RELEASE
|    |    |    \--- org.springframework:spring-context:4.3.9.RELEASE
|    |    |         +--- org.springframework:spring-aop:4.3.9.RELEASE
|    |    |         |    +--- org.springframework:spring-beans:4.3.9.RELEASE
|    |    |         |    |    \--- org.springframework:spring-core:4.3.9.RELEASE
|    |    |         |    \--- org.springframework:spring-core:4.3.9.RELEASE
|    |    |         +--- org.springframework:spring-beans:4.3.9.RELEASE (*)
|    |    |         +--- org.springframework:spring-core:4.3.9.RELEASE
|    |    |         \--- org.springframework:spring-expression:4.3.9.RELEASE
|    |    |              \--- org.springframework:spring-core:4.3.9.RELEASE
|    |    +--- org.springframework.boot:spring-boot-autoconfigure:1.5.4.RELEASE
|    |    |    \--- org.springframework.boot:spring-boot:1.5.4.RELEASE (*)
|    |    +--- org.springframework.boot:spring-boot-starter-logging:1.5.4.RELEASE
|    |    |    +--- ch.qos.logback:logback-classic:1.1.11
|    |    |    |    +--- ch.qos.logback:logback-core:1.1.11
|    |    |    |    \--- org.slf4j:slf4j-api:1.7.22 -> 1.7.25
|    |    |    +--- org.slf4j:jcl-over-slf4j:1.7.25
|    |    |    |    \--- org.slf4j:slf4j-api:1.7.25

I have looked at this answer which helped explain a little about the difference between compile and runtime, but it only showed that runtime is when your code actually executes a dependency. When would you have a runtime dependency, but not a compile time?

Brandon
  • 404
  • 6
  • 21
  • 2
    In our spring-boot application, we write log messages using slf4j. At runtime, slf4j is binded with log4j2 and log4j2 uses a configuration file to output our logs to a file. So slf4j is a compile time dependency, and log4j2 is a runtime dependency in this case. – DevelopingDeveloper Aug 17 '17 at 16:42
  • 2
    I think I might understand now. So in my project I did not set up a logger. If I did, log4j2 could be set up as a `runtime` dependency because Spring or slf4j uses dependency injection (at runtime) to resolve that logger. Is that correct? – Brandon Aug 17 '17 at 16:58
  • Possible duplicate of [Compile time vs Run time Dependency - Java](https://stackoverflow.com/questions/4270950/compile-time-vs-run-time-dependency-java) – Lukas Körfer Aug 17 '17 at 17:42
  • @lu.koerfer, I have looked at that and included it in my question. It didn't answer everything I had questions about. In essence, when do you use compile time vs runtime in your gradle file. – Brandon Aug 17 '17 at 20:19
  • Also this response helped me find use cases https://stackoverflow.com/questions/45842742/when-would-i-need-maven-dependency-with-runtime-scope – Fawkes Nov 02 '20 at 16:41

1 Answers1

11

A typical case involves dynamically creating classes via reflection. As a contrived example, consider this app:

package net.codetojoy;

public class App {
    public static void main(String[] args) throws Exception {
        Class c = Class.forName("org.apache.commons.lang3.StringUtils");
        Object object = c.getConstructor().newInstance();
        System.out.println("object is : " + object);
    }
}

It will create an object of StringUtils from Apache Commons Lang. (This example is silly; consider a case where libA will effectively do this for classes in libB).

There is no compile-time dependency so there is no reason to burden the compile-time classpath with the jar. However at run-time, the jar is certainly required. The build.gradle file is below. It uses the application plugin which nicely bundles the dependencies into a runnable deliverable.

apply plugin: 'java'
apply plugin: 'application'

repositories {
    jcenter()
}

dependencies {
    runtime group: 'org.apache.commons', name: 'commons-lang3', version: '3.6'
}

mainClassName = 'net.codetojoy.App'

Example output:

$ gradle run -q
object is : org.apache.commons.lang3.StringUtils@4aa298b7
Michael Easter
  • 23,733
  • 7
  • 76
  • 107
  • This is a good example and helps, thanks! One follow up question: would dependency injection / @Autowire annotation be another example where you might have a runtime dependency? Like if an implementation class is in a different package than an interface that is in your compile time libraries? – Brandon Aug 17 '17 at 20:26
  • Well, I would qualify the statement a bit and say that, yes, annotations that search the classpath at run-time would fall into this category. I can't really remember the @Autowire mechanism but I believe it is an example. Hopefully others will correct me here if I'm wrong. – Michael Easter Aug 18 '17 at 16:44