method of one task is automatically called by another task in gradle - java

I am facing the problem in build.gradle file. I am using gradle version 2.14.1. In my gradle build there is a function named ask(),I am using in task grun(type:JavaExec) {...}, which is automatically called by other tasks. I don't want this to happen. ask() function invokes gradle console to get input from user while I run gradle grun --no-daemon. But I am getting console in all gradle tasks like gradle compile --no-daemon , gradle grunGui --no-daemon or gradle grunTree --no-daemon and no other task is depended on this task except grun. This is my gradle code:
apply plugin: 'antlr'
repositories {
mavenCentral()
}
dependencies {
antlr 'org.antlr:antlr4:4.5.2' // using ANTLR v4
}
generateGrammarSource {
/*arguments += ["-visitor", "-long-messages"]*/
arguments += ["-visitor", "-no-listener"]
}
task compile(type: JavaCompile){
classpath = project.getConfigurations().getByName(AntlrPlugin.ANTLR_CONFIGURATION_NAME) + sourceSets.main.runtimeClasspath
source = fileTree(dir: 'src/main/', include: '*.java')
destinationDir = file('build/classes/main')
}
task grunGui (type:JavaExec){
classpath = project.getConfigurations().getByName(AntlrPlugin.ANTLR_CONFIGURATION_NAME) + sourceSets.main.runtimeClasspath
main = 'org.antlr.v4.gui.TestRig'
def grammarName = "Wolf"
args = [grammarName, 'init', '-gui', "src/main/Wolf/first.wlf"]
}
task grunTokens (type:JavaExec){
classpath = project.getConfigurations().getByName(AntlrPlugin.ANTLR_CONFIGURATION_NAME) + sourceSets.main.runtimeClasspath
main = 'org.antlr.v4.gui.TestRig'
def grammarName = "Wolf"
args = [grammarName, 'init', '-tokens', "src/main/Wolf/first.wlf"]
}
task grunTree (type:JavaExec){
classpath = project.getConfigurations().getByName(AntlrPlugin.ANTLR_CONFIGURATION_NAME) + sourceSets.main.runtimeClasspath
main = 'org.antlr.v4.gui.TestRig'
def grammarName = "Wolf"
args = [grammarName, 'init', '-tree', "src/main/Wolf/first.wlf"]
}
def ask() {
def console = System.console()
if (console)
return console.readLine('\n> Please enter input string or filename to parse OR press enter⏎ to skip:\n')
else
logger.error "Cannot get console. Using default inputFile src/main/Wolf/first.wlf"
return ''
}
task grun(type:JavaExec) {
classpath = project.getConfigurations().getByName(AntlrPlugin.ANTLR_CONFIGURATION_NAME) + sourceSets.main.runtimeClasspath
main = 'Wolf'
def input = ask()
args = input.length() > 0 ? [input] : ["src/main/Wolf/first.wlf"]
}
Console is coming while calling compile task

Related

Gradle task : Git with dynamic values & specific treatment automation

