gradle how configurations is used - gradle

Example in the gradle war plugin: why need to define moreLibs like the following? please explain:
configurations {
moreLibs
}
dependencies {
moreLibs ":otherLib:1.0"
}
war {
classpath configurations.moreLibs
webXml = file('src/someWeb.xml')
}
Can we define anything inside configurations?
configurations {
foobar
}
I have seen these in many places. Can anyone explain?

Yes, you can write anything in the configurations block and it will create a new configuration with that name and you can also further configure it, e. g. by setting its transitive property to false and other stuff.
A custom configuration is just a name for which you can define dependencies that are then resolved transitively by Gradle automatically and can be used for various purposes where you need those resolved files.
In your example you define a moreLibs configuration, add a dependency to it that will be resolved transitively by Gradle and then added to the wars lib directory.
You don't have to do this if you don't have a need to. All libs in the runtime configuration (and thus also those in the compile configuration) are automatically added to the wars lib directory. But if you for some reason need additional libs in there that you don't want to add to compile or runtime, you can do it this way.
Another example of where a custom configuration can be useful is if you want to use a custom Ant task. You define a custom configuration, add the Ant tasks dependency to it, then you let Gradle transitively resolve it and can add the whole fileset as classpath to the taskdef for Ant.

Related

Which dependencies are added to a Gradle project which uses a 'project lib dependency' and is this configurable?

Gradle project lib dependencies are a means of defining a project as requiring, as one of its dependencies, the output from another project.
The documentation states:
A “lib” dependency is a special form of an execution dependency. It
causes the other project to be built first and adds the jar with the
classes of the other project to the classpath. It also adds the
dependencies of the other project to the classpath.
However, which dependencies of the project are added? Is it the compile, implementation or runtime dependencies, for instance? Is this configurable? i.e. how would I configure a project to require the output of another project and the dependencies from an arbitrary configuration of that other project?
For instance, in my root project, I can define project1 to depend on project2:
project(":project1") {
dependencies {
implementation project(':project2')
}
}
How do I add the dependencies of an arbitrary configuration of :project2 (let's say it's called myConfiguration) to project1?
The answer is contained within the DSL documentation for Dependencyhandler.
By default, when you declare dependency to projectA, you actually
declare dependency to the 'default' configuration of the projectA. If
you need to depend on a specific configuration of projectA, use map
notation for projects:
configurationName project(path: ':projectA', configuration: 'someOtherConfiguration')

Gradle - don't specify version in included dependencies names

My application gets packaged as ear and I have used earlib and deploy configuration. However for all those dependencies version gets mentioned in the jar names.
For example, if I mention dependencies as below,
earlib 'com.xyz:abc:1.0.1'
In generated ear I can see jar name as abc-1.0.1.jar but I want to get it included simply as abc.jar.
Declare a dependency without a version
Gradle lets you declare a dependency without a version but you have to define a dependency constraint, which basically is the definition of your dependency version. This is commonly used in large projects:
dependencies {
implementation 'org.springframework:spring-web'
}
dependencies {
constraints {
implementation 'org.springframework:spring-web:5.0.2.RELEASE'
}
}
Declare a dynamic version
Another option is to declare a dynamic version by using the plus operator. This allows you to use the latest relase of a dependency while you pack your application. Doing so is potentially dangerous since its bears the risk of breaking the application:
apply plugin: 'java-library'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework:spring-web:5.+'
}
Declaring a file dependency
If you don't want to rely on a binary repository at all but provide dependencies yourself, you can declare a file dependency, from the directories ant, libs and tools. This allows you to name and version dependencies as you like but you have to maintain them yourself:
configurations {
antContrib
externalLibs
deploymentTools
}
dependencies {
antContrib files('ant/antcontrib.jar')
externalLibs files('libs/commons-lang.jar', 'libs/log4j.jar')
deploymentTools fileTree(dir: 'tools', include: '*.exe')
}
Note I recommend against removing the versions as they are important diagnostic information when the application doesn't work.
The ear task is an instance of the Ear task type, which in turn is basically a specialised form of the standard Zip task type. All archiving tasks allow you to rename files as they are packed.
For example, the following might work:
ear {
rename '(.+)-[^-].+(\\.jar)', '$1$2'
lib {
rename '(.+)-[^-].+(\\.jar)', '$1$2'
}
}
I strongly recommend that you check out the new user manual chapter on Working with files for more information about copying and archiving files. Hopefully I'll remember to update this answer with the non-release-candidate link once Gradle 4.7 is out.
Also, if you have any feedback on that chapter let me know.
EDIT Based on OP's feedback, I discovered that the Ear task uses a child copy specification for the JARs in the earlib configuration. Child specifications are independent of both the main one and other child specs, so the main rename() doesn't apply to the earlib files. That's why we add a rename() via the lib {} block.

