Skip to content

Commit

Permalink
Added Annotation Processing
Browse files Browse the repository at this point in the history
Annotation is now supported by default. Can
use android gradle plugin's `annotationProcessor` configurations.

Fixes: groovy#142
  • Loading branch information
AndrewReitz committed Jun 1, 2017
1 parent 1cc1679 commit cc33059
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ android:
components:
- tools
- platform-tools
- build-tools-25.0.2
- build-tools-25.0.3
- android-25
- extra-google-m2repository
- extra-android-m2repository
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
1.2.0
-----
* Added support for annotation processing (#142)
* Disabled groovy task for when there are no groovy sources
* Dropped support for Android Gradle Plugin Versions < 1.5.0
1.1.0
-----
* Support for 2.2.0 of Android Gradle Plugin
Expand Down
30 changes: 3 additions & 27 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:groovyVersion: 2.4.11
:pluginVersion: 1.1.0
:pluginSnapshotVersion: 1.2.0
:pluginVersion: 1.2.0
:pluginSnapshotVersion: 1.3.0
:androidPluginVersion: 2.2.3

= Groovy language support for Android
Expand Down Expand Up @@ -194,31 +194,7 @@ androidGroovy {

== Annotation Processing

To use annotation processing `javaAnnotationProcessing` must be set to true in `groovyOptions`

[source, groovy]
----
androidGroovy {
options {
configure(groovyOptions) {
javaAnnotationProcessing = true
}
}
}
----

For more examples of annotation processing setup see
https://github.com/pieces029/is-taylor-swift-single-groovy-android[Example Dagger Application]
and https://github.com/pieces029/groovy-android-data-binding[Example Databinding Application]

== Data Binding

Databinding is actually annotation processing but hidden behind Android Studio
and a Gradle plugin. Because of this you will need to use the https://bitbucket.org/hvisser/android-apt[android-apt]
in order to see any of the generated output files.

The setup for Databinding and <<Annotation Processing>> are the same, refer to the
previous section in order to enable <<Annotation Processing>>.
As of 1.2.0 Release annotation processing is configured by default.

== Android `packagingOptions`

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'org.codehaus.groovy:groovy-android-gradle-plugin:1.1.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:3.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class GroovyAndroidPlugin implements Plugin<Project> {
// Exclude any java files that may be included in both java and groovy source sets
javaTask.exclude { file ->
project.logger.debug("Exclude java file $file.file")
project.logger.debug("Eexlude against groovy files $groovySourceSet.groovy.files")
project.logger.debug("Exelude against groovy files $groovySourceSet.groovy.files")
file.file in groovySourceSet.groovy.files
}

Expand All @@ -156,6 +156,11 @@ class GroovyAndroidPlugin implements Plugin<Project> {
def androidRunTime = project.files(getRuntimeJars(androidPlugin, androidExtension))
task.classpath = androidRunTime + javaTask.classpath
task.groovyClasspath = task.classpath

project.logger.debug("Java compilerArgs $javaTask.options.compilerArgs")
groovyTask.options.compilerArgs += javaTask.options.compilerArgs
project.logger.debug("Groovy CompilerArgs $groovyTask.options.compilerArgs")
groovyTask.groovyOptions.javaAnnotationProcessing = true
}

javaTask.finalizedBy(groovyTask)
Expand All @@ -178,7 +183,9 @@ class GroovyAndroidPlugin implements Plugin<Project> {
private static getRuntimeJars(BasePlugin plugin, BaseExtension extension) {
if (plugin.metaClass.getMetaMethod('getRuntimeJarList')) {
return plugin.runtimeJarList
} else if (extension.metaClass.getMetaMethod('getBootClasspath')) {
}

if (extension.metaClass.getMetaMethod('getBootClasspath')) {
return extension.bootClasspath
}

Expand All @@ -188,9 +195,12 @@ class GroovyAndroidPlugin implements Plugin<Project> {
private static SourceTask getJavaTask(BaseVariantData baseVariantData) {
if (baseVariantData.metaClass.getMetaProperty('javaCompileTask')) {
return baseVariantData.javaCompileTask
} else if (baseVariantData.metaClass.getMetaProperty('javaCompilerTask')) {
}

if (baseVariantData.metaClass.getMetaProperty('javaCompilerTask')) {
return baseVariantData.javaCompilerTask
}

return null
}

Expand Down Expand Up @@ -230,6 +240,10 @@ class GroovyAndroidPlugin implements Plugin<Project> {
result << variantData.scope.aidlSourceOutputDir
}

if (variantData.scope.annotationProcessorOutputDir != null) {
result << variantData.scope.annotationProcessorOutputDir
}

// We use getter instead of property for globalScope since property returns
// TransformGlobalScope instead of GlobalScope (Static type checker failing).
if (variantData.scope.getGlobalScope().extension.dataBinding.enabled) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package groovyx.functional

import static groovyx.internal.TestProperties.androidPluginVersion
import static groovyx.internal.TestProperties.buildToolsVersion
import static groovyx.internal.TestProperties.compileSdkVersion

class AnnotationProcessingSpec extends FunctionalSpec {
def "should compile android app with annotation processing"() {
given:
file("settings.gradle") << "rootProject.name = 'test-app'"

buildFile << """
buildscript {
repositories {
maven { url "${localRepo.toURI()}" }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:$androidPluginVersion'
classpath 'org.codehaus.groovy:groovy-android-gradle-plugin:$PLUGIN_VERSION'
}
}
apply plugin: 'com.android.application'
apply plugin: 'groovyx.android'
repositories {
jcenter()
}
android {
compileSdkVersion $compileSdkVersion
buildToolsVersion '$buildToolsVersion'
defaultConfig {
minSdkVersion 16
targetSdkVersion $compileSdkVersion
versionCode 1
versionName '1.0.0'
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
}
buildTypes {
debug {
applicationIdSuffix '.dev'
}
}
compileOptions {
sourceCompatibility '1.7'
targetCompatibility '1.7'
}
}
dependencies {
compile 'org.codehaus.groovy:groovy:2.4.11:grooid'
compile 'com.squareup.moshi:moshi:1.5.0'
annotationProcessor 'com.ryanharter.auto.value:auto-value-moshi:0.4.3'
provided 'com.ryanharter.auto.value:auto-value-moshi-annotations:0.4.3'
annotationProcessor 'com.google.auto.value:auto-value:1.4.1'
provided 'com.jakewharton.auto.value:auto-value-annotations:1.4'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
testCompile 'junit:junit:4.12'
}
// force unit test types to be assembled too
android.testVariants.all { variant ->
tasks.getByName('assemble').dependsOn variant.assemble
}
"""

file('src/main/AndroidManifest.xml') << """
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="groovyx.test">
<application
android:allowBackup="true"
android:label="Test App">
<activity
android:name=".MainActivity"
android:label="Test App">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
""".trim()

file('src/main/res/layout/activity_main.xml') << """
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Groovy!"
android:gravity="center"
android:textAppearance="?android:textAppearanceLarge"
/>
</FrameLayout>
""".trim()

file('src/main/groovy/groovyx/test/MainActivity.groovy') << """
package groovyx.test
import android.app.Activity
import android.os.Bundle
import groovy.transform.CompileStatic
import com.google.auto.value.AutoValue
@CompileStatic
class MainActivity extends Activity {
@Override void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
contentView = R.layout.activity_main
def dog = Animal.create 'dog', 4
println dog
def car = Automobile.create 'car', 4
println car
}
}
@AutoValue
@CompileStatic
abstract class Temp {
static Temp create(String name) {
new AutoValue_Temp(name)
}
abstract String name()
}
"""

file('src/main/groovy/groovyx/test/Automobile.java') << """
package groovyx.test;
import com.google.auto.value.AutoValue;
@AutoValue
abstract class Automobile {
static Automobile create(String name, int numberOfWheels) {
return new AutoValue_Automobile(name, numberOfWheels);
}
abstract String name();
abstract int numberOfWheels();
}
"""

file('src/main/java/groovyx/test/Animal.java') << """
package groovyx.test;
import com.google.auto.value.AutoValue;
@AutoValue
abstract class Animal {
static Animal create(String name, int numberOfLegs) {
return new AutoValue_Animal(name, numberOfLegs);
}
abstract String name();
abstract int numberOfLegs();
}
"""

file('src/test/groovy/groovyx/test/JvmTest.groovy') << """
package groovyx.test
import org.junit.Test
class JvmTest {
@Test void shouldCompile() {
assert 10 * 2 == 20
}
}
"""

file('src/androidTest/groovy/groovyx/test/AndroidTest.groovy') << """
package groovyx.test
import android.support.test.runner.AndroidJUnit4
import android.test.suitebuilder.annotation.SmallTest
import groovy.transform.CompileStatic
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4)
@SmallTest
@CompileStatic
class AndroidTest {
@Test void shouldCompile() {
assert 5 * 2 == 10
}
}
"""

when:
run 'assemble', 'test'

then:
noExceptionThrown()
file('build/outputs/apk/test-app-debug.apk').exists()
file('build/intermediates/classes/debug/groovyx/test/MainActivity.class').exists()

file('build/intermediates/classes/debug/groovyx/test/Animal.class').exists()
file('build/generated/source/apt/debug/groovyx/test/AutoValue_Animal.java').exists()
file('build/generated/source/apt/release/groovyx/test/AutoValue_Animal.java').exists()
file('build/intermediates/classes/debug/groovyx/test/AutoValue_Animal.class').exists()

file('build/intermediates/classes/debug/groovyx/test/Automobile.class').exists()
file('build/generated/source/apt/debug/groovyx/test/AutoValue_Automobile.java').exists()
file('build/generated/source/apt/release/groovyx/test/AutoValue_Automobile.java').exists()
file('build/intermediates/classes/debug/groovyx/test/AutoValue_Automobile.class').exists()

file('build/intermediates/classes/debug/groovyx/test/Temp.class').exists()
file('build/generated/source/apt/debug/groovyx/test/AutoValue_Temp.java').exists()
file('build/generated/source/apt/release/groovyx/test/AutoValue_Temp.java').exists()
file('build/intermediates/classes/debug/groovyx/test/AutoValue_Temp.class').exists()

file('build/intermediates/classes/androidTest/debug/groovyx/test/AndroidTest.class').exists()
file('build/intermediates/classes/test/debug/groovyx/test/JvmTest.class').exists()
file('build/intermediates/classes/test/release/groovyx/test/JvmTest.class').exists()
}
}
Loading

0 comments on commit cc33059

Please sign in to comment.