i'm trying to build tasks to help my team. i have 2 mains branch for front & back and if the developper working on back and need to update front i want to cherry pick all commits from front and vice versa for front to back.
I'm using gradle 7.4.2
Here is my pseudocode to what i want to do :
if (${git branch --show-current} == 'front') {
def st = git cherry-pick $(git merge-base --fork-point back)..back
} else if (${git branch --show-current} == 'back') {
def st = git cherry-pick $(git merge-base --fork-point front)..front
}
But yeah, gradle don't look at that friendly ahahah
Well.. i'm badly new with gradle tasks so don't hesitate to tips me
Actually i have an error to the step to construct the request to get the commit to my final request
plugins {
id 'java'
id 'io.quarkus'
id 'base'
}
ext {
charset = 'UTF-8'
}
def current
task getGitCurrent(type: Exec) {
commandLine 'git', 'branch', '--show-current'
standardOutput = new ByteArrayOutputStream()
ext.current = {
standardOutput.toString(charset)
}
def currentRes = file("${buildDir}/current.txt")
outputs.file currentRes
doLast {
if (!buildDir.exists()) {
buildDir.mkdirs()
}
current = tasks.getGitCurrent.current()
println "current branch : ${current}"
}
}
def commitStart
task getGitCommitStart(dependsOn: 'getGitCurrent') {
doLast {
println "Branche A : ${current}"
def String notCurrent
if (current == "front") {
notCurrent = "back"
} else if (current == "back") {
notCurrent = "front"
} else notCurrent = "master"
println "Branche B : ${notCurrent}"
exec {
commandLine 'git', 'merge-base', '--fork-point', "$notCurrent"
standardOutput = new ByteArrayOutputStream()
ext.commitStartRes = {
standardOutput.toString(charset)
}
def commitStartRes = file("${buildDir}/commitStart.txt")
outputs.file commitStartRes
if (!buildDir.exists()) {
buildDir.mkdirs()
}
commitStart = tasks.getGitCommitStart.commitStart()
}
}
}
And i have this exception who correspond to the line :
outputs.file commitStartRes
* What went wrong:
Execution failed for task ':getGitCommitStart'.
> Cannot call TaskOutputs.file(Object) on task ':getGitCommitStart' after task has started execution.
I just don't understand why my task getGitCommitStart() don't working like getGitCurrent() because it gives me good results. The problem looks about doLast scope, something looks wrong but I'm a little confused, what i'm missing there ?
Well i decomposed step-by-step and i'm so close to get a result, here i am :
task first(type: Exec) {
commandLine 'git', 'branch', '--show-current'
standardOutput = new ByteArrayOutputStream()
ext.current = {
standardOutput.toString(charset)
}
}
task second(dependsOn: 'first') {
def currentRes = file("${buildDir}/current.txt")
outputs.file currentRes
doLast {
if (!buildDir.exists()) {
buildDir.mkdirs()
}
current = tasks.first.current()
currentRes.write(current, charset)
if (current == "front") {
notCurrent = "back"
} else if (current == "back") {
notCurrent = "front"
} else notCurrent = "main"
}
}
task third(type: Exec) {
commandLine 'cmd', 'git', 'merge-base', '--fork-point', "$notCurrent"
standardOutput = new ByteArrayOutputStream()
ext.commitStart = {
standardOutput.toString(charset)
}
}
task last(dependsOn :[second,third]) {
commitStartRes = file("${buildDir}/commitStart.txt")
outputs.file commitStartRes
doLast {
if (!buildDir.exists()) {
buildDir.mkdirs()
}
commitStart = tasks.third.commitStart()
commitStartRes.write(commitStart, charset)
println "current branch : ${current}"
println "not current branch : ${notCurrent}"
println "commit start from : ${commitStart}"
}
}
And this... is working up to the task third where my output is unfortunatly not a commit id but a
Microsoft Windows [version 10.0.22000.795]
(c) Microsoft Corporation. Tous droits r�serv�s.
C:\Users\xxxxx\Documents\Projects\xxx\back>
Well i'm on progress i guess...

Error while running Fortify on Gradle 7.2 project

