summaryrefslogtreecommitdiff
path: root/compiler/src/main/java
diff options
context:
space:
mode:
authorGeorge Mount <mount@google.com>2016-09-28 19:21:41 +0000
committerGeorge Mount <mount@google.com>2016-09-28 12:48:34 -0700
commite468b817509c5c7dd657a0cbc997452e1106aed8 (patch)
treeaa194fa6a5d607d7eda7d4e11dfc2578a7eec05b /compiler/src/main/java
parent83bcfb874866a2f6f74f7700fe2c67f0af2a3c20 (diff)
downloaddata-binding-e468b817509c5c7dd657a0cbc997452e1106aed8.tar.gz
Re-adds "Add support for dependent bindable properties."
This reverts commit 729298e98a96730a9fbcf8c1d2575a8f0da7cc70. This also fixes the build break caused by the added abstract methods in ModelMethod and ModelField. Change-Id: I4d7d5085a1a2e02ede0662591d8ccd79770c5fb3
Diffstat (limited to 'compiler/src/main/java')
-rw-r--r--compiler/src/main/java/android/databinding/tool/Binding.java2
-rw-r--r--compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java69
-rw-r--r--compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java2
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/Callable.java7
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/InjectedField.java2
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java2
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java13
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/ModelField.java9
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/ModelMethod.java7
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationField.java5
-rw-r--r--compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java5
11 files changed, 117 insertions, 6 deletions
diff --git a/compiler/src/main/java/android/databinding/tool/Binding.java b/compiler/src/main/java/android/databinding/tool/Binding.java
index 2395f23a..5f193a3e 100644
--- a/compiler/src/main/java/android/databinding/tool/Binding.java
+++ b/compiler/src/main/java/android/databinding/tool/Binding.java
@@ -156,7 +156,7 @@ public class Binding implements LocationScopeProvider {
// Now try with the value object directly
mSetterCall = SetterStore.get(modelAnalyzer).getSetterCall(mName,
viewType, mExpr.getResolvedType(), mExpr.getModel().getImports());
- if (warn) {
+ if (warn && mSetterCall != null) {
L.w(ErrorMessages.OBSERVABLE_FIELD_USE, mSetterCall.getDescription());
}
}
diff --git a/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java b/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java
index be48cd4a..d4a54de0 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java
@@ -16,6 +16,7 @@
package android.databinding.tool.expr;
+import android.databinding.Bindable;
import android.databinding.tool.Binding;
import android.databinding.tool.BindingTarget;
import android.databinding.tool.InverseBinding;
@@ -26,16 +27,20 @@ import android.databinding.tool.reflection.Callable;
import android.databinding.tool.reflection.Callable.Type;
import android.databinding.tool.reflection.ModelAnalyzer;
import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.reflection.ModelField;
import android.databinding.tool.store.SetterStore;
import android.databinding.tool.store.SetterStore.BindingGetterCall;
import android.databinding.tool.util.BrNameUtil;
import android.databinding.tool.util.L;
import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.util.StringUtils;
import android.databinding.tool.writer.KCode;
import com.google.common.collect.Lists;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
public class FieldAccessExpr extends MethodBaseExpr {
// notification name for the field. Important when we map this to a method w/ different name
@@ -157,6 +162,70 @@ public class FieldAccessExpr extends MethodBaseExpr {
}
}
+ /**
+ * @return The list of all properties that dirty this expression. This will also contain the
+ * the BR identifier for this property if there is one. If the property is not bindable,
+ * it will contain an empty list.
+ */
+ public String[] getDirtyingProperties() {
+ String[] names = null;
+ if (mGetter != null && mGetter.canBeInvalidated()) {
+ if (mGetter.type == Type.FIELD) {
+ if (mGetter.bindableAnnotation != null &&
+ mGetter.bindableAnnotation.value().length != 0) {
+ L.e("Bindable annotation with property names is only supported on methods. " +
+ "Field '%s.%s' has @Bindable(\"%s\")",
+ getTarget().getResolvedType().toJavaCode(), mGetter.name,
+ StringUtils.join(mGetter.bindableAnnotation.value(), "\", \""));
+ }
+ } else if (mGetter.method != null && mGetter.canBeInvalidated() &&
+ mGetter.bindableAnnotation != null) {
+ String[] dependencies = mGetter.bindableAnnotation.value();
+ validateDependencies(dependencies);
+ names = new String[dependencies.length + 1];
+ for (int i = 0; i < dependencies.length; i++) {
+ names[i] = "BR." + dependencies[i];
+ }
+ names[dependencies.length] = getBrName();
+ }
+ }
+ if (names == null) {
+ String br = getBrName();
+ if (br == null) {
+ names = new String[0];
+ } else {
+ names = new String[] { br };
+ }
+ }
+ return names;
+ }
+
+ /**
+ * Validates the dependent properties -- they must exist and be Bindable.
+ */
+ private void validateDependencies(String[] dependencies) {
+ try {
+ Scope.enter(this);
+ Arrays.stream(dependencies).forEach(field -> {
+ ModelClass resolvedType = getTarget().getResolvedType();
+ Callable getter = resolvedType.findGetterOrField(field, mGetter.isStatic());
+ if (getter == null) {
+ L.e("Could not find dependent property '%s' referenced in " +
+ "@Bindable annotation on %s.%s", field,
+ mGetter.method.getDeclaringClass().toJavaCode(),
+ mGetter.method.getName());
+ } else if (!getter.canBeInvalidated()) {
+ L.e("The dependent property '%s' referenced in @Bindable annotation on " +
+ "%s.%s must be annotated with @Bindable", field,
+ mGetter.method.getDeclaringClass().toJavaCode(),
+ mGetter.method.getName());
+ }
+ });
+ } finally {
+ Scope.exit();
+ }
+ }
+
@Override
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
if (mIsListener) {
diff --git a/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java b/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java
index dfeec181..dea19925 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java
@@ -186,7 +186,7 @@ public class MethodCallExpr extends Expr {
flags |= STATIC;
}
mGetter = new Callable(Type.METHOD, mMethod.getName(), null, mMethod.getReturnType(args),
- mMethod.getParameterTypes().length, flags, mMethod);
+ mMethod.getParameterTypes().length, flags, mMethod, null);
}
return mGetter.resolvedType;
}
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/Callable.java b/compiler/src/main/java/android/databinding/tool/reflection/Callable.java
index 5088523d..54db94e3 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/Callable.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/Callable.java
@@ -15,6 +15,8 @@
*/
package android.databinding.tool.reflection;
+import android.databinding.Bindable;
+
import org.jetbrains.annotations.Nullable;
public class Callable {
@@ -42,8 +44,10 @@ public class Callable {
private final int mParameterCount;
+ public final Bindable bindableAnnotation;
+
public Callable(Type type, String name, String setterName, ModelClass resolvedType,
- int parameterCount, int flags, ModelMethod method) {
+ int parameterCount, int flags, ModelMethod method, Bindable bindable) {
this.type = type;
this.name = name;
this.resolvedType = resolvedType;
@@ -51,6 +55,7 @@ public class Callable {
this.setterName = setterName;
mFlags = flags;
this.method = method;
+ this.bindableAnnotation = bindable;
}
public String getTypeCodeName() {
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/InjectedField.java b/compiler/src/main/java/android/databinding/tool/reflection/InjectedField.java
index 85719f1c..82db70b1 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/InjectedField.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/InjectedField.java
@@ -16,6 +16,8 @@
package android.databinding.tool.reflection;
+import android.databinding.Bindable;
+
import java.util.Map;
/**
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java b/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java
index f47442b7..a91ae109 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/InjectedMethod.java
@@ -16,6 +16,8 @@
package android.databinding.tool.reflection;
+import android.databinding.Bindable;
+
import java.util.List;
import java.util.Map;
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 813b72e1..d408405e 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
@@ -15,6 +15,7 @@
*/
package android.databinding.tool.reflection;
+import android.databinding.Bindable;
import android.databinding.tool.reflection.Callable.Type;
import android.databinding.tool.util.L;
import android.databinding.tool.util.StringUtils;
@@ -417,7 +418,7 @@ public abstract class ModelClass {
public Callable findGetterOrField(String name, boolean staticOnly) {
if ("length".equals(name) && isArray()) {
return new Callable(Type.FIELD, name, null,
- ModelAnalyzer.getInstance().loadPrimitive("int"), 0, 0, null);
+ ModelAnalyzer.getInstance().loadPrimitive("int"), 0, 0, null, null);
}
String capitalized = StringUtils.capitalize(name);
String[] methodNames = {
@@ -435,8 +436,10 @@ public abstract class ModelClass {
if (method.isStatic()) {
flags |= STATIC;
}
+ final Bindable bindable;
if (method.isBindable()) {
flags |= CAN_BE_INVALIDATED;
+ bindable = method.getBindableAnnotation();
} else {
// if method is not bindable, look for a backing field
final ModelField backingField = getField(name, true, method.isStatic());
@@ -444,13 +447,16 @@ public abstract class ModelClass {
backingField == null ? "NOT FOUND" : backingField.getName());
if (backingField != null && backingField.isBindable()) {
flags |= CAN_BE_INVALIDATED;
+ bindable = backingField.getBindableAnnotation();
+ } else {
+ bindable = null;
}
}
final ModelMethod setterMethod = findSetter(method, name);
final String setterName = setterMethod == null ? null : setterMethod.getName();
final Callable result = new Callable(Callable.Type.METHOD, methodName,
setterName, method.getReturnType(null), method.getParameterTypes().length,
- flags, method);
+ flags, method, bindable);
return result;
}
}
@@ -484,7 +490,8 @@ public abstract class ModelClass {
if (publicField.isBindable()) {
flags |= CAN_BE_INVALIDATED;
}
- return new Callable(Callable.Type.FIELD, name, setterFieldName, fieldType, 0, flags, null);
+ return new Callable(Callable.Type.FIELD, name, setterFieldName, fieldType, 0, flags, null,
+ publicField.getBindableAnnotation());
}
public ModelMethod findInstanceGetter(String name) {
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ModelField.java b/compiler/src/main/java/android/databinding/tool/reflection/ModelField.java
index 0cde85b0..2baef1e8 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/ModelField.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelField.java
@@ -15,6 +15,8 @@
*/
package android.databinding.tool.reflection;
+import android.databinding.Bindable;
+
public abstract class ModelField {
/**
@@ -46,4 +48,11 @@ public abstract class ModelField {
* @return The declared type of the field variable.
*/
public abstract ModelClass getFieldType();
+
+ /**
+ * @return the Bindable annotation on the field or null if there isn't one.
+ */
+ public Bindable getBindableAnnotation() {
+ return null;
+ }
}
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ModelMethod.java b/compiler/src/main/java/android/databinding/tool/reflection/ModelMethod.java
index 01500706..5605245a 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/ModelMethod.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelMethod.java
@@ -44,6 +44,13 @@ public abstract class ModelMethod {
public abstract boolean isBindable();
/**
+ * @return the Bindable annotation on the method or null if it doesn't exist.
+ */
+ public Bindable getBindableAnnotation() {
+ return null;
+ }
+
+ /**
* Since when this method is available. Important for Binding expressions so that we don't
* call non-existing APIs when setting UI.
*
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationField.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationField.java
index 9373c6c9..be860570 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationField.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationField.java
@@ -70,6 +70,11 @@ class AnnotationField extends ModelField {
}
@Override
+ public Bindable getBindableAnnotation() {
+ return mField.getAnnotation(Bindable.class);
+ }
+
+ @Override
public boolean equals(Object obj) {
if (obj instanceof AnnotationField) {
AnnotationField that = (AnnotationField) obj;
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java
index 66c1dbc5..839aa282 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java
@@ -147,6 +147,11 @@ class AnnotationMethod extends ModelMethod {
}
@Override
+ public Bindable getBindableAnnotation() {
+ return mExecutableElement.getAnnotation(Bindable.class);
+ }
+
+ @Override
public int getMinApi() {
if (mApiLevel == -1) {
mApiLevel = SdkUtil.getMinApi(this);