Gradle sourceSets based on gradle.settings - java

I would like to have some features of my Java library conditionaly built based on custom settings defined in project's settings.gradle.
Example:
build.gradle
apply plugin: 'java'
sourceCompatibility = 1.7
repositories {
mavenCentral()
}
sourceSets {
extra_feature
}
dependencies {
compile 'net.java.dev.jna:jna:4.1.0'
}
// I need a way to link the "extra_feature" sourceSets to the default "build" action based on some settings in settings.gradle.
settings.gradle
extraFeatures = true

First, move your parameter to gradle.properties
Second, use simple if to control source sets:
sourceSets (
if ("true" == "$extraFeatures") {
}
)
Example (I didnt test it):
sourceSets {
main {
java {
srcDir 'src/java'
if ("true" == "$extraFeatures") {
srcDir 'src/java/mysecretcode'
}
}
}
}

Related

Kotlin+Gradle runnable jar - dependency causing "Could not find or load main class"

Gradle build file:
buildscript {
ext.kotlin_version = '1.2.41'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
group 'com.anivive'
version '0.1'
apply plugin: 'kotlin'
sourceSets {
main.java.srcDirs += 'src/main/kotlin/'
test.java.srcDirs += 'src/test/kotlin/'
}
repositories {
mavenLocal()
maven {
url "https://packagecloud.io/anivive/anivive/maven2"
}
mavenCentral()
}
dependencies {
compile 'anivive:Import_Utils:1.2.44'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
jar {
baseName = 'XMLModelBuilder'
version = '0.1'
manifest {
attributes 'Main-Class': 'com.anivive.Main'
}
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
File structure:
src
- main
- kotlin
- com
- anivive
- Main.kt
Main.kt:
package com.anivive
import com.anivive.util.ExampleClass
object Main {
#JvmStatic
fun main(args: Array<String>) {
ExampleClass.exampleMethod()
}
}
So, I'm trying to build a runnable jar file that will call a single method from a class in the dependency 'anivive:Import_Utils:1.2.44'.
If I remove the dependency, and change my main method to just println("Test"), the jar will run fine via java -jar build/libs/jarFile.jar and it will print out Test.
However, with the dependency included and when trying to call a function from it, I will get Error: Could not find or load main class com.anivive.Main whenever I try to run the Jar file. I suspect it has something to do with hosting the jar file on packagecloud, but I'm surprised this is a problem, considering I can run the program just fine from IntelliJ.
What gives?

Add Library to Gradle Kotlin app

I converted simple Kitlon file into Library, the file is:
Display.kt:
package hello
fun main(args: Array<String>) {
println("Hello World!")
}
had been compiled into library using the command:
kotlinc Display.kt -d Display.jar
The output had been cross checked to be worked using the command:
kotlin -classpath Display.jar hello.DisplayKt
Then I moved it to folder src/main/resources, then tried calling it from another app, using the below code:
Hello.kt:
package hello
import hello.DisplayKt
fun main(args: Array<String>) {
println("Hi")
}
and defined the build.gradle file as below (tried to put all option I read about to solve my case):
// set up the kotlin-gradle plugin
buildscript {
ext.kotlin_version = '1.1.2-2'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// apply the kotlin-gradle plugin
apply plugin: "kotlin"
// add kotlin-stdlib dependencies.
repositories {
mavenCentral()
}
dependencies {
//dependencies from a remote repositor
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
//local file
compile files('src/main/resources/Display.jar')
compile fileTree(dir: 'src/main/resources', include: '*.jar')
}
jar {
manifest {
//Define mainClassName as: '[your_namespace].[your_arctifact]Kt'
attributes ('Main-Class': 'hello.HelloKt', "Implementation-Title": "Gradle",
"Implementation-Version": 1)
}
// NEW LINE HERE !!!
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
sourceSets {
main {
java {
srcDirs = ['src/kotlin']
}
resources {
srcDirs = ['src/resources']
}
}
}
but, after running gradle build command, I got the below error:
Unresolved reference: DisplayKt
Note: I'm very very new to JAVA/KOTLIN and GRADLE
I found the answer, the full path of the function is hello.main

How to use variables in a multi-project gradle build system?

I have a multi-project structure managed with gradle. All the java sub-projects have this jar block:
def main_class = "foo.Main"
jar {
manifest {
attributes 'Main-Class': main_class
}
}
So I decided that I'm going to move the jar block to the root project and have only the def main_class in the sub-projects, but no matter how I defined the main_class variable, it didn't work. I tried project.ext and properties {} as well.
I had a task, called dist which worked with project.ext:
root project:
subprojects {
task dist(dependsOn: jar) << {
copy {
from('build/libs') {
include (build_jar)
}
into('.')
rename(build_jar, app_jar)
}
}
}
a sub-project:
project.ext {
build_jar = "..."
app_jar = "..."
}
How can I define a variable that works with jar like with the dist task?
You can just do:
ext {
main_class = 'com.Main'
}
subprojects {
apply plugin: 'java'
jar {
manifest {
attributes 'Main-Class': main_class
}
}
}
in PROJECT_ROOT/build.gradle file.
To override extra properties in subproject's build.gradle you must put your desired task (in this case the jar task) inside the afterEvaluate block.
root project build.gradle:
subprojects {
apply plugin: 'java'
apply plugin: 'application'
ext {
// the property that should be overridden in suproject's build.gradle
main_class = ''
}
afterEvaluate {
jar {
manifest {
attributes 'Main-Class': main_class
}
}
}
}
sub project build.gradle:
mainClassName = 'project.specific.Main'
ext.set("main_class", mainClassName)
// you could also use this notation, but I prefer the first one
// since it is more clear on what it is doing
//main_class = mainClassName

AspectJ + Gradle configuration

I'd like to use AspectJ in Gradle project (it's not an Android project - just a simple Java app).
Here is how my build.gradle looks like:
apply plugin: 'java'
buildscript {
repositories {
maven {
url "https://maven.eveoh.nl/content/repositories/releases"
}
}
dependencies {
classpath "nl.eveoh:gradle-aspectj:1.6"
}
}
repositories {
mavenCentral()
}
project.ext {
aspectjVersion = "1.8.2"
}
apply plugin: 'aspectj'
dependencies {
//aspectj dependencies
aspectpath "org.aspectj:aspectjtools:${aspectjVersion}"
compile "org.aspectj:aspectjrt:${aspectjVersion}"
}
The code compiles, however the aspect seems to not be weaved. What could be wrong?
I have been struggled with this for a while, so this the config I use and works well.
In your configuration do this.
configurations {
ajc
aspects
aspectCompile
compile{
extendsFrom aspects
}
}
In your dependencies use the following configuration. Spring dependencies are not needed if you are not using spring fwk.
dependencies {
//Dependencies required for aspect compilation
ajc "org.aspectj:aspectjtools:$aspectjVersion"
aspects "org.springframework:spring-aspects:$springVersion"
aspectCompile "org.springframework:spring-tx:$springVersion"
aspectCompile "org.springframework:spring-orm:$springVersion"
aspectCompile "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:$hibernateJpaVersion"
}
compileJava {
sourceCompatibility="1.7"
targetCompatibility="1.7"
//The following two lines are useful if you have queryDSL if not ignore
dependsOn generateQueryDSL
source generateQueryDSL.destinationDir
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
doLast{
ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
ant.iajc(source:"1.7", target:"1.7", destDir:sourceSets.main.output.classesDir.absolutePath, maxmem:"512m", fork:"true",
aspectPath:configurations.aspects.asPath,
sourceRootCopyFilter:"**/.svn/*,**/*.java",classpath:configurations.compile.asPath){
sourceroots{
sourceSets.main.java.srcDirs.each{
pathelement(location:it.absolutePath)
}
}
}
}
}
I dont use the plugin I use the ant and aspectj compiler to do that, probably there will be an easy way
Just want to add the so called "official" plugin for AspectJ mentioned by Archie.
Here's some gradle script example on how to do it:
apply plugin: 'java'
sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
if (!hasProperty('mainClass')) {
ext.mainClass = 'com.aspectz.Main'
}
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.aspectj:gradle-aspectj:0.1.6"
//classpath "gradle.plugin.aspectj:plugin:0.1.1"
//classpath "gradle.plugin.aspectj:gradle-aspectj:0.1.1"
}
}
ext {
aspectjVersion = '1.8.5'
}
apply plugin: "aspectj.gradle"
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.10'
compile("log4j:log4j:1.2.16")
compile("org.slf4j:slf4j-api:1.7.21")
compile("org.slf4j:slf4j-log4j12:1.7.21")
compile("org.aspectj:aspectjrt:1.8.5")
compile("org.aspectj:aspectjweaver:1.8.5")
}
However, it seems that it only supports Java 8 and above. As when you use java 7 to build it, it got error :
java.lang.UnsupportedClassVersionError: aspectj/AspectJGradlePlugin : Unsupported major.minor version 52.0
Looks like there is a new "official" gradle plugin for AspectJ:
https://plugins.gradle.org/plugin/aspectj.gradle
Unfortunately the documentation is minimal. I haven't tried it myself.
This plugin worked for me (gradle 5.6):
plugins {
id 'java'
id "io.freefair.aspectj.post-compile-weaving" version "4.1.4"
}
A bit ugly, but short and does not require additional plugins or configurations.
Works for me:
Add aspectjweaver dependency ti Gradle build script. Then in the task you need it find the path to its jar and pass as javaagent in jvmArgs:
dependencies {
compile "org.aspectj:aspectjweaver:1.9.2"
}
test {
group 'verification'
doFirst {
def weaver = configurations.compile.find { it.name.contains("aspectjweaver") }
jvmArgs = jvmArgs << "-javaagent:$weaver"
}
}
Add aop.xmlfile to the resources\META-INF\ folder with the specified Aspect class:
<aspectj>
<aspects>
<aspect name="utils.listener.StepListener"/>
</aspects>
</aspectj>
Example of an aspect:
package utils.listener
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.*
import org.aspectj.lang.reflect.MethodSignature
#Aspect
#SuppressWarnings("unused")
public class StepListener {
/* === Pointcut bodies. Should be empty === */
#Pointcut("execution(* *(..))")
public void anyMethod() {
}
#Pointcut("#annotation(org.testng.annotations.BeforeSuite)")
public void withBeforeSuiteAnnotation() {
}
}
Adding this in my build.gradle file worked for me.
project.ext {
aspectjVersion = '1.8.12'
}
apply plugin: "aspectj.gradle"
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.aspectj:gradle-aspectj:0.1.6"
}
}
Doing a gradle assemble injected the code defined in the aspect.