I am getting an error while running Fortify 20 on a Gradle-Java Project. The project compiles smoothly with "gradle build" command, but when running Fortify I get this error:
Must not use executable property on ForkOptions together with javaCompiler property
The only clue I have is that this functionality was introduced since version 6.7 but the project was built on gradle 7.
I wonder if it is possible to inhibit one of the 2 things causing the error?
Looks like it might be related to Gradle.
https://github.com/gradle/gradle/blob/master/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/JavaCompile.java
If you look at the github code, you will see this method:
private void validateConfiguration() {
if (javaCompiler.isPresent()) {
checkState(getOptions().getForkOptions().getJavaHome() == null, "Must not use `javaHome` property on `ForkOptions` together with `javaCompiler` property");
checkState(getOptions().getForkOptions().getExecutable() == null, "Must not use `executable` property on `ForkOptions` together with `javaCompiler` property");
}
}
validateConfiguration() is called from createSpec() which is run during compile().
Please see example build.gradle below which uses java plugin and compileJava task, and options.forkOptions.executable:
https://docs.gradle.org/current/userguide/java_plugin.html#java_plugin
import com.nr.builder.JarUtil
apply plugin: 'java'
subprojects {
dependencies {
// introspector classes for testing externals
testImplementation(project(":instrumentation-test"))
}
}
ext.moduleName = "com.greetings"
dependencies {
implementation("junit:junit:4.13")
}
compileJava {
inputs.property("moduleName", "com.greetings")
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--patch-module', "$moduleName=" + files(sourceSets.main.java.srcDirs).asPath,
]
classpath = files()
}
}
compileJava.options.encoding = 'UTF-8'
compileJava.options.fork = true
// Compile with Java 11 to test module support
compileJava.options.forkOptions.executable = jdk11 + '/bin/javac'
compileJava.options.forkOptions.javaHome = new File(jdk11)
compileTestJava.options.encoding = 'UTF-8'
compileTestJava.options.fork = true
// Compile with Java 11 to test module support
compileTestJava.options.forkOptions.executable = jdk11 + '/bin/javac'
compileTestJava.options.forkOptions.javaHome = new File(jdk11)
// Boot classpath no longer works in JDK 9+ so we should ignore it here
compileJava.options.bootstrapClasspath = null
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
def module_test_args = [
"-javaagent:${project.jar.archivePath.absolutePath}",
"-javaagent:${JarUtil.getNewRelicJar(project(":newrelic-agent")).absolutePath}",
"-Dnewrelic.config.file=${project(':newrelic-agent').projectDir}/src/test/resources/com/newrelic/agent/config/newrelic.yml",
"-Dnewrelic.unittest=true",
"-Dnewrelic.config.startup_log_level=warn",
"-Dnewrelic.debug=$newrelicDebug",
"--module-path=lib:out/production/classes",
"--add-modules com.greetings",
"--module junit/org.junit.runner.JUnitCore"
]
test {
dependsOn(project(":newrelic-agent").getTasksByName("newrelicJar", false))
forkEvery = 1
maxParallelForks = Runtime.runtime.availableProcessors()
executable = jdk11 + '/bin/java'
minHeapSize = "256m"
maxHeapSize = "256m"
beforeSuite {
descriptor ->
// We get two notifications per Test class. One of them is simply the Gradle executor used to run the test
// We filter that one out and only log the Test class name with this null check.
if (descriptor.getClassName() != null) {
logger.lifecycle("Running test suite: " + descriptor.getClassName())
}
}
}
javadoc {
onlyIf { JavaVersion.current().isJava11Compatible() }
}
If you want to keep using the Gradle toolchain feature, add the following to your build.gradle:
// Circumvents issues with Fortify scan without disabling Gradle toolchain feature
tasks.withType(JavaCompile).configureEach {
doFirst {
configure(options) {
configure(forkOptions) {
executable = null
javaHome = null
}
}
}
}

How to pass -np argument to MPJ in gradle?

I was trying to do something with MPJ Express(My home work)
and i couldn't find how to pass -np argument to MPJRun.
group 'ST1'
version '1.0-SNAPSHOT'
apply plugin: 'application'
mainClassName = 'example.Main'
sourceCompatibility = 1.8
def mpjHome = System.getenv( 'MPJ_HOME')
def mpjStarter = files("$mpjHome/lib/starter.jar")
def mpjJar = files("$mpjHome/lib/mpj.jar ")
def mpjClasspath = sourceSets.main.runtimeClasspath - mpjJar
dependencies {
compile mpjJar
}
run{
main = 'runtime.starter.MPJRun'
classpath = mpjStarter
args '-np 2' ,mainClassName, '-cp' , mpjClasspath.asPath
dependsOn classes
}
Your args line should looks like:
args '-np', 2 ,mainClassName, '-cp' , mpjClasspath.asPath
movie which shows config in gradle: https://www.youtube.com/watch?v=gj-3Td6ZOyc&t=942s

