Can a program depend on a library during compilation but not runtime?
Each Maven dependency has a scope that defines which classpath that dependency is available on.
When you create a JAR for a project, dependencies are not bundled with the generated artifact; they are used only for compilation. (However, you can still make maven include the dependencies in the built jar, see: Including dependencies in a jar with Maven)
When you use Maven to create a WAR or an EAR file, you can configure Maven to bundle dependencies with the generated artifact, and you can also configure it to exclude certain dependencies from the WAR file using the provided
scope.
The most common scope — compile
— indicates that the dependency is available to your project on the compile classpath, the unit test compile and execution classpaths, and the eventual runtime classpath when you execute your application. In a Java EE web application, this means the dependency is copied into your deployed application. In a JAR file however, dependencies will not be included when the compile
scope is used.
runtime
scope indicates that the dependency is available to your project on the unit test execution and runtime execution classpaths,
but unlike the compile
scope it is not available when you compile your application or its unit tests. A Runtime Dependency is copied into your deployed application, but it is not available during compilation. This is good for making sure you do not mistakenly depend on a specific library. Imagine you have a specific logging implementation being used, but you only want to import a logging facade in your source code. You would include the concrete log library with a runtime
scope, so you do not mistakenly rely on it.
Finally, provided
scope indicates that the container in which your application executes provides the dependency on your behalf. In a Java EE application, this means the dependency is already on the Servlet container’s or application server’s classpath and is not copied into your deployed application. It also means that you need this dependency for compiling your project.
Generally you are right and probasbly it is the ideal situation if runtime and compile time dependencies are identical.
I will give you 2 example when this rule is incorrect.
If class A depends on class B that depends on class C that depends on class D where A is your class and B, C and D are classes from different third party libraries you need only B and C at compile time and you need also D at runtime. Often programs use dynamic class loading. In this case you do not need classes dynamically loaded by library you are using at compile time. Moreover often the library chooses which implementation to use at runtime. For example SLF4J or Commons Logging can change the target log implementation at runtime. You need only SSL4J itself at compile time.
Opposite example when you need more dependencies at compile time than at runtime. Think that you are developing application that has to work at different environments or operating systems. You need all platform specific libraries at compile time and only libraries needed for current environment at runtime.
I hope my explanations help.
You need at compile time dependencies which you might need at runtime. However many libraries run without all its possible dependencies. i.e. libraries which can use four different XML libraries, but only needs one to work.
Many libraries, need other libraries in turn. These libraries are not needed at compile time but are needed at runtime. i.e. when the code is actually run.
A compile-time dependency is generally required at runtime. In maven, a compile
scoped dependency will be added to the classpath on runtime (e.g. in wars they will be copied to WEB-INF/lib).
It is not, however, strictly required; for instance, we may compile against a certain API, making it a compile-time dependency, but then at runtime include an implementation that also includes the API.
There may be fringe cases where the project requires a certain dependency to compile but then the corresponding code is not actually needed, but these will be rare.
On the other hand, including runtime dependencies that are not needed at compile-time is very common. For instance, if you're writing a Java EE 6 application, you compile against the Java EE 6 API, but at runtime, any Java EE container can be used; it's this container that provides the implementation.
Compile-time dependencies can be avoided by using reflection. For instance, a JDBC driver can be loaded with a Class.forName
and the actual class loaded be configurable through a configuration file.