Support generics in conversion parameters.
Bug 23490384
Change-Id: I691da60a671d15c73cf2753ff830f9effb360e96
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java b/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
index e95ba39..aa6634b 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
@@ -143,6 +143,11 @@
public abstract boolean isTypeVar();
/**
+ * @return whether this is a wildcard type argument or not.
+ */
+ public abstract boolean isWildcard();
+
+ /**
* @return whether or not this ModelClass is java.lang.Object and not a primitive or subclass.
*/
public boolean isObject() {
@@ -477,6 +482,21 @@
return matching;
}
+ public boolean isIncomplete() {
+ if (isTypeVar() || isWildcard()) {
+ return true;
+ }
+ List<ModelClass> typeArgs = getTypeArguments();
+ if (typeArgs != null) {
+ for (ModelClass typeArg : typeArgs) {
+ if (typeArg.isIncomplete()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
protected abstract ModelField[] getDeclaredFields();
protected abstract ModelMethod[] getDeclaredMethods();
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java
index dcc708a..02e767e 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java
@@ -55,27 +55,12 @@
@Override
public String toJavaCode() {
- if (isIncomplete(mTypeMirror)) {
+ if (isIncomplete()) {
return getCanonicalName();
}
return mTypeMirror.toString();
}
- private static boolean isIncomplete(TypeMirror typeMirror) {
- final TypeKind typeKind = typeMirror.getKind();
- if (typeKind == TypeKind.DECLARED) {
- DeclaredType declaredType = (DeclaredType) typeMirror;
- for (TypeMirror typeArg : declaredType.getTypeArguments()) {
- if (isIncomplete(typeArg)) {
- return true;
- }
- }
- } else if (typeKind == TypeKind.TYPEVAR) {
- return true;
- }
- return false;
- }
-
@Override
public boolean isArray() {
return mTypeMirror.getKind() == TypeKind.ARRAY;
@@ -263,6 +248,11 @@
}
@Override
+ public boolean isWildcard() {
+ return mTypeMirror.getKind() == TypeKind.WILDCARD;
+ }
+
+ @Override
public boolean isInterface() {
return mTypeMirror.getKind() == TypeKind.DECLARED &&
((DeclaredType)mTypeMirror).asElement().getKind() == ElementKind.INTERFACE;
diff --git a/compiler/src/main/java/android/databinding/tool/store/SetterStore.java b/compiler/src/main/java/android/databinding/tool/store/SetterStore.java
index b5b579a..a31337a 100644
--- a/compiler/src/main/java/android/databinding/tool/store/SetterStore.java
+++ b/compiler/src/main/java/android/databinding/tool/store/SetterStore.java
@@ -287,13 +287,36 @@
}
private static String getQualifiedName(TypeMirror type) {
- if (type.getKind() == TypeKind.ARRAY) {
+ final TypeKind kind = type.getKind();
+ if (kind == TypeKind.ARRAY) {
return getQualifiedName(((ArrayType) type).getComponentType()) + "[]";
+ } else if (kind == TypeKind.DECLARED && isIncompleteType(type)) {
+ DeclaredType declaredType = (DeclaredType) type;
+ return declaredType.asElement().toString();
} else {
return type.toString();
}
}
+ private static boolean isIncompleteType(TypeMirror type) {
+ final TypeKind kind = type.getKind();
+ if (kind == TypeKind.TYPEVAR || kind == TypeKind.WILDCARD) {
+ return true;
+ } else if (kind == TypeKind.DECLARED) {
+ DeclaredType declaredType = (DeclaredType) type;
+ List<? extends TypeMirror> typeArgs = declaredType.getTypeArguments();
+ if (typeArgs == null) {
+ return false;
+ }
+ for (TypeMirror arg : typeArgs) {
+ if (isIncompleteType(arg)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public void addConversionMethod(ExecutableElement conversionMethod) {
L.d("STORE addConversionMethod %s", conversionMethod);
List<? extends VariableElement> parameters = conversionMethod.getParameters();
@@ -706,6 +729,10 @@
}
private boolean canUseForConversion(ModelClass from, ModelClass to) {
+ if (from.isIncomplete() || to.isIncomplete()) {
+ from = from.erasure();
+ to = to.erasure();
+ }
return from.equals(to) || ModelMethod.isBoxingConversion(from, to) ||
to.isAssignableFrom(from);
}
diff --git a/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java b/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java
index cc6891e..3136e7f 100644
--- a/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java
+++ b/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java
@@ -125,6 +125,11 @@
}
@Override
+ public boolean isWildcard() {
+ return false;
+ }
+
+ @Override
public boolean isInterface() {
return mClass.isInterface();
}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConverterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConverterTest.java
new file mode 100644
index 0000000..35a98fc
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConverterTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.ConvertersBinding;
+
+import android.test.UiThreadTest;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+public class ConverterTest extends BaseDataBinderTest<ConvertersBinding> {
+ public ConverterTest() {
+ super(ConvertersBinding.class);
+ }
+
+ @UiThreadTest
+ public void testGenericConverter() {
+ initBinder();
+ ArrayList<String> values = new ArrayList<String>();
+ LinkedList<String> linkedValues = new LinkedList<String>();
+ values.add("Hello");
+ values.add("World");
+ linkedValues.add("Holy");
+ linkedValues.add("Cow!");
+ mBinder.setList(values);
+ mBinder.setLinked(linkedValues);
+ mBinder.executePendingBindings();
+ assertEquals("Hello World", mBinder.textView1.getText().toString());
+ assertEquals("Holy Cow!", mBinder.textView2.getText().toString());
+ }
+}
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/GenericConverter.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/GenericConverter.java
new file mode 100644
index 0000000..a8aae55
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/GenericConverter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp.adapter;
+
+import android.databinding.BindingConversion;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+public class GenericConverter {
+ @BindingConversion
+ public static <T> String convertArrayList(ArrayList<T> values) {
+ return convert(values);
+ }
+
+ @BindingConversion
+ public static String convertLinkedList(LinkedList<?> values) {
+ return convert(values);
+ }
+
+ private static <T> String convert(List<T> values) {
+ if (values == null) {
+ return "";
+ }
+ StringBuilder vals = new StringBuilder();
+ for (T val : values) {
+ if (vals.length() != 0) {
+ vals.append(' ');
+ }
+ vals.append(val);
+ }
+ return vals.toString();
+ }
+}
diff --git a/integration-tests/TestApp/app/src/main/res/layout/converters.xml b/integration-tests/TestApp/app/src/main/res/layout/converters.xml
new file mode 100644
index 0000000..f133819
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/converters.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+ <data>
+ <variable name="list" type="java.util.ArrayList<String>"/>
+ <variable name="linked" type="java.util.LinkedList<String>"/>
+ </data>
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/textView1"
+ android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:text="@{list}"/>
+ <TextView
+ android:id="@+id/textView2"
+ android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:text="@{linked}"/>
+ </LinearLayout>
+</layout>
\ No newline at end of file