Eclipse Gradle adding a classpath entry

I'm adding a classpath entry to the .classpath file in Eclipse to avoid having to add it manually each time I run the .eclipse task while I add a number of dependencies. I need some resources on the path to run locally.
this works,
eclipse.classpath.file {
withXml {
def node = it.asNode()
node.appendNode('classpathentry',
[kind: 'lib', path: '/some/path'])
}
}
this doesn't,
eclipse.classpath.file {
whenMerged { classpath ->
classpath.entries.add { entry -> kind: 'lib', path: '/some/path' }
}
}
The error I get is,
startup failed: build.gradle': 75: unexpected token: lib # line 75, column 48.
.entries.add { entry -> kind: 'lib', pat
^
For future reference, what is wrong with the second example?
The equivalent should be something like:
eclipse.classpath.file {
whenMerged { classpath ->
def lib = new org.gradle.plugins.ide.eclipse.model.Library(fileReference(file('path/to/my/jar')))
lib.exported = true
classpath.entries << lib
}
}
See Gradle docs for Library and its interface ClasspathEntry.

Android new build system (gradle) and aspectj

In Google IO the new build system gradle is announced to replace ant.
My project is using aspectj and I would like to use it in my project.
I couldn't figure out some variables to get it working. I don't find android.* output classpath there. Anyone can help?
Here is my current build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4'
}
}
apply plugin: 'android'
sourceCompatibility = 1.6
configurations {
ajc
}
dependencies {
compile fileTree(dir: 'libs', includes: ['*.jar'])
ajc files('build-tools/aspectjtools.jar', 'libs/aspectjrt.jar')
}
android {
compileSdkVersion 16
buildToolsVersion "17"
defaultConfig {
minSdkVersion 8
targetSdkVersion 16
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('test')
}
}
gradle.projectsEvaluated {
compileJava.doLast {
tasks.compileAspectJ.execute()
}
println 'lalalalala'
}
task compileAspectJ {
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties",
classpath: configurations.ajc.asPath)
ant.iajc(source: sourceCompatibility, target: sourceCompatibility,
destDir: "?????????????????????",
classpath: "????????????????????????????") {
sourceroots{
android.sourceSets.main.java.srcDirs.each {
pathelement(location: it.absolutePath)
}
}
}
}
This is the old ant code that works very well:
http://code.google.com/p/anymemo/source/browse/custom_rules.xml
Edit:
Updated the build.gradle according to the first answer.However I the iajc does not seem to recognize all the libraries and complain the classes in the libraries not found
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android'
sourceCompatibility = 1.6
targetCompatibility = 1.6
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.0"
defaultConfig {
minSdkVersion 9
targetSdkVersion 16
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
configurations {
ajc
aspects
ajInpath
}
ext.aspectjVersion = '1.7.3'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
ajc "org.aspectj:aspectjtools:${aspectjVersion}"
compile "org.aspectj:aspectjrt:${aspectjVersion}"
compile 'com.android.support:appcompat-v7:18.0.0'
}
android.applicationVariants.all { variant ->
variant.javaCompile.doLast {
def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
println 'AAAAAAAAAAAAAAAAA: ' + androidSdk
def iajcClasspath = configurations.compile.asPath + ":" + androidSdk
configurations.compile.dependencies.each { dep ->
if(dep.hasProperty("dependencyProject")) {
iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
}
}
println 'BBBBBBBBBBBBBB : ' + iajcClasspath
ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
ant.iajc (
source:sourceCompatibility,
target:targetCompatibility,
destDir:"${project.buildDir}/classes/${variant.dirName}",
maxmem:"512m",
fork:"true",
aspectPath:configurations.aspects.asPath,
inpath:configurations.ajInpath.asPath,
sourceRootCopyFilter:"**/.svn/*,**/*.java",
classpath:iajcClasspath
){
sourceroots{
android.sourceSets.main.java.srcDirs.each{
pathelement(location:it.absolutePath)
}
pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
}
}
}
}
Errors:
1 [error] The method onPrepareOptionsMenu(Menu) of type FingerPaint must override or impl[3780/18642]
rtype method
[ant:iajc] public boolean onPrepareOptionsMenu(Menu menu) {
[ant:iajc] ^^^^^^^^^^^^^^^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:21
2 [error] The method onPrepareOptionsMenu(Menu) is undefined for the type GraphicsActivity
[ant:iajc] super.onPrepareOptionsMenu(menu);
[ant:iajc] ^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:21
7 [error] The method onOptionsItemSelected(MenuItem) of type FingerPaint must override or implement a
supertype method
[ant:iajc] public boolean onOptionsItemSelected(MenuItem item) {
[ant:iajc] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:22
8 [error] The constructor ColorPickerDialog(FingerPaint, FingerPaint, int) is undefined
[ant:iajc] new ColorPickerDialog(this, this, mPaint.getColor()).show();
[ant:iajc] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:25
4 [error] The method onOptionsItemSelected(MenuItem) is undefined for the type GraphicsActivity
[ant:iajc] return super.onOptionsItemSelected(item);
[ant:iajc] ^^^^^^^^^^^^
[ant:iajc] /home/liberty/mp/android/AnyMemo/src/com/example/android/apis/graphics/FingerPaint.java:25
8 [error] The method getDefaultSharedPreferences(Context) in the type PreferenceManager is not applic
able for the arguments (FingerPaint)
[ant:iajc] SharedPreferences shre = PreferenceManager.getDefaultSharedPreferences(this);
[ant:iajc]
EDIT:
This the final build.gradle file that works for my project:
https://code.google.com/p/anymemo/source/browse/build.gradle?spec=svnf85aaa4b2d78c62876d0e1f6c3e28252bf03f820&r=f85aaa4b2d78c62876d0e1f6c3e28252bf03f820
I also wanted to use aspectj with gradle and Android Studio, and I finally got it working, but I still have some hand-written paths that I'd like to replace with more generic gradle options.
Edit: I replaced every hard-coded absolute paths with gradle based alternatives, so this solution does not depend any more on a given platform or user name. However, it still uses relative paths that could change from an IDE to an other or in further releases of Android Studio.
Also, I'm not really satisfied with the way I find the android.jar.
I first load aspectj:
configurations {
ajc
aspects
ajInpath
}
ext.aspectjVersion = '1.7.3'
dependencies {
compile project(":LibTest")
ajc "org.aspectj:aspectjtools:${aspectjVersion}"
compile "org.aspectj:aspectjrt:${aspectjVersion}"
compile 'com.android.support:appcompat-v7:18.0.0'
}
And I then add a task that will run after the JavaCompile task of the current variant:
android.applicationVariants.all { variant ->
variant.javaCompile.doLast {
def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
def iajcClasspath = configurations.compile.asPath + ";" + androidSdk
configurations.compile.dependencies.each { dep ->
if(dep.hasProperty("dependencyProject")) {
iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
}
}
ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
ant.iajc (
source:sourceCompatibility,
target:targetCompatibility,
destDir:"${project.buildDir}/classes/${variant.dirName}",
maxmem:"512m",
fork:"true",
aspectPath:configurations.aspects.asPath,
inpath:configurations.ajInpath.asPath,
sourceRootCopyFilter:"**/.svn/*,**/*.java",
classpath:iajcClasspath
){
sourceroots{
android.sourceSets.main.java.srcDirs.each{
pathelement(location:it.absolutePath)
}
pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
}
}
}
}
Wherever I use ${variant.dirName}, it will be replaced by either "debug" or "release" according to the current build configuration.
Adding android.jar to the classpath is required to compile Android specific classes, and the line pathelement(location:"${project.buildDir}/source/r/${variant.dirName}") is require to use classes from the auto-generated R.java file.
Edit: The iterations over the project dependencies to build iajcClasspath let you use classes from your libraries projects. configurations.compile.asPath already contains a reference to your apklib (aar file), which is actually a zip containing both the jar and the resources of the library. Iajc doesn't recognize these files as it, but there is a bundle directory containing the classes.jar for your library under the build directory. I use a relative path with "release" hard-coded in it, because the library has a different variant than the main project in my situation, so I can't use ${variant.dirName} here.
Here is the complete build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.0"
defaultConfig {
minSdkVersion 7
targetSdkVersion 18
}
}
configurations {
ajc
aspects
ajInpath
}
ext.aspectjVersion = '1.7.3'
dependencies {
compile project(":LibTest")
ajc "org.aspectj:aspectjtools:${aspectjVersion}"
compile "org.aspectj:aspectjrt:${aspectjVersion}"
compile 'com.android.support:appcompat-v7:18.0.0'
}
android.applicationVariants.all { variant ->
variant.javaCompile.doLast {
def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
def iajcClasspath = configurations.compile.asPath + ";" + androidSdk
configurations.compile.dependencies.each { dep ->
if(dep.hasProperty("dependencyProject")) {
iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
}
}
ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
ant.iajc (
source:sourceCompatibility,
target:targetCompatibility,
destDir:"${project.buildDir}/classes/${variant.dirName}",
maxmem:"512m",
fork:"true",
aspectPath:configurations.aspects.asPath,
inpath:configurations.ajInpath.asPath,
sourceRootCopyFilter:"**/.svn/*,**/*.java",
classpath:iajcClasspath
){
sourceroots{
android.sourceSets.main.java.srcDirs.each{
pathelement(location:it.absolutePath)
}
pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
}
}
}
}
I figured out that the AAR can not be used as a jar library in my code. If you are using dependencies like this
compile 'com.android.support:appcompat-v7:18.0.0'
You need to find the jar file and add to the classpath. The following code will do it.
tree = fileTree(dir: "${project.buildDir}/exploded-bundles", include: '**/classes.jar')
tree.each { jarFile ->
iajcClasspath += ":" + jarFile
}
So the whole section would be:
variant.javaCompile.doLast {
// Find the android.jar and add to iajc classpath
def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
println 'Android SDK android.jar path: ' + androidSdk
def iajcClasspath = androidSdk + ":" + configurations.compile.asPath
configurations.compile.dependencies.each { dep ->
if(dep.hasProperty("dependencyProject")) {
iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/release/classes.jar"
}
}
// handle aar dependencies pulled in by gradle (Android support library and etc)
tree = fileTree(dir: "${project.buildDir}/exploded-bundles", include: '**/classes.jar')
tree.each { jarFile ->
iajcClasspath += ":" + jarFile
}
println 'Classpath for iajc: ' + iajcClasspath
ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
For the full example please see the build.gradle for AnyMemo project here:
https://code.google.com/p/anymemo/source/browse/build.gradle?spec=svnf85aaa4b2d78c62876d0e1f6c3e28252bf03f820&r=f85aaa4b2d78c62876d0e1f6c3e28252bf03f820
Although previous answers scripts works for most of the situations, they doesn't cover some of the problems of using Android with AspectJ and Gradle.
My test was to create a library project that should be used by anyone via mavenCentral or by me as a reference library project, and a test application project. The library project is the one that has all the aspects and the application test was trying to use those aspects.
Giving this as a context, the resulting project structure was:
HEAD-Gradle
---LibraryProject
-------SomeAspects
---TestApplication
-------Uses-SomeAspects
The solutions I found that make it work are:
1- For library projects you must use
libraryVariants.all { variant ->
instead of
android.applicationVariants.all { variant ->
2- The build dir changed for 19.+ build tools of Android, so as it is suggested in one comment (thanks to "WithoutClass"), you have to use the exploded-aar dir instead of exploded-bundles dir in the tree variable definition.
From:
def tree = fileTree(dir: "${project.buildDir}/exploded-bundles", include: '**/classes.jar')
To:
def tree = fileTree(dir: "${project.buildDir}/exploded-aar", include: '**/classes.jar')
3- The final problem I faced when making the integration was that if you have a library project, aspects defined on it were not found on the child project. To solve this you have to add the classes.jar of your custom library to the aspectJ compiler configuration. You can achieve this by adding to the dependencies:
aspects project(":YourLibraryProject")
and it is also needed to make some changes in the script provided in the final of this post.
Right now the best script I can imagine that gives full support for aspectj using even library projects is:
For dependencies:
configurations {
ajc
aspects
ajInpath
}
//Version of aspectj
def aspectjVersion = '1.8.+'
// The dependencies for this project
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//Your dependencies to a custom library project
compile project(":YourLibraryProject")
aspects project(":YourLibraryProject")
//Aspectj dependencies
ajc "org.aspectj:aspectjtools:${aspectjVersion}"
compile "org.aspectj:aspectjrt:${aspectjVersion}"
}
The compiler running script
android.applicationVariants.all { variant ->
variant.javaCompile.doLast {
// Find the android.jar and add to iajc classpath
def androidSdk = android.adbExe.parent + "/../platforms/" + android.compileSdkVersion + "/android.jar"
def iajcClasspath = androidSdk + ":" + configurations.compile.asPath
//This line and the fordward assignations allow the aspects support in the child project from the library project
def customAspectsPath = configurations.aspects.asPath
configurations.compile.dependencies.each { dep ->
if(dep.hasProperty("dependencyProject")) {
iajcClasspath += ":" + dep.dependencyProject.buildDir + "/bundles/${variant.buildType.name}/classes.jar"
customAspectsPath += ":" + dep.dependencyProject.buildDir + "/bundles/${variant.buildType.name}/classes.jar"
}
}
// handle aar dependencies pulled in by gradle (Android support library and etc)
def tree = fileTree(dir: "${project.buildDir}/exploded-aar", include: '**/classes.jar')
tree.each { jarFile ->
iajcClasspath += ":" + jarFile
}
ant.taskdef( resource:"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: configurations.ajc.asPath)
ant.iajc (
source:sourceCompatibility,
target:targetCompatibility,
destDir:"${project.buildDir}/classes/${variant.dirName}",
maxmem:"512m",
fork:"true",
aspectPath:customAspectsPath,
inpath:configurations.ajInpath.asPath,
sourceRootCopyFilter:"**/.svn/*,**/*.java",
classpath:iajcClasspath
){
sourceroots{
android.sourceSets.main.java.srcDirs.each{
pathelement(location:it.absolutePath)
}
pathelement(location:"${project.buildDir}/source/r/${variant.dirName}")
}
}
}
}
Remember that if you want to run AspectJ on a library-child project, you must have also this script on the build.gradle of the library.
In the case of using Android Studio 0.8 or above, it seems that using gradle 0.12.+ is necessary.
In gradle 0.12.+, exploded aar are extracted in the build folder, not in the exploded-aar folder.
Therefore, in order to handle aar dependencies, you must use this code:
tree = fileTree(dir: "${project.buildDir}", include: '**/classes.jar')
tree.each { jarFile ->
iajcClasspath += ":" + jarFile
}
Another easier way to set things up is using the android aspectj plugin which is better maintained.
https://github.com/uPhyca/gradle-android-aspectj-plugin

Categories

Resources