How registering the output of a SourceSets for the dependencies

I have a project with the java plugin applied, and an additionnal source set
project(':dependencie') {
apply plugin: 'java'
sourceSets {
generated {
java {
srcDir 'src/generated/java'
}
}
main {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
test {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
}
}
And another depending of this one :
project(':dependsFrom') {
apply plugin: 'java'
dependencies {
compile(
project(':dependencie')
) { transitive = false }
}
}
My problemes is that when I am trying to compile dependsFrom, it doesn't find the classes of the sourceSet generated for the project dependencie. My workaround is to add the line
output.dir(generated.output, builtBy: 'regenerateFromWsdl')
to the main source set of dependencie but any insight to how "registering" the output of the generated source set for future dependencies would be really helpful.
I you want to model the generated code as a separate source set, you have to create a Jar and publish it via the runtime configuration:
task generatedJar(type: Jar) {
from sourceSets.generated.output
}
artifacts {
runtime generatedJar
}
Alternatively, you could add src/generated/java as another source directory for the main source set, in which case it will get compiled/packaged/exported together with that.
In fact I found a solution. You just need to add the generated sourceSet output to the jar task of dependencie project, as it is this same jar task which "inject" the project into the dependecie system.
My problem was that I tought that any additional sourceSet of the project would have been automatically used by all the tasks of the project.
Here the modified gradle script
project(':dependencie') {
apply plugin: 'java'
sourceSets {
generated {
java {
srcDir 'src/generated/java'
}
}
main {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
test {
compileClasspath += generated.output
runtimeClasspath += generated.output
}
}
jar {
from sourceSets.generated.output
}
}

Categories

Resources