Task in gradle to include java class before compile - java

I need to create Gradle task which can replace .java files before Gradle build.
Gradle build package app in .war file. And I need to have replaced bytecode there after build.
I tried sourceSets Gradle task but it can only exclude files.
sourceSets {
main {
java {
exclude 'com/myapp/example/resource/impl/ResourceBundleImpl.java'
}
}
}
But I need to also include file in the same place. How I can do it with Gradle?
The directory to file that I need to exclude: com/myapp/example/resource/impl/ResourceBundleImpl.java
The directory to file that I need to include: src/main/webapp/WEB-INF/my/ResourceBundleImpl.java
To copy file content it is also posible solution.But How can I do it before compile time?
The below task didn't helped, becouse in build file have .java files instead of .classe file.
task prepareSources(type: Copy) {
from('src/main/webapp/WEB-INF/my')
into('build/classes/java/main/com/myapp/example/resource/impl')com/myapp/example
}
// Prepare sources, before compile
compileJava {
dependsOn prepareSources
}
The below task throws :
Task :cdx-war:compileJava FAILED
error: package com.myapp.example.util does not exist
sourceSets {
main {
java {
srcDir "$projectDir"
exclude 'com/medtronic/diabetes/carelink/rbps/resource/impl/ResourceBundleImpl.java'
include 'src/main/webapp/WEB-INF/my/ResourceBundleImpl.java'
}
}

I put classes that I need to replace together and add suffix to one of them and replace this suffix during compile time :
sourceSets {
main {
java {
srcDirs = ["$buildDir\\generated-src"]
}
}
}
task copySourceSet(type: Copy) {
println 'Change java class in patient-svc-war'
from "$rootDir\\patient-svc-war\\src\\main\\java"
into "$buildDir\\generated-src"
from file("$rootDir\\patient-svc-war\\**_suffix.java")
into "$buildDir\\generated-src"
rename { String fileName ->
fileName.replace("_suffix", "")
}
filter { line -> line.replaceAll('_suffix', '')}
}
compileJava.source "$buildDir\\generated-src"
compileJava {
dependsOn copySourceSet
}
compileJava.doLast {
delete "$buildDir\\generated-src"
}

Related

How to provide generated data-binding classes in a Gradle Javadoc task?

With this Gradle task I've used to extract AAR, in order to generate Javadoc:
task javadoc(type: Javadoc) {
doFirst {
configurations.implementation.filter { it.name.endsWith('.aar') }.each { aar ->
copy {
from zipTree(aar)
include "**/classes.jar"
into "$buildDir/tmp/aarsToJars/${aar.name.replace('.aar', '')}/"
}
}
}
failOnError false
options.linkSource true
options.links("https://docs.oracle.com/en/java/javase/11/docs/api/")
options.links("https://developer.android.com/reference/")
title = "Colorpicker Library ${versionName} API"
source = android.sourceSets.main.java.srcDirs
classpath = files(new File("${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"))
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += fileTree(dir: "$buildDir/tmp/aarsToJars/")
configurations.implementation.setCanBeResolved(true)
classpath += configurations.implementation
destinationDir = file("${project.buildDir}/outputs/javadoc/")
exclude "**/BuildConfig.java"
exclude "**/R.java"
}
It fails since I've enabled androidx.databinding 7.2.1 inside the library module:
> Task :library:javadoc
...\ColorPickerDialogFragment.java:24: error: package com.acme.databinding does not exist
import com.acme.databinding.DialogColorPickerBinding;
^
...\ColorPickerDialogFragment.java:46: error: cannot find symbol
DialogColorPickerBinding mDataBinding;
^
symbol: class DialogColorPickerBinding
location: class ColorPickerDialogFragment
2 errors
How can I add these generated sources to classpath? Ignoring the class import doesn't seem to be an option. Or does javadoc have to depend on the task, which generates these (bad timing)? In general, exclude "**/ColorPickerDialogFragment.java" is not the answer I'm looking for.
Extracting the built AAR and putting it on classpath provides the generated classes -
but it's a whole lot more elegant to reference the intermediate classes.jar already:
task javadoc(type: Javadoc) {
...
doFirst {
...
def aar_main = new File("$buildDir/intermediates/aar_main_jar")
if (aar_main.exists()) {
copy {
from aar_main
include "**/classes.jar"
into "$buildDir/tmp/aarsToJars/aar_main_jar/"
}
}
}
}
One can also check .exists() before already:
javadoc.onlyIf {
new File("$buildDir/intermediates/aar_main_jar").exists()
}

Delombok'ing source code with added jar dependencies

I am unable to delombok my Java source code, apparently due to jar dependencies that the project has, and I don't understand why. There are two jar files that have to be committed to the repo to tag along, and they are added to the project in the dependencies node of the build.gradle file by adding the line compile files('myproj1.jar'). So, the relevant part of the build.gradle file looks like this:
dependencies {
compile files('myproj1.jar')
compile files('myproj2.jar')
.....
}
When I run the delombok task I get the following error:
Execution failed for task ':delombok'.
> taskdef class lombok.delombok.ant.Tasks$Delombok cannot be found
using the classloader AntClassLoader[/path/to/repo/myproj1.jar:/path/to/repo/myproj2.jar]
Why would delombok task be using the AntClassLoader from the jar files?
I have tried the delombok'ing code from this post
Here is the task from my build.gradle file
def srcJava = 'src/main/java'
def srcDelomboked = 'build/src-delomboked'
task delombok {
// delombok task may depend on other projects already being compiled
dependsOn configurations.compile.getTaskDependencyFromProjectDependency(true, "compileJava")
// Set up incremental build, must be made in the configuration phase (not doLast)
inputs.files file(srcJava)
outputs.dir file(srcDelomboked)
doLast {
FileCollection collection = files(configurations.compile)
FileCollection sumTree = collection + fileTree(dir: 'bin')
ant.taskdef(name: 'delombok', classname: 'lombok.delombok.ant.Tasks$Delombok', classpath: configurations.compile.asPath)
ant.delombok(from:srcJava, to:srcDelomboked, classpath: sumTree.asPath)
}
}
I expect to be able to delombok my Java source code as part of the build process so that when the project is compiled there are no dependencies on Lombok.
So after continued trial an error, I have a working implementation. To answer my own question, the problem has nothing to do with the additional Jar files. Rather, when gradle runs the delombok task, the classes in the lombok jar are not in the classpath of the org.gradle.api.AntBuilder (ie, the ant task), and so it does not have a reference to lombok.delombok.ant.Tasks$Delombok anywhere (which seems obvious at this point, but not at the time).
The solution thus far has been to add those references in from configurations.compile
Combining code snippits from this post and this post you can do it with something like this:
def srcDelomboked = 'build/src-delomboked'
task delombok {
description 'Delomboks the entire source code tree'
def srcJava = 'src/main/java'
inputs.files files( srcJava )
outputs.dir file( srcDelomboked )
doFirst {
ClassLoader antClassLoader = org.apache.tools.ant.Project.class.classLoader
def collection = files( configurations.compile + configurations.testCompile )
def sumTree = collection + fileTree( dir: 'bin' )
sumTree.forEach { File file ->
antClassLoader.addURL(file.toURI().toURL())
}
ant.taskdef( name: 'delombok', classname: 'lombok.delombok.ant.Tasks$Delombok',
classpath: configurations.compile.asPath + configurations.testCompile.asPath )
ant.delombok( from: srcJava, to: srcDelomboked, classpath: sumTree.asPath )
}
}
sourceSets {
main {
java { srcDirs = [ srcDelomboked ] } //blow away the old source sets so that we only use the delomboked source sets
}
test {
java { srcDirs += [ srcDelomboked ] } //but add those new source sets to the tests so that their references are available at test time
}
}
compileJava.dependsOn(delombok)
bootJar {
mainClassName = 'com.myproj.MyMainClass' // you will need this if its a Spring Boot project
}
Hope this helps whomever else needs to delombok their code.

Gradle : :Could not find method main() for arguments" on setting outputDir in sourceSets

Please find the script below to clean and build a project using gradle.
Everything was working fine until I added outputDir to the sourceSets in java block.
On commenting out the outputDir line, the gradle clean and build is successful, but the class files are generated in ''build/classes//main'' which I did not want. I wanted the class in directory ''build/classes//'' and not create the main folder and place the class files in that.
apply plugin: 'java'
//Declarations
def projectName="SomeProject"
def projectDir="build//classes"
sourceSets {
main {
java {
srcDir 'src'
outputDir = file("${projectDir}")
}
}
}
dependencies {
compile fileTree(include: ['*.jar'],dir: 'lib')
}
jar{
manifest {
attributes 'Main-Class': 'Foo'
attributes 'Class-Path': 'lib/com.jcraft.jsch_0.1.31.jar lib/commons-io-2.6.jar lib/commons-net-3.6.jar lib/javax.mail.jar lib/jsch-0.1.54.jar lib/json-simple-1.1.1.jar lib/jxl-2.6.jar lib/ojdbc8.jar'
}
baseName = '${projectName}'
}
Also tried with outputdir 'build//classes/ but the same error is occuring as
Could not find method main() for arguments [build_3eivce3rhjp4go01pnr2m3vvmq$_run_closure1_closure6#87800a] on root project 'SomeProject'.
Please suggest what am I missing. Seems some basic issue to me, but can't crack it.
See this documentation : https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceSetOutput.html
outputDir is a property, not a method, so you are not using the correct syntax to set the property value : use the following instead:
sourceSets {
main {
java {
srcDir 'src'
outputDir = file("${projectName}")
}
}
}
Note: you are using simple quote ' in '${projectName}' instead of double
quote " : this cannot work as your variable projectName will not be evaluated.

Gradle Include Source Files

I have a project in which I have two different 'sub-projects', the main library and a compiler for a programming language in a directory structure like this:
- build.gradle
- src
- library
- compiler
- ...
My build.gradle looks like this:
sourceSets
{
library
{
java
{
srcDir 'src/library'
srcDir 'src/asm'
}
}
compiler
{
java
{
srcDir 'src/compiler'
}
}
//...
}
// ...
task buildLib(type: Jar, dependsOn: 'classes') {
from sourceSets.library.output
classifier = 'dyvil-library'
}
task buildCompiler(type: Jar, dependsOn: 'classes') {
from sourceSets.compiler.output
classifier = 'dyvil-compiler'
}
My problem is that whenever I try to run the buildCompiler task, the build fails and the Java Compiler gives me hundreds of errors in places where the compiler source code references classes in the library. I already tried to make the compiler dependant on the library classes like this:
task buildCompiler(type: Jar, dependsOn: [ 'classes', 'libraryClasses' ]) {
from sourceSets.compiler.output
classifier = 'dyvil-compiler'
}
But that did not help. I know that I could theoretically copy the srcDirs from sourceSets.library into sourceSets.compiler like this:
compiler
{
java
{
srcDir 'src/library'
srcDir 'src/asm'
srcDir 'src/compiler'
}
}
But that seems like a bad idea for obvious reasons.
Is there another way to include the source files from the library when compiling the compiler (duh)?
There's a similar question on SO here.
I replicated your situation locally and the fix was to add a line to the sourceSets for compiler as follows:
compiler
{
java {
srcDir 'src/compiler'
}
compileClasspath += library.output
}

gradle - copy file after its generation

I try to build jar and after that copy it to another folder.
task createJar(type: Jar) {
archiveName = "GradleJarProject.jar"
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': 'me.test.Test'
}
baseName = project.name
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
task copyJarToBin {
copy {
from 'build/libs/GradleJarProject.jar'
into "d:/tmp"
}
}
task buildApp (dependsOn: [clean, createJar, copyJarToBin])
But I can't figure out one problem.
copyJarToBin task try to copy old jar. If I delete /build folder in the project and run buildApp() task, task createJar() will generate .jar file, but copyJarToBin() won't find that .jar file.
Could you help me?
Thanks.
The culprit is your copyJarToBin task. when doing
task copyJarToBin {
copy {
from 'build/libs/GradleJarProject.jar'
into "d:/tmp"
}
}
you copy the jar during the configuration time by using the copy method. (see the gradle user guide at https://docs.gradle.org/current/userguide/userguide_single.html#sec:build_phases to understand the build lifecycle)
You want to run the actual copy operation during the execution phase (the execution of the task).
One way to solve that is to move the call of the copy method into a doLast block:
task copyJarToBin {
doLast {
copy {
from 'build/libs/GradleJarProject.jar'
into "d:/tmp"
}
}
}
The problem with this approach is that you won't benefit of gradles incremental build feature and copy that file every single time you execute the task even though the file hasn't changed.
A better and more idiomatic way of writing your copyJarToBin task is to change your task implementation to use the Copy task type:
task copyJarToBin(type: Copy) {
from 'build/libs/GradleJarProject.jar'
into "d:/tmp"
}
We can even improve this snippet by taking advantage of gradle's autowiring feature. You can declare the output of one task as input to another. So instead of writing `build/libs/GradleJarProject.jar' you can simply do:
task copyJarToBin(type: Copy) {
from createJar // shortcut for createJar.outputs.files
into "d:/tmp"
}
Now you don't need to bother about task ordering as gradle know that the createJar task must be executed before the copyJarToBin task can be executed.
I think the above answer is somehow old. Here is an answer using gradle 3.3
jar {
baseName = 'my-app-name'
version = '0.0.1'
}
task copyJar(type: Copy) {
from jar // here it automatically reads jar file produced from jar task
into 'destination-folder'
}
build.dependsOn copyJar
Just made few corrections to above Answers:
jar {
baseName = "$artifactId"
version = '0.0.1'
}
task copyJar(type: Copy) {
from jar // copies output of file produced from jar task
into 'destination-folder'
}
build.finalizedBy copyJar
You probably need to ensure they are run in the right order,
task copyJarToBin(type:Copy,dependsOn:[createJar]) {
copy {
from "${buildDir}/GradleJarProject.jar" // needs to be gstring
into "d:/tmp"
}
}
In my use case I needed projectA to consume (unzip) contents from projectB's jar output. In this case the embedded doLast { copy { .. }} was required.
configurations {
consumeJarContents
}
dependencies {
consumeJarContents project(':projectB')
}
task copyFromJar() {
dependsOn configurations.consumeJarContents
doLast {
copy {
configurations.consumeJarContents.asFileTree.each {
from( zipTree(it) )
}
into "$buildDir/files"
}
}
}
The problem with task copyFromJar(type: Copy) in this scenario is that the Copy configuration phase checks for the jar file, which it does not find because it has not yet been created, and so declares NO-INPUT for the task at execution time.

Categories

Resources