I'm trying to understand the specific need for runtime
scoped dependency in maven. In which situation I would need this, where neither compile
or provided
scope won't do?
For example, I would use compile
scope for dependency, when I have to call the library API directly in the code (compile against it) and package the dependency in the artifact or dependent project artifacts.
I would use provided
scope when I have to compile against the API, but don't package it (rather except it to be available at runtime).
But when would I need runtime
scope? Is this for situations, when I don't directly call the library API (rather use reflection), but want to package it inside the artifact? Why not just to use compile
scope? Is the only benefit faster compile time, or is there something other special in runtime
scope that couldn't be achieved or avoided with compile
scope?
All what you can do with the runtime
scope can be also done with the default scope : compile
.
So why use runtime
?
Because in some cases, this makes really sense and can make your build more robust.
A typical use case is ensuring that the client code doesn't use a specific implementation.
Suppose you build an application relying on an API packaged as a Maven dependency (my-service-api
) and the implementation of this API is packaged as another Maven dependency (my-service-impl
).
Suppose now you need to provide the implementation at the runtime in the built application but you don't want that the client code of your application refers directly the implementation.
By using the runtime
scope for my-service-impl
:
<dependencies>
<dependency>
<groupId>my-group</groupId>
<artifactId>my-service-api</artifactId>
</dependency>
<dependency>
<groupId>my-group</groupId>
<artifactId>my-service-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependencies>
As the compiler will never have the dependency in the classpath, you cannot create any coupling with the implementation in the client code of your application.
Client code will only see the API of the dependency :
By using the compile
scope for my-service-impl
:
<dependencies>
<dependency>
<groupId>my-group</groupId>
<artifactId>my-service-api</artifactId>
</dependency>
<dependency>
<groupId>my-group</groupId>
<artifactId>my-service-impl</artifactId>
</dependency>
<dependencies>
Things are different : you could by mistake reference implementation classes and so create an undesirable coupling with the implementation.
A known usage to favor runtime
scope is as you have to cope with a JDBC dependency of a specific DBMS (Oracle, PostgreSQL or whatever).
To write portable code, you don't want to allow the client code to refer to classes of this JDBC dependency but you want all the same include it in your application as at runtime the classes are needed to make the JDBC api works with this DBMS.
There is considerable confusion around the runtime
scope. I think this confusion reflects its marginal benefit and the absence of a really compelling general purpose use case for it.
The commonly cited benefits are:
- They help avoid accidental dependencies
- They facilitate usages such as
Class.forName("a.b.ClassName")
and allow you to switch the binding represented by "a.b.ClassName" without having to recompile your application. Common examples of this benefit: JDBC drivers and SLF4J bindings
But, given the general confusion and the marginal benefits I'd suggest sticking to compile
scope unless you have encountered one of those corner cases where runtime
scope is really useful.
Runtime scoped dependencies are useful for dynamically loaded libraries, that you do not explicitly reference in the code but need to be there for your application to run.
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.
Well it means that the classes within the library are present to the JVM classpath (runtime environment), but not to the JAVA Compiler classpath (compile-time), therefore when compiling your project these classes will not be visible to the compiler.. therefore you cannot use/import any of these classes at compile-time.
This scope is useful for dynamically-loaded classes (that is, classes that you will reference/load at runtime)