This post is inspired from the mess I have made in my java project  around compile time and run time 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 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 run time 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 run time. 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:

public class ClazzC { }

The above code generates ClazzC.class file.

The above code will generate ClazzA.class file.

The only case where ClazzC.class is not needed in run time 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 other wise just ignores it. In an actual project, many of the internal dependencies can be skipped or not needed at run time in the same way.

So if you are skipping some libraries in run time 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, you code may fail to run.

About provided scope:

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

The Tomcat library includes servlet-api.jar. Suppose you are not using the Tomcat run time 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 same jar provided by some one else during run time”. In this case it is the Tomcat server.

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