Suppose we have a multi-project build. Eventually the entire project is bundled into a war. We know the web container will provide some utility jars, say, some logging-related jars, so we want to use a provided kind of scope. The war plugin offers the nice providedCompile and providedRuntime configuration. However, we want to use the war plugin only in the subproject that creates the war. So, the problem is, how can we use something like providedCompile and providedRuntime in other sub-projects? Ideally, we want to apply that scope to the logging jars in a subprojects {} closure.
update
My scenario is like below.
In the root build.gradle, I have something like this:
subprojects {
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile 'org.slf4j:slf4j-api:1.7.7' // already provided by the servlet container
compile 'javax.servlet:javax.servlet-api:3.1.0' // already provided by the servlet container
runtime 'ch.qos.logback:logback-classic:1.1.2' // already provided by the servlet container
runtime 'ch.qos.logback:logback-core:1.1.2' // already provided by the servlet container
...
These dependencies are used not just by the war sub-project, but they should be excluded in the war. Therefore, I need some mechanism to achieve this.
BTW, I have already worked out a solution.
There are a couple of ways to achieve a provided scope.
Option 1
Create a custom configuration provided. For example:
configurations {
provided
}
sourceSets.test {
runtimeClasspath += configurations.provided
}
The downside of this approach is that IDEs, for instance, IntelliJ IDEA, probably don't understand custom configuration and hence are not able to pull dependencies correctly. This happened to me with IntelliJ IDEA.
Option 2
Use the predefined compile and runtime configurations. Then, in the build.gradle of the war sub-project, filter out the jars of your choice. For example,
war {
Set exclusions = ['slf4j-api-1.7.7.jar', 'javax.servlet-api-3.1.0.jar',
'logback-classic-1.1.2.jar', 'logback-core-1.1.2.jar'] as Set
classpath = classpath.filter { file ->
!exclusions.contains( file.name )
}
}
With gradle 2.12, it is possible to use compileOnly when using java plugin.
https://docs.gradle.org/2.12/release-notes#support-for-declaring-compile-time-only-dependencies-with-java-plugin
Related
It's probably very simple, but only to people who know what they are doing.
I have a Java program that imports these two:
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
As an aside, I don't want to use the lang3 package but the lang package.
I do not have anything in my Gradle file about these. When I try to build the file, it gives me errors for these two, saying the packages do not exist.
My questions are:
Do I need to add them as "compile" or as "api"?
What is the exact syntax? I have lines that look like this:
api group: 'commons-httpclient', name: 'commons-httpclient', version: '3.1'
How do I find the right name (or should I just invent one)? and the version?
Anything your code needs (besides basic JRE classes) is a dependency for your code. Gradle manages these dependencies, usually downloading them from a repository.
First you need to find such a repository. You probably have repositories already configured in your build.gradle, like so:
buildscript {
repositories {
mavenCentral()
// maybe more repositories
}
}
That means Gradle will try to download dependencies from Maven Central. You can either do a web search for "gradle" and your dependency, or go to repository and search, or check the dependency's homepage.
You'll end up with a dependency name and version like 'org.apache.commons:commons-lang3:3.12.0'. This needs to go in your build.gradle.
Gradle has different dependencies:
buildscript dependencies provide code that Gradle needs to execute to build your project, e.g., a tool to pull in version control system information or generate code
implementation dependencies are dependencies your code needs to run, like a logging framework or JSON parser or PDF generator
test dependencies are dependencies needed to run your automated tests, like JUnit
Depending on where you need the dependency, you put it in the buildscript or the dependencies block.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.tmatesoft.svnkit:svnkit:1.9.+'
}
}
dependencies {
implementation 'pdfbox:pdfbox:0.7.3'
testImplementation 'junit:junit:4.+'
}
You don't need to repeat the implementation dependencies for the testImplementation btw, as it inherits them automatically.
You can define your own configurations as need; see the Gradle manual on dependencies, for example if you have different test suites (unit, integration, performance, ...) that need different dependencies.
you'll have to go to their official website and get the implementations then add those to the dependencies(you'll find it at the bottom of the file) in the build.gradle(module) it would look something like -
the $lifecycle_version might be somethiing like 1.2.3 or some version number.
this is what I got (not exactly sure if this is right)-
implementation 'org.apache.commons:commons-lang3:3.12.0'
got from library website in the gradle short tab
in the build.gradle(project), look for maven repo.
Once done, you'll be able to import the respective libraries.
I'm new to Gradle and trying to work out how to get my dependencies working correctly.
I have a project which builds a war using the 'war' plugin. I'd then like to use that project, and some other similar projects, to deploy those wars.
However, I can't work out how to make the project which is responsible for assembling these other projects dependent on the war projects.
The project 'war1' has a single 'war' method, I’ve tried the following
dependencies, none of which work:
dependencies {
war project(path: ':war1')
/* or */ compile project(path: ':war1')
/* or */ assemble project(path: ':war1')
}
Could not find method xxx() for arguments [DefaultProjectDependency{dependencyProject='project ':war1', configuration='default'}]
You can specify dependencies on .war artifacts in Gradle like this example...
dependencies {
runtime "org.jasig.cas:cas-server-webapp:3.5.2#war"
}
NOTE: this example is for an external dependency, not a dependency on another sub-project within the same multi-project setup. Looking at the api docs, it appears that you would do that like this...
dependencies {
runtime project(path: ':war1', configuration: 'war')
}
Also -- perhaps you could benefit from the Gradle WAR overlay plugin. This plugin allows you to "enhance" a war dependency by adding or tweaking a few files within it, and thereby provide some configuration choices that your project knows about, but the original war didn't.
I have been trying to find the correct settings for IntelliJ's annotation processing in order for it to co-exist with Gradle's build process.
Whenever I build from IntelliJ I cannot get it to recognise the generated sources from the gradle-apt-plugin.
My requirements for my project are:
Building between IntelliJ and Gradle should be seamless and not interfere with the process of each other
I need to use IntelliJ's Create separate module per source set option
I need to use IntelliJ's folder based structure
IntelliJ needs to be able to recognise and autocomplete AutoValue classes
Here are the steps for a MCVE in order to reproduce the issue with IntelliJ 2017.2.4 and Gradle 3.5:
Create a new Gradle project from IntelliJ
Check the Create separate module per source set option
Open build.gradle file:
Add the following plugins block:
plugins {
id 'java'
id 'net.ltgt.apt' version '0.12'
}
Add the following dependencies block
dependencies {
compileOnly 'com.google.auto.value:auto-value:1.5'
apt 'com.google.auto.value:auto-value:1.5'
}
Go to Settings → Build, Execution, Deployment → Annotation Processors
Check the Enable Annotation Processing
Create a class:
#AutoValue
public abstract class GeneratedSourcesTest {
static GeneratedSourcesTest create(String field) {
return new AutoValue_GeneratedSourcesTest(field);
}
public abstract String field();
}
On IntelliJ run Build → Build Project
Open the GeneratedSourcesTest class, on the static factory method, everything compiles fine but I get the error:
cannot resolve symbol ‘AutoValue_GeneratedSourcesTest’
How can I make the AutoValue_GeneratedSourcesTest class accessible from IntelliJ?
After importing your Gradle project under IDEA do the following steps:
Set annotation processing configuration as follows:
Run menu: Build - Build Project
Right click on each new generated folder and select: Mark Directory as - Generated Sources Root so it was marked as follows:
Add /generated to project's .gitignore file
That's a minimal viable configuration which will provide full IDE support for generated classes.
The drawback is, whenever Gradle project gets re-imported the generated folders will need be marked as Generated Sources Root again.
Perhaps this can be improved with adding these paths as source sets under build.gradle.
Sometimes it happens that IDEA modules lose their compiler output path settings in result of the above. It's sufficient to just set it back to their default folders.
The answers are (should be) in the README for the gradle-apt-plugin: https://github.com/tbroyer/gradle-apt-plugin
Namely, also apply the net.ltgt.apt-idea plugin.
Btw, I recommend delegating build/run actions to Gradle in IntelliJ. Sure it's a bit slower, but requires zero setup in the IDE and works reliably. That said, it should also work OK if you don't.
Just have your build.gradle with these and it works fine, no need of touching intellij, source set etc..
plugins {
id 'java'
id "net.ltgt.apt" version "0.20"
}
apply plugin: 'idea'
apply plugin: 'net.ltgt.apt-idea'
group 'abc'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile "com.google.auto.value:auto-value-annotations:1.6.2"
annotationProcessor "com.google.auto.value:auto-value:1.6.2"
}
I didn't have to do anything to intellij using maven by adding the optional true tag.
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.9</version>
<optional>true</optional>
</dependency>
Dear StackOverflow users
I have a gradle project of which I want to turn the artifact into an osgi bundle. In this bundle I have:
packages that I don't want to export (may not appear in manifest's Export-Package entry)
dependencies that I want to embed (may not appear in manifest's Import-Package entry)
After a bit of tinkering I have come up with the following gradle.build file which does what I intend but maybe not in the cleanest way possible, leveraging bnd...
group 'com.mycompany'
version '1.0.0'
apply plugin: 'java'
apply plugin: 'osgi'
repositories {
jcenter()
}
dependencies{
compile 'org.osgi:org.osgi.framework:1.8.0' //provided
compile 'com.google.code.gson:gson:2.8.0' //embedded
}
jar {
//embedding the gson dependency
from({
def x = configurations.compile.find({
return it.getName().contains('gson')
})
def tree = zipTree(x)
return tree
})
//explicitly building manifest entries
manifest {
instruction 'Bundle-Vendor',
'My Company'
instruction 'Bundle-Activator',
'com.mycompany.mybundle.Activator'
instruction 'Import-Package',
'!com.google.gson',
'*'
instruction 'Export-Package',
/com.mycompany.mybundle;version="${version}"/
}
}
Is it possible to accomplish this in a cleaner way? I mainly want to avoid two things:
having to manually write the import and export-package entries
having to manually copy the contents of the embedded dependencies (gson) into my jar
I thought bnd (underlying the osgi plugin) could do that for me, but with what I have tried so far (even if I add them as private package) bnd still exports everything and imports the gson package as well as it won't add the gson classes to the jar
You would be better off using the Bnd Gradle plugin for OSGi. It is written and supported by the developers of bnd who know a thing or two about OSGi.
To specify a Maven dependency in my project, I provide a name, a group id, and a version. This has been enough for every dependency in my project, save one. Pig has multiple jars in the same artifact (not sure if I have the proper nomenclature; I'm still rather new to Maven), but I only need one.
Specifically, I need pig-0.13.0-h2.jar. However, when I provide the dependency
compile "org.apache.pig:pig:0.13.0"
in my build.gradle, only pig-0.13.0.jar, pig-0.13.0-sources.jar, and pig-0.13.0.pom are downloaded. I need the "*-h2.jar", because that's the correct one to work with my version of Hadoop.
Is there a way to tell Gradle (and, generally, Maven or whatever) that my compile dependency requires this exact jar, and that only this one should be included in the classpath?
What you need is to specify the classifier. The following script will do the job:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile "org.apache.pig:pig:0.13.0:h2"
}
task copyDeps(type: Copy) {
from configurations.compile
into 'deps'
}