How to get Intellij to recognize properties in application.yml

I am trying to get Intellij to recognize my properties using gradle. I have followed the steps here. So this means I have a #ConfigurationProperties annotated class with some properties.
I added the spring dependency to process them:
dependencies {
optional "org.springframework.boot:spring-boot-configuration-processor"
}
compileJava.dependsOn(processResources)
I added the plugin (I've tried not using the plugin and just making it a compile dependency, no change)
buildscript {
repositories {
maven { url 'http://repo.spring.io/plugins-release' }
}
dependencies { classpath 'io.spring.gradle:propdeps-plugin:0.0.9.RELEASE' }
}
apply plugin: 'propdeps'
apply plugin: 'propdeps-maven'
apply plugin: 'propdeps-idea'
When I run the build, I see a build/classes/java/main/META-INF/spring-configuration-metadata.json file is created based off of my properties.
When I try to use the property in either application.yml or application.properties, Intellij says it cannot resolve it.
The docs does say it should be called additional-spring-configuration-metadata.json and may expect it to be called that to process it, but I do not see a way to make the build name it that way nor configure Intellij to expect otherwise.
Has anyone got this working with gradle? Or is this a bug.
Edit I created a repo with a pair of projects to demonstrate this. One for gradle and one for maven. I created the projects from start.spring.io and basically just added the properties configuration. I also used a straight compile dependency in both cases instead of optional / compileOnly.
I had not confirmed this before, but the code assist does work for maven, but not gradle. Both create a spring-configuration-metadata.json in the META-INF in their respective build folders. I am not exactly sure who is not picking it up.
Misc relevant versions
Intellij: 2017.3.4
Springboot: 1.5.9
Gradle: 4.4.1
Java: 8.161
Turn the annotation processing on
Do not delegate IDE build/run actions to Gradle
Rebuild your project in IDE: Build -> Rebuild Project
As far as I can tell, IntelliJ (at the time of this writing, 2018.1.2) wants the spring-configuration-metadata.json file to either be in a main source root (src/main/resources/META-INF/ or src/main/java/META-INF/) or in its default output directory for it to pick it up for autocompletion of properties in your source tree. To expand on phospodka's comment, you can add something like this to your build.gradle to satisfy IntelliJ.
task copyConfigurationMetadata(type: Copy) {
from(compileJava) {
include 'META-INF/spring-configuration-metadata.json'
}
into "out/production/classes"
}
compileJava {
dependsOn processResources
finalizedBy copyConfigurationMetadata
}
This answer is a combination of the (at this time) other two answers with a minor twist. In my case this is what "fixed" the issue: (in 2019.03.01-Ultimate)
Turn on the default annotation processing (File>Settings>Build, Execution, Deployment>Annotation Processors>Enable Annotation processing
Select Obtain processors from project classpath
Select Store generated sources relative to module output directory
keep other defaults
click OK
Add the code in #thyme's answer to your build.gradle
EXCEPT instead of into "out/production/classes"
use: into "build/generated/sources/annotationProcessor"
Now you should be able to run gradle clean/build and Intellij should be able to find your "additional metadata" definitions.
Notice that even though the build.gradle code doesn't explicitly mention 'additional-spring-configuration-metadata.json', it is exactly that "additional metadata" that ends up in the annotationProcessor folder as "spring-configuration-metatdata.json" where Intellij finds it.
EDIT: Also note, you need to clean / rebuild after adding any new "additional metadata" items before Intellij will see the new entries (in the freshly regenerated file).

Gradle, OSGI and dependency management

I'm new to Gradle, please, help me to understand the following. I'm trying to build an OSGI web app via Intellij Idea + Gradle. I've found that Gradle has OSGI plugin, which is described here:
https://docs.gradle.org/current/userguide/osgi_plugin.html
But I have no idea on how to add dependency on, for example, org.apache.felix.dependencymanager which is OSGI bundle. So, I need this jar while compilation, and I don't need it in my resulting jar. I think, that I need something similar to maven 'provided' scope, or something like that.
P.S. Does anyone understand, what 'TBD' means in Gradle documentation? Does this means it has to be implemented in future, or is some mechanism is implemented, but is not yet described in docs?
Please check out the plugin I wrote, osgi-run, which was designed to make it extremely easy to play with OSGi without using any external tools like Eclipse (though osgi-run can generate a Manifest file for you, which you can point at from your IDE to get IDE OSGi support - this is what I do using IntelliJ), just Gradle.
With osgi-run, you just add a dependency to whatever you want as with any Java project... whether it should be provided by the environment or not does not matter at compile time, this is a deployment-time concern.
For example, add to your build.gradle file:
apply plugin: 'osgi' // or other OSGi plugin if you prefer
repositories {
mavenCentral() // add repos to get your dependencies from
}
dependencies {
compile "org.apache.felix:org.apache.felix.dependencymanager:4.3.0"
}
Note: the osgi plugin is just required to turn your jar into a bundle. osgi-run does not do that.
If you have any runtime dependencies that should be present in the OSGi environment but not in the compile classpath, do something like this:
dependencies {
...
osgiRuntime 'org.apache.felix:org.apache.felix.configadmin:1.8.8'
}
Now write some code, and once you're ready to run a OSGi container with your stuff in it, add these lines to the build.gradle file:
// this should be the first line
plugins {
id "com.athaydes.osgi-run" version "1.4.3"
}
...
// deployment to OSGi container config
runOsgi {
// which bundles do you want to add?
// transitive deps will be automatically added
bundles += project
// do not deploy jars matching these regexes (not needed, this is the default)
excludedBundles = ['org\\.osgi\\..*']
// make the manifest visible to the IDE for OSGi support
copyManifestTo file( 'auto-generated/MANIFEST.MF' )
}
Run:
gradle createOsgiRuntime
And find your full OSGi environment, ready to run, in the build/osgi directory.
Run it with:
build/osgi/run.sh # or run.bat in Windows
You can even run it during the build already:
gradle runOsgi
So you probably want to make your own provided configuration.
configurations {
// define new scope
provided
}
sourceSets {
// add the configurations to the compile classpath but not runtime
main.compileClasspath += configurations.provided
// be sure to add the provided configs to your tests too if needed
test.compileClasspath += configurations.provided
}
dependencies {
// declare your provided dependencies
provided 'org.apache.felix:org.apache.felix.dependencymanager:4.3.0'
}
Also the suggestion above about using the bndtool directly instead of the gradle provided osgi plugin is a good one. The gradle plugin has many deficiencies and is really just a wrapper to the bndtool anyways. Also the gradle team has declared they do not have the bandwidth or expertise to fix the osgi plugin [1].
[1] https://discuss.gradle.org/t/the-osgi-plugin-has-several-flaws/2546/5

Gradle: What Is The Default Configuration and How Do I Change It

When I run the "dependencies" task there are several sections: compile, runtime, testCompile ...
One of those sections is "default - Configuration for default artifacts." What is this section and what is it used for?
How do I change what is in the "default configuration"?
Details: Gradle 1.7
Unless your build is publishing Ivy modules, the default configuration is mainly relevant when dealing with project dependencies in a multi-project build. Given a multi-project build with projects A and B, if A declares a project dependency on B without explicitly naming a configuration (e.g. dependencies { compile project(":B") }, A (more precisely A's compile configuration) will depend on project B's default configuration. In other words, dependencies { compile project(":B") } is a shortcut for dependencies { compile project(path: ":B", configuration: "default") }.
The default configuration extends from the runtime configuration, which means that it contains all the dependencies and artifacts of the runtime configuration, and potentially more. You can add dependencies and artifacts in the usual way (using a dependencies/artifacts block in B's build script). Alternatively, B could declare a custom configuration, and A could depend on that by explicitly naming that configuration (e.g. dependencies { compile project(path: ":B", configuration: "myCustomConfig") }.
When using the gradle java plugin the 'default' configuration extendsFrom 'runtime', 'runtimeOnly', 'implementation'
If you do not use the java plugin then you can define it yourself like this
configurations {
"default"
}
The java plugin sets up the default configuration here: https://github.com/gradle/gradle/blob/85d30969f4672bb2739550b4de784910a6810b7a/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaPlugin.java#L437
The documentation is not that good in this area.
An example of "serving" a default artifact from a composite build.
The example creates a subproject that refers to a dependency in another project. This can be nessesary when working with composite builds, as only the "default" group can be depended upon.
We use this to take many jars from a single project and serve it as different dependencies when referencing the project as a composite build.
apply plugin: 'base'
configurations {
depend
}
dependencies {
depend project(path: ':', configuration: 'ConfWithArtifact')
}
artifacts {
"default" (file: configurations.depend.singleFile) {
builtBy(configurations.depend)
}
}
The default configuration is actually created by the base plugin, and so you don't need to define it yourself.
I've also had the problem with composite builds only compositing from the default configuration, but I solved it slightly differently:
plugins {
id 'base'
}
configurations {
bootstrap
it.'default'.extendsFrom bootstrap
}
dependencies {
bootstrap project(path: ':other', configuration: 'otherConfiguration')
}
This approach allows the artifact from the :other project to keep its transitive dependencies, assuming you're interested in keeping them.

Resources