This post is inspired from the mess I have made in my java project around compile time and runtime dependencies. There are lots of questions you will ask when you try to resolve all the dependencies for your project using tools like Maven or Gradle. These tools make a distinction between compile time and run time dependency, like compile scope, provided scope etc.

  • Compile-time dependency: You need this particular set of class files in your CLASSPATH during compilation of your project. Your code either creating object of a class from this particular library extends it or has some kind of reference.
  • Run-time dependency: The dependency which is required in your CLASSPATH because you actually calls that class, creating an object or do something with it during the code flow. It can be either in a hard-coded way or through reflection or such methods.

At some point of time we may question the need of a distinction between these two kinds of dependencies because ideally, all the libraries which are required for compile time should be available at runtime as well.

The above point is correct up to an extent. But there are rare cases where a library is required for compile time but then the corresponding library or piece of code is not required at runtime. That means you can have a compile time only dependency. From a popular answer from StackOverflow:

This is based on the fact that Java only links class dependencies on first access to that class, so if you never access a particular class at run-time because a code path is never traversed, Java will ignore both the class and its dependencies.

They are providing an example too:

Also Read:  70 tips for java developers to write clean and maintainable code

public class ClazzC { }

The above code generates ClazzC.class file.

public class ClazzA {
    public static clazzB {
        public String toString() {
            ClazzC c = new ClazzC ();
            return c.toString();
    public static void main(String[] args) {
        if (args.length > 0) {
            clazzB b = new clazzB ();

The above code will generate ClazzA.class file.

The only case where ClazzC.class is not needed in runtime is when we pass nor arguments to the program. That means JVM will only look for ClazzB’s dependency only if it is called through the program otherwise just ignores it. In an actual project, many of the internal dependencies can be skipped or not needed at runtime in the same way.

So if you are skipping some libraries in runtime which are needed for compilation (means you have not added the .jar file into the lib of the war or ear ), in the future, as your code base expands and starts using many other functionalities of the libraries, your code may fail to run.

About provided scope:

Maven and Gradle, both provide a way to add dependencies with a provided scope. What does that really mean?. There is a perfect example of this.

The Tomcat library includes servlet-api.jar. Suppose you are not using the Tomcat runtime dependency in your web project but including the same servlet-api.jar in your project as a transient dependency. So if you don’t want to use your jar instead wants to use the Tomcat jar, you can use the provided scope in maven. It basically says that “use this dependency only for compilation, I have the same jar provided by someone else during runtime”. In this case, it is the Tomcat server.

Also Read:  How to write a gradle task in your build.gradle to do a custom job

In maven and Gradle  it is pretty easy to define a dependency with provided scope:





apply plugin: 'war'
dependencies {
  providedCompile 'com.sun.faces:jsf-impl:2.2.13';


Share this article:

Leave a Reply

Your email address will not be published. Required fields are marked *