Classpath in Gradle - gradle

I am new to Gradle. I have written a JavaCompile task. So, when I didn't specify the classpath in the task it is throwing me an error. In maven, we don't specify the classpath it automatically takes the default location of the dependencies and takes them during compilation. Is it a must to specify the classpath in Gradle?

Yes, the task needs a classpath set via a property available during the configuration phase.
It isn't common in my experience to declare JavaCompile tasks directly, and when you do it usually means some sort of the special or custom build. In this case you will want full control over the compiler options.
A common motif is for the classpath to be set in terms of a specific configuration:
classpath = configurations.compile
This is similar in practice to the implicit Maven classpath taken from the dependencies. However, since Gradle config is composed of blocks of Groovy (or whatever) and not contextual XML, you have to tell it from what configuration you want to take the classpath.

Related

Extend JavaExec task with additional configuration on the classpath

I have a task of type JavaExec that does a lot of complicated steps in order to compile & run the application. This task is generated by a plugin outside of my control.
I want to create another task that "extends" this task, adding an extra dependency configuration. This configuration stores some dependencies that should only be included for this specific task.
Is there an easy way for me to create such a task, or do I have to copy over all configuration properties (which may change at any time) manually?

Gradle - Adding new configuration to classpath throws error

I have created a custom Gradle plugin which creates a new configuration for some dependencies that I want to treat separately. Since these used to be in the compile configuration I have added the new configuration to the classpath (from the Java plugin) like so:
project.sourceSets.all { sourceSet ->
sourceSet.compileClasspath += myConfiguration
}
My configuration extends the compile configuration. My reasoning for this was that if there were any other 3rd party plugins that did "something" to the compile configuration then it would also affect my new configuration, since it is also an instance of compile.
It seems that later on another plugin, the Spring PropDeps Plugin, also modifies the classpath and the build fails with:
Failed to apply plugin [class 'org.springframework.build.gradle.propdep.PropDepsPlugin']
Cannot change dependencies of configuration ':my-project:compile' after it has been resolved.
Looking at the source code for that plugin they are doing the same steps that I am in my custom plugin to create a configuration, namely create the configuration and add it to the classpath as soon as the plugin is applied, see here.
It would seem crazy if only one plugin could add a new configuration to the classpath. What am I doing wrong here?
Note that my custom plugin is applied in the allprojects block whereas the Spring plugin is applied in the subprojects block - not sure if this matters.
Hmmm ... as I was writing the question something struck me about both extending the compile configuration and adding to the compile classpath. This seemed like I was adding a circular dependency. Low and behold, when I did not extend the configuration the build worked!

How should i set main class for Spring Boot application in Gradle?

I read spring boot documentation and i see there are at least 2 ways to set main class:
bootRepackage {
mainClass = 'demo.Application'
}
and
springBoot {
mainClass = "demo.Application"
}
Which one should i use or they are both required for different tasks? I do not want to repeat myself.
In Gradle terms, springBoot is an extension. When you use it to configure the main class, you're configuring it for every repackaging task in the project. On the other hand bootRepackage is referencing a single repackaging task so you're just configuring the mainClass for that one task.
Which one should i use or they are both required for different tasks?
If you only have a single repackaging task (as is the default) this is a matter of personal preference.
If you have configured additional repackaging tasks, you are probably better configuring it on each individual task rather than using the springBoot extension. If you use a mixture of the two, the setting on an individual repackaging task will take precedence over whatever you have configured using springBoot.
This is from documentation for springBoot plugin:
The gradle plugin automatically extends your build script DSL with a
springBoot element for global configuration of the Boot plugin. Set
the appropriate properties as you would with any other Gradle
extension (see below for a list of configuration options):
And below that there is an example of configuration of mainClass element of bootRepackage plugin:
The main class that should be run. If not specified, and you
have applied the application plugin, the mainClassName project
property will be used. If the application plugin has not been
applied or no mainClassName has been specified, the archive will
be searched for a suitable class. "Suitable" means a unique class
with a well-formed main() method (if more than one is found the
build will fail). If you have applied the application plugin,
the main class can also be specified via its "run" task
(main property) and/or its "startScripts" task
(mainClassName property) as an alternative to using the
"springBoot" configuration.
In other words those two are identical.

Gradle - specifying configuration based dependency

While reading this gradle document, I came across this wordings saying that dependencies for each configuration. Here what does this configuration meant to be. Because I usually used to specify the dependencies in such a vague way like
dependencies {
compile 'org.springframework:spring-core:4.0.5.RELEASE',
'org.hibernate:hibernate-core:3.6.7.Final'
}
Is there any other possible way to specify the dependencies(based on configuration)?. I am little curious to know about that.
If yes, what is advantage of specifying dependencies like that. Can someone able to throw some light here?
Also how the below command will be useful?
gradle -q dependencies api:dependencies webapp:dependencies
In Gradle dependencies are grouped into configurations. Configurations have a name, a number of other properties, and they can extend each other. Many Gradle plugins add pre-defined configurations to your project.
These are the configurations added by Java plugin. As you can see, compile is a configuration, it is extended by many other configurations. You can create your own configuration:
configurations {
myConfig {
description = 'my config'
transitive = true
extendsFrom compile
}
}
Also how the below command will be useful?
This command prints the dependencies of main project and api and webapp subprojects.

Understanding Maven scoping better

I have been struggling to figure out what's the use of scoping that is provided by Maven
as mentioned here.
Why should you not always have compile time scoping? Real life examples would be really appreciated.
The compile scoped dependencies are only used during compilation.
The test scoped ones -- only during tests. Say you have tests using junit, or easymock. You obviously do not want your final artifact to have a dependency on them, but would like to be able to just depend on these libraries while running your tests.
Those dependencies which are marked provided are expected to be on your classpath when you're running the produced artifact. For example: you have a webapp and you have a dependency on the servlet library. Obviously, you should not package it inside your WAR file, as the webapp container will already have it and a conflict may occur.
One of the reasons to have different scopes for dependencies is that different parts of the build can depend on different dependencies. For example, if you are only compiling your code and not executing any tests, then there is no point in having Maven downloading your test dependencies (if they're not already present in your local repository, of course). The other reason is that not all dependencies need to be placed in your final artifact (whether it's an assembly, or WAR file), as some of the dependencies are only used during the build and testing phases.
compile
Will copy these jar files into prepared War file.
Ex: hibernate-core.jar need to have in our prepared War.
provided
These jars will be considered only at complie time and test time
Ex:
servlet.jar will be provided by deployed server, so no need to provide from our prepared War file.
test
These jars are only required for running test classes.
Ex: Junit.jar will be required only for running Junit test classes, no need to deploy these.
Scopes are quite well explained in here:
https://maven.apache.org/pom.html#Dependencies
As a reference, I copied the paragraph:
scope: This element refers to the classpath of the task at hand
(compiling and runtime, testing, etc.) as well as how to limit the
transitivity of a dependency. There are five scopes available:
compile
- this is the default scope, used if none is specified. Compile dependencies are available in all classpaths. Furthermore, those
dependencies are propagated to dependent projects.
provided - this is
much like compile, but indicates you expect the JDK or a container to
provide it at runtime. It is only available on the compilation and
test classpath, and is not transitive.
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.
test - this scope indicates that the dependency is
not required for normal use of the application, and is only available
for the test compilation and execution phases.
system - this scope is
similar to provided except that you have to provide the JAR which
contains it explicitly. The artifact is always available and is not
looked up in a repository.
there are a couple of reasons that you might not want to have all dependencies to be default compile scope
reduce the size of final artifact(jar,war...) by indicating different scope.
when you have a multiple-modules project, you have ability to let each module have it's own version of dependency
avoid class version collision by provided scope, for instance if you are going deploy a war file to weblogic server, you need to get rid of some javax jars, like javax.servlet, javax.xml.parsers, JPA jars and etc. otherwise you might end up with class collision error.

Resources