From fbdb3c08f0b4a2ac2af49801ceff1241efe47f42 Mon Sep 17 00:00:00 2001 From: George Mount Date: Tue, 10 Feb 2015 11:02:48 -0800 Subject: [PATCH] Prepare ClassAnalyzer to be replaced by other implementations. ClassAnalyzer uses normal reflection. We intend to move to an Annotation Processor and possibly an Android Studio plugin version of type interaction as well. This abstracts the type interaction to prepare. Change-Id: I2b95ea9074bca7e3053aeadcd3692dffe93b41d6 --- .../annotationprocessor/ProcessBindable.java | 4 + .../ProcessExpressions.java | 43 ++++ .../java/com/android/databinding/Binding.java | 10 +- .../android/databinding/BindingTarget.java | 10 +- .../databinding/ExpressionVisitor.java | 29 ++- .../android/databinding/expr/BracketExpr.java | 18 +- .../databinding/expr/ComparisonExpr.java | 7 +- .../com/android/databinding/expr/Expr.java | 18 +- .../android/databinding/expr/ExprModel.java | 19 +- .../databinding/expr/FieldAccessExpr.java | 26 +- .../android/databinding/expr/GroupExpr.java | 7 +- .../databinding/expr/IdentifierExpr.java | 7 +- .../android/databinding/expr/MathExpr.java | 13 +- .../databinding/expr/MethodCallExpr.java | 14 +- .../databinding/expr/ResourceExpr.java | 43 ++-- .../android/databinding/expr/SymbolExpr.java | 7 +- .../android/databinding/expr/TernaryExpr.java | 7 +- .../databinding/reflection/Callable.java | 58 +++++ .../{ => reflection}/ClassAnalyzer.java | 222 ++++++++--------- .../databinding/reflection/ClassClass.java | 230 ++++++++++++++++++ .../databinding/reflection/ClassField.java | 27 ++ .../databinding/reflection/ClassMethod.java | 64 +++++ .../reflection/ReflectionAnalyzer.java | 88 +++++++ .../reflection/ReflectionClass.java | 68 ++++++ .../reflection/ReflectionField.java | 20 ++ .../reflection/ReflectionMethod.java | 30 +++ .../databinding/store/SetterStore.java | 157 ++++-------- .../kotlin/com/android/databinding/ext/ext.kt | 8 +- .../kotlin/com/android/databinding/main.kt | 4 +- .../databinding/writer/LayoutBinderWriter.kt | 9 +- .../databinding/ExpressionVisitorTest.java | 16 +- .../android/databinding/LayoutBinderTest.java | 10 +- .../databinding/expr/ExprModelTest.java | 6 +- .../android/databinding/expr/ExprTest.java | 8 +- .../gradlePlugin/src/main/kotlin/plugin.kt | 5 +- 35 files changed, 938 insertions(+), 374 deletions(-) create mode 100644 tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/Callable.java rename tools/data-binding/compiler/src/main/java/com/android/databinding/{ => reflection}/ClassAnalyzer.java (71%) create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassClass.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassField.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassMethod.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionAnalyzer.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionClass.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionField.java create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionMethod.java diff --git a/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java b/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java index 3b5e3150380a0..cc89e35d4b9e3 100644 --- a/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java +++ b/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java @@ -15,6 +15,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -23,11 +24,14 @@ import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.JavaFileObject; diff --git a/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java b/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java new file mode 100644 index 0000000000000..a1ae692c637b3 --- /dev/null +++ b/tools/data-binding/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java @@ -0,0 +1,43 @@ +package com.android.databinding.annotationprocessor; + +import android.binding.Bindable; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.io.Writer; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; + +public class ProcessExpressions { + + public static boolean process(ProcessingEnvironment processingEnv, + Set annotations, RoundEnvironment roundEnv) { + return true; + } +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/Binding.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/Binding.java index 82e440c122046..d1740cce8bf5e 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/Binding.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/Binding.java @@ -16,6 +16,8 @@ package com.android.databinding; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import com.android.databinding.store.SetterStore; import com.android.databinding.expr.Expr; @@ -37,15 +39,15 @@ public class Binding { } public String toJavaCode(String targetViewName, String expressionCode) { - Class viewType = mTarget.getResolvedType(); - return SetterStore.get(ClassAnalyzer.getInstance()).getSetterCall(mName, viewType, + ReflectionClass viewType = mTarget.getResolvedType(); + return SetterStore.get(ReflectionAnalyzer.getInstance()).getSetterCall(mName, viewType, mExpr.getResolvedType(), targetViewName, expressionCode); } -// private String resolveJavaCode(ClassAnalyzer classAnalyzer) { +// private String resolveJavaCode(ReflectionAnalyzer reflectionAnalyzer) { // // } -//// return classAnalyzer.findMethod(mTarget.getResolvedType(), mName, +//// return reflectionAnalyzer.findMethod(mTarget.getResolvedType(), mName, //// Arrays.asList(mExpr.getResolvedType())); // //} // diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java index ab0b34c29ec92..58b8de5f1d860 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java @@ -18,8 +18,8 @@ package com.android.databinding; import com.android.databinding.expr.Expr; import com.android.databinding.expr.ExprModel; - -import org.w3c.dom.Node; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.ArrayList; import java.util.List; @@ -29,7 +29,7 @@ public class BindingTarget { String mViewClass; List mBindings = new ArrayList<>(); ExprModel mModel; - Class mResolvedClass; + ReflectionClass mResolvedClass; String mIncludedLayout; // if this target presents itself in multiple layout files with different view types, // it receives an interface type and should use it in the getter instead. @@ -68,9 +68,9 @@ public class BindingTarget { return mViewClass; } - public Class getResolvedType() { + public ReflectionClass getResolvedType() { if (mResolvedClass == null) { - mResolvedClass = ClassAnalyzer.getInstance().findClass(mViewClass); + mResolvedClass = ReflectionAnalyzer.getInstance().findClass(mViewClass); } return mResolvedClass; } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java index abedbd25dad3c..1b5459d349b35 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java @@ -20,6 +20,7 @@ import com.google.common.base.Preconditions; import com.android.databinding.expr.Expr; import com.android.databinding.expr.ExprModel; +import com.android.databinding.reflection.ReflectionAnalyzer; import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.tree.ParseTree; @@ -78,32 +79,38 @@ public class ExpressionVisitor extends BindingExpressionBaseVisitor { @Override public Expr visitQuestionQuestionOp(@NotNull BindingExpressionParser.QuestionQuestionOpContext ctx) { final Expr left = ctx.left.accept(this); - return mModel.ternary( - mModel.comparison("==", left, mModel.symbol("null", Object.class)), + return mModel.ternary(mModel.comparison("==", left, mModel.symbol("null", Object.class)), left, ctx.right.accept(this)); } @Override public Expr visitTerminal(@NotNull TerminalNode node) { final int type = node.getSymbol().getType(); + Class classType; switch (type) { case BindingExpressionParser.IntegerLiteral: - return mModel.symbol(node.getText(), Integer.class); + classType = int.class; + break; case BindingExpressionParser.FloatingPointLiteral: - return mModel.symbol(node.getText(), Float.class); + classType = float.class; + break; case BindingExpressionParser.BooleanLiteral: - return mModel.symbol(node.getText(), Boolean.class); + classType = boolean.class; + break; case BindingExpressionParser.CharacterLiteral: - return mModel.symbol(node.getText(), Character.class); + classType = char.class; + break; case BindingExpressionParser.SingleQuoteString: - return mModel.symbol(node.getText(), String.class); case BindingExpressionParser.DoubleQuoteString: - return mModel.symbol(node.getText(), String.class); + classType = String.class; + break; case BindingExpressionParser.NullLiteral: - return mModel.symbol(node.getText(), Object.class); + classType = Object.class; + break; default: throw new RuntimeException("cannot create expression from terminal node " + node.toString()); } + return mModel.symbol(node.getText(), classType); } @Override @@ -234,8 +241,8 @@ public class ExpressionVisitor extends BindingExpressionBaseVisitor { // @org.jetbrains.annotations.NotNull // @Override // public Class resolveValueType( -// @org.jetbrains.annotations.NotNull ClassAnalyzer classAnalyzer) { -// return classAnalyzer.commonParentOf(aggregate.getResolvedClass(), nextResult.getResolvedClass()); +// @org.jetbrains.annotations.NotNull ReflectionAnalyzer reflectionAnalyzer) { +// return reflectionAnalyzer.commonParentOf(aggregate.getResolvedClass(), nextResult.getResolvedClass()); // } // // @org.jetbrains.annotations.NotNull diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/BracketExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/BracketExpr.java index b576554475c58..06cc7c10cfbbb 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/BracketExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/BracketExpr.java @@ -16,7 +16,9 @@ package com.android.databinding.expr; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ClassClass; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.List; import java.util.Map; @@ -36,24 +38,20 @@ public class BracketExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { - Class targetType = getTarget().resolveType(classAnalyzer); + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { + ReflectionClass targetType = getTarget().resolveType(reflectionAnalyzer); if (targetType.isArray()) { mAccessor = BracketAccessor.ARRAY; - } else if (List.class.isAssignableFrom(targetType)) { + } else if (targetType.isList()) { mAccessor = BracketAccessor.LIST; - } else if (Map.class.isAssignableFrom(targetType)) { + } else if (targetType.isMap()) { mAccessor = BracketAccessor.MAP; } else { throw new IllegalArgumentException("Cannot determine variable type used in [] " + "expression. Cast the value to List, ObservableList, Map, " + "Cursor, or array."); } - if (targetType.isArray()) { - return targetType.getComponentType(); - } else { - return Object.class; - } + return targetType.getComponentType(); } @Override diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ComparisonExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ComparisonExpr.java index 82b00357a1ed1..2737e31fc61c3 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ComparisonExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ComparisonExpr.java @@ -16,7 +16,8 @@ package com.android.databinding.expr; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.List; @@ -33,8 +34,8 @@ public class ComparisonExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { - return boolean.class; + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { + return reflectionAnalyzer.loadPrimitive("boolean"); } @Override diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java index d4821fe3da94b..7e597339cdc76 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java @@ -28,8 +28,8 @@ import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.android.databinding.ClassAnalyzer; -import com.android.databinding.util.L; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; abstract public class Expr { @@ -41,7 +41,7 @@ abstract public class Expr { private Boolean mIsDynamic; - private Class mResolvedType; + private ReflectionClass mResolvedType; private String mUniqueKey; @@ -145,7 +145,7 @@ abstract public class Expr { } public boolean isObservable() { - return ClassAnalyzer.getInstance().isObservable(getResolvedType()); + return ReflectionAnalyzer.getInstance().isObservable(getResolvedType()); } public BitSet getShouldReadFlags() { @@ -278,15 +278,15 @@ abstract public class Expr { } - public Class getResolvedType() { + public ReflectionClass getResolvedType() { if (mResolvedType == null) { // TODO not get instance - mResolvedType = resolveType(ClassAnalyzer.getInstance()); + mResolvedType = resolveType(ReflectionAnalyzer.getInstance()); } return mResolvedType; } - abstract protected Class resolveType(ClassAnalyzer classAnalyzer); + abstract protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer); abstract protected List constructDependencies(); @@ -535,7 +535,7 @@ abstract public class Expr { } public String getDefaultValue() { - return ClassAnalyzer.getInstance().getDefaultValue(getResolvedType().getSimpleName()); + return ReflectionAnalyzer.getInstance().getDefaultValue(getResolvedType().toJavaCode()); } protected BitSet getPredicateInvalidFlags() { @@ -569,7 +569,7 @@ abstract public class Expr { return mIsUsed; } - public void updateExpr(ClassAnalyzer classAnalyzer) { + public void updateExpr(ReflectionAnalyzer reflectionAnalyzer) { } static class Node { diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java index 9da08a7cd4f53..4a0d7fd96e4eb 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java @@ -21,7 +21,8 @@ import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import com.android.databinding.util.L; import com.android.databinding.writer.FlagSet; @@ -191,7 +192,7 @@ public class ExprModel { public void seal() { List notifiableExpressions = new ArrayList<>(); //ensure class analyzer. We need to know observables at this point - final ClassAnalyzer classAnalyzer = ClassAnalyzer.getInstance(); + final ReflectionAnalyzer reflectionAnalyzer = ReflectionAnalyzer.getInstance(); ArrayList processedExprs = new ArrayList<>(); ArrayList exprs = new ArrayList<>(); @@ -200,13 +201,13 @@ public class ExprModel { exprs.addAll(mExprMap.values()); exprs.removeAll(processedExprs); for (Expr expr: exprs) { - expr.updateExpr(classAnalyzer); + expr.updateExpr(reflectionAnalyzer); } processedExprs.addAll(exprs); } while (!exprs.isEmpty()); int counter = 0; - final Iterable observables = filterObservables(classAnalyzer); + final Iterable observables = filterObservables(reflectionAnalyzer); List flagMapping = Lists.newArrayList(); mObservables = Lists.newArrayList(); for (Expr expr : observables) { @@ -219,7 +220,7 @@ public class ExprModel { } // non-observable identifiers gets next ids - final Iterable nonObservableIds = filterNonObservableIds(classAnalyzer); + final Iterable nonObservableIds = filterNonObservableIds(reflectionAnalyzer); for (Expr expr : nonObservableIds) { flagMapping.add(expr.getUniqueKey()); expr.setId(counter++); @@ -336,23 +337,23 @@ public class ExprModel { return mFlagMapping[id]; } - private Iterable filterNonObservableIds(final ClassAnalyzer classAnalyzer) { + private Iterable filterNonObservableIds(final ReflectionAnalyzer reflectionAnalyzer) { return Iterables.filter(mExprMap.values(), new Predicate() { @Override public boolean apply(Expr input) { return input instanceof IdentifierExpr && !input.hasId() - && !classAnalyzer.isObservable(input.getResolvedType()) + && !reflectionAnalyzer.isObservable(input.getResolvedType()) && input.isDynamic(); } }); } - private Iterable filterObservables(final ClassAnalyzer classAnalyzer) { + private Iterable filterObservables(final ReflectionAnalyzer reflectionAnalyzer) { return Iterables.filter(mExprMap.values(), new Predicate() { @Override public boolean apply(Expr input) { - return classAnalyzer.isObservable(input.getResolvedType()); + return reflectionAnalyzer.isObservable(input.getResolvedType()); } }); } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java index efb8cdf8466e3..5e63971e5d2e6 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java @@ -16,18 +16,16 @@ package com.android.databinding.expr; -import com.android.databinding.ClassAnalyzer; -import com.android.databinding.util.L; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.Callable; +import com.android.databinding.reflection.ReflectionClass; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Collections; import java.util.List; public class FieldAccessExpr extends Expr { String mName; - ClassAnalyzer.Callable mGetter; + Callable mGetter; final boolean mIsObservableField; FieldAccessExpr(Expr parent, String name) { @@ -46,7 +44,7 @@ public class FieldAccessExpr extends Expr { return getChildren().get(0); } - public ClassAnalyzer.Callable getGetter() { + public Callable getGetter() { if (mGetter == null) { getResolvedType(); } @@ -62,7 +60,7 @@ public class FieldAccessExpr extends Expr { getResolvedType(); } // maybe this is just a final field in which case cannot be notified as changed - return mGetter.type != ClassAnalyzer.Callable.Type.FIELD || mGetter.isDynamic; + return mGetter.type != Callable.Type.FIELD || mGetter.isDynamic; } @Override @@ -89,10 +87,10 @@ public class FieldAccessExpr extends Expr { } @Override - public void updateExpr(ClassAnalyzer classAnalyzer) { + public void updateExpr(ReflectionAnalyzer reflectionAnalyzer) { if (mGetter == null) { - mGetter = classAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName); - if (classAnalyzer.isObservableField(mGetter.resolvedType)) { + mGetter = reflectionAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName); + if (reflectionAnalyzer.isObservableField(mGetter.resolvedType)) { // Make this the ".get()" and add an extra field access for the observable field Expr parent = getParent(); parent.getParents().remove(this); @@ -103,16 +101,16 @@ public class FieldAccessExpr extends Expr { getChildren().add(observableField); observableField.getParents().add(this); - mGetter = classAnalyzer.findMethodOrField(mGetter.resolvedType, "get"); + mGetter = reflectionAnalyzer.findMethodOrField(mGetter.resolvedType, "get"); mName = ""; } } } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { if (mGetter == null) { - mGetter = classAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName); + mGetter = reflectionAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName); } return mGetter.resolvedType; } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/GroupExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/GroupExpr.java index b5ef3cea21da9..d62b98cf1c7ce 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/GroupExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/GroupExpr.java @@ -16,7 +16,8 @@ package com.android.databinding.expr; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.List; @@ -26,8 +27,8 @@ public class GroupExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { - return getWrapped().resolveType(classAnalyzer); + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { + return getWrapped().resolveType(reflectionAnalyzer); } @Override diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java index a123a8017dec8..6e9485110f82a 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java @@ -19,7 +19,8 @@ package com.android.databinding.expr; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.List; @@ -57,10 +58,10 @@ public class IdentifierExpr extends Expr { } @Override - protected Class resolveType(final ClassAnalyzer classAnalyzer) { + protected ReflectionClass resolveType(final ReflectionAnalyzer reflectionAnalyzer) { Preconditions.checkNotNull(mUserDefinedType, "Identifiers must have user defined types from the XML file. %s is missing it", mName); - return classAnalyzer.findClass(mUserDefinedType); + return reflectionAnalyzer.findClass(mUserDefinedType); } @Override diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MathExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MathExpr.java index e14a1433a27f6..7d99a58e87013 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MathExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MathExpr.java @@ -16,7 +16,8 @@ package com.android.databinding.expr; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.List; @@ -33,15 +34,15 @@ public class MathExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { if ("+".equals(mOp)) { // TODO we need upper casting etc. - if (String.class.equals(getLeft().getResolvedType()) - || String.class.equals(getRight().getResolvedType())) { - return String.class; + if (getLeft().getResolvedType().isString() + || getRight().getResolvedType().isString()) { + return reflectionAnalyzer.findClass(String.class); } } - return classAnalyzer.findCommonParentOf(getLeft().getResolvedType(), + return reflectionAnalyzer.findCommonParentOf(getLeft().getResolvedType(), getRight().getResolvedType()); } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java index 5ed387ebd117c..119e65e919bb4 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java @@ -18,7 +18,9 @@ package com.android.databinding.expr; import com.google.common.collect.Iterables; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.Callable; +import com.android.databinding.reflection.ReflectionClass; import java.util.ArrayList; import java.util.Arrays; @@ -27,7 +29,7 @@ import java.util.List; public class MethodCallExpr extends Expr { final String mName; - ClassAnalyzer.Callable mGetter; + Callable mGetter; MethodCallExpr(Expr target, String name, List args) { super(Iterables.concat(Arrays.asList(target), args)); @@ -35,13 +37,13 @@ public class MethodCallExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { if (mGetter == null) { - List args = new ArrayList<>(); + List args = new ArrayList<>(); for (Expr expr : getArgs()) { args.add(expr.getResolvedType()); } - mGetter = classAnalyzer.findMethod(getTarget().getResolvedType(), mName, args); + mGetter = reflectionAnalyzer.findMethod(getTarget().getResolvedType(), mName, args); } return mGetter.resolvedType; } @@ -75,7 +77,7 @@ public class MethodCallExpr extends Expr { return getChildren().subList(1, getChildren().size()); } - public ClassAnalyzer.Callable getGetter() { + public Callable getGetter() { return mGetter; } } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java index 80cbbf5ab9d3f..a8caace564b4b 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java @@ -17,12 +17,10 @@ package com.android.databinding.expr; import com.google.common.collect.ImmutableMap; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; -import java.io.IOException; -import java.net.URL; import java.util.Collections; -import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -62,7 +60,7 @@ public class ResourceExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { String type; switch (mResourceType) { case "anim": @@ -72,43 +70,36 @@ public class ResourceExpr extends Expr { type = "android.animation.Animator"; break; case "bool": - return boolean.class; + return reflectionAnalyzer.findClass(boolean.class); case "color": - return int.class; + case "dimenOffset": + case "dimenSize": + case "id": + case "integer": + case "layout": + case "plurals": + return reflectionAnalyzer.findClass(int.class); case "colorStateList": type = "android.content.res.ColorStateList"; break; case "dimen": - return float.class; - case "dimenOffset": - return int.class; - case "dimenSize": - return int.class; + case "fraction": + return reflectionAnalyzer.findClass(float.class); case "drawable": type = "android.graphics.drawable.Drawable"; break; - case "fraction": - return float.class; - case "id": - return int.class; case "intArray": - return int[].class; - case "integer": - return int.class; + return reflectionAnalyzer.findClass(int[].class); case "interpolator": type = ""; break; - case "layout": - return int.class; - case "plurals": - return int.class; case "stateListAnimator": type = "android.animation.StateListAnimator"; break; case "string": - return String.class; + return reflectionAnalyzer.findClass(String.class); case "stringArray": - return String[].class; + return reflectionAnalyzer.findClass(String[].class); case "transition": type = "android.transition.Transition"; break; @@ -119,7 +110,7 @@ public class ResourceExpr extends Expr { type = mResourceType; break; } - return classAnalyzer.findClass(type); + return reflectionAnalyzer.findClass(type); } @Override diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/SymbolExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/SymbolExpr.java index 86299c63d96f9..5c66822a85e9b 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/SymbolExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/SymbolExpr.java @@ -18,7 +18,8 @@ package com.android.databinding.expr; import com.google.common.collect.Lists; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.List; @@ -37,8 +38,8 @@ public class SymbolExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { - return mType; + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { + return reflectionAnalyzer.findClass(mType); } @Override diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/TernaryExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/TernaryExpr.java index fc25e6d41a8a7..01dde253ec214 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/TernaryExpr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/TernaryExpr.java @@ -18,7 +18,8 @@ package com.android.databinding.expr; import com.google.common.collect.Lists; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; import java.util.BitSet; import java.util.List; @@ -46,8 +47,8 @@ public class TernaryExpr extends Expr { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { - return classAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(), + protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) { + return reflectionAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(), getIfFalse().getResolvedType()); } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/Callable.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/Callable.java new file mode 100644 index 0000000000000..75c1e035fa223 --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/Callable.java @@ -0,0 +1,58 @@ +/* + * 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 com.android.databinding.reflection; + +public class Callable { + + public static enum Type { + METHOD, + FIELD + } + + public final Type type; + + public final String name; + + public final ReflectionClass resolvedType; + + public final boolean isDynamic; + + public final boolean canBeInvalidated; + + public Callable(Type type, String name, ReflectionClass resolvedType, boolean isDynamic, + boolean canBeInvalidated) { + this.type = type; + this.name = name; + this.resolvedType = resolvedType; + this.isDynamic = isDynamic; + this.canBeInvalidated = canBeInvalidated; + } + + public String getTypeCodeName() { + return resolvedType.toJavaCode(); + } + + @Override + public String toString() { + return "Callable{" + + "type=" + type + + ", name='" + name + '\'' + + ", resolvedType=" + resolvedType + + ", isDynamic=" + isDynamic + + ", canBeInvalidated=" + canBeInvalidated + + '}'; + } +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/ClassAnalyzer.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassAnalyzer.java similarity index 71% rename from tools/data-binding/compiler/src/main/java/com/android/databinding/ClassAnalyzer.java rename to tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassAnalyzer.java index e590fb27706c8..ff1ccb5f56ccc 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/ClassAnalyzer.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassAnalyzer.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.databinding; +package com.android.databinding.reflection; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; @@ -24,14 +24,18 @@ import com.android.databinding.util.L; import org.apache.commons.lang3.StringUtils; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; -public class ClassAnalyzer { +public class ClassAnalyzer extends ReflectionAnalyzer { private static final String OBSERVABLE_CLASS_NAME = "android.binding.Observable"; private static final String OBSERVABLE_LIST_CLASS_NAME = "android.binding.ObservableList"; @@ -62,7 +66,7 @@ public class ClassAnalyzer { private static ClassLoader sClassLoader; - private HashMap mClassCache = new HashMap<>(); + private HashMap mClassCache = new HashMap<>(); private final ClassLoader mClassLoader; @@ -124,22 +128,27 @@ public class ClassAnalyzer { return name; } - public boolean isDataBinder(Class klass) { - return mIViewDataBinder.isAssignableFrom(klass); + @Override + public boolean isDataBinder(ReflectionClass reflectionClass) { + ClassClass classClass = (ClassClass) reflectionClass; + return mIViewDataBinder.isAssignableFrom(classClass.mClass); } - static String toCodeName(Class klass) { - return klass.getName().replace("$", "."); - } - - public Callable findMethod(Class klass, String name, List args) { + @Override + public Callable findMethod(ReflectionClass reflectionClass, String name, + List argClasses) { + Class klass = ((ClassClass) reflectionClass).mClass; + ArrayList args = new ArrayList<>(argClasses.size()); + for (int i = 0; i < argClasses.size(); i++) { + args.add(((ClassClass) argClasses.get(i)).mClass); + } // TODO implement properly for (String methodName : new String[]{"set" + StringUtils.capitalize(name), name}) { for (Method method : klass.getMethods()) { if (methodName.equals(method.getName()) && args.size() == method .getParameterTypes().length) { - return new Callable(Callable.Type.METHOD, methodName, method.getReturnType(), true, - false); + return new Callable(Callable.Type.METHOD, methodName, + new ClassClass(method.getReturnType()), true, false); } } } @@ -148,12 +157,20 @@ public class ClassAnalyzer { "cannot find method " + name + " at class " + klass.getSimpleName()); } - public boolean isObservable(Class klass) { - return mObservable.isAssignableFrom(klass) || mObservableList.isAssignableFrom(klass) || - mObservableMap.isAssignableFrom(klass); + @Override + public boolean isObservable(ReflectionClass reflectionClass) { + Class klass = ((ClassClass) reflectionClass).mClass; + return isObservable(klass); } - public boolean isObservableField(Class klass) { + private boolean isObservable(Class klass) { + return mObservable.isAssignableFrom(klass) || mObservableList.isAssignableFrom(klass) || + mObservableMap.isAssignableFrom(klass); + } + + @Override + public boolean isObservableField(ReflectionClass reflectionClass) { + Class klass = ((ClassClass) reflectionClass).mClass; for (Class observableField : mObservableFields) { if (observableField.isAssignableFrom(klass)) { return true; @@ -162,16 +179,29 @@ public class ClassAnalyzer { return false; } - public boolean isBindable(Field field) { + @Override + public boolean isBindable(ReflectionField reflectionField) { + Field field = ((ClassField) reflectionField).mField; + return isBindable(field); + } + + @Override + public boolean isBindable(ReflectionMethod reflectionMethod) { + Method method = ((ClassMethod) reflectionMethod).mMethod; + return isBindable(method); + } + + private boolean isBindable(Field field) { return field.getAnnotation(mBindable) != null; } - public boolean isBindable(Method method) { + private boolean isBindable(Method method) { return method.getAnnotation(mBindable) != null; } - public Callable findMethodOrField(Class klass, String name) { - + @Override + public Callable findMethodOrField(ReflectionClass reflectionClass, String name) { + Class klass = ((ClassClass) reflectionClass).mClass; for (String methodName : new String[]{"get" + StringUtils.capitalize(name), "is" + StringUtils.capitalize(name), name}) { @@ -180,9 +210,8 @@ public class ClassAnalyzer { Field backingField = findField(klass, name, true); if (Modifier.isPublic(method.getModifiers())) { final Callable result = new Callable(Callable.Type.METHOD, methodName, - method.getReturnType(), - true, isBindable(method) || (backingField != null && isBindable( - backingField))); + new ClassClass(method.getReturnType()), true, + isBindable(method) || (backingField != null && isBindable(backingField)) ); L.d("backing field for %s is %s", result, backingField); return result; } @@ -193,9 +222,9 @@ public class ClassAnalyzer { try { Field field = findField(klass, name, false); if (Modifier.isPublic(field.getModifiers())) { - return new Callable(Callable.Type.FIELD, name, field.getType(), + return new Callable(Callable.Type.FIELD, name, new ClassClass(field.getType()), !Modifier.isFinal(field.getModifiers()) - || isObservable(field.getType()), isBindable(field)); + || isObservable(field.getType()), isBindable(field)); } } catch (Throwable t) { @@ -247,14 +276,18 @@ public class ClassAnalyzer { return findField(klass, name, false); } - public Class findCommonParentOf(Class klass1, Class klass2) { - Class curr = klass1; + @Override + public ReflectionClass findCommonParentOf(ReflectionClass reflectionClass1, + ReflectionClass reflectionClass2) { + ClassClass klass1 = (ClassClass) reflectionClass1; + ClassClass klass2 = (ClassClass) reflectionClass2; + ClassClass curr = klass1; while (curr != null && !curr.isAssignableFrom(klass2)) { curr = curr.getSuperclass(); } if (curr == null) { - Class primitive1 = SetterStore.getPrimitiveType(klass1); - Class primitive2 = SetterStore.getPrimitiveType(klass2); + ClassClass primitive1 = klass1.unbox(); + ClassClass primitive2 = klass2.unbox(); if (!klass1.equals(primitive1) || !klass2.equals(primitive2)) { return findCommonParentOf(primitive1, primitive2); } @@ -264,62 +297,31 @@ public class ClassAnalyzer { return curr; } - public ClassLoader getClassLoader() { - return mClassLoader; - } - - public Class loadPrimitive(String className) { + public ClassClass loadPrimitive(String className) { if ("int".equals(className)) { - return int.class; + return new ClassClass(int.class); } if ("short".equals(className)) { - return short.class; + return new ClassClass(short.class); } if ("long".equals(className)) { - return long.class; + return new ClassClass(long.class); } if ("float".equals(className)) { - return float.class; + return new ClassClass(float.class); } if ("double".equals(className)) { - return double.class; + return new ClassClass(double.class); } if ("boolean".equals(className) || "bool".equals(className)) { - return boolean.class; + return new ClassClass(boolean.class); } return null; } - public String getDefaultValue(String className) { - if("int".equals(className)) { - return "0"; - } - if("short".equals(className)) { - return "0"; - } - if("long".equals(className)) { - return "0L"; - } - if("float".equals(className)) { - return "0f"; - } - if("double".equals(className)) { - return "0.0"; - } - if("boolean".equals(className)) { - return "false"; - } - if ("char".equals(className)) { - return "'\\u0000'"; - } - if ("byte".equals(className)) { - return "0"; - } - return "null"; - } - - public Class findClass(String className) { - Class loaded = mClassCache.get(className); + @Override + public ClassClass findClass(String className) { + ClassClass loaded = mClassCache.get(className); if (loaded != null) { return loaded; } @@ -329,11 +331,11 @@ public class ClassAnalyzer { try { if (className.startsWith("[") && className.contains("L")) { int indexOfL = className.indexOf('L'); - Class baseClass = findClass( + ClassClass baseClass = findClass( className.substring(indexOfL + 1, className.length() - 1)); String realClassName = className.substring(0, indexOfL + 1) + - baseClass.getCanonicalName() + ';'; - loaded = Class.forName(realClassName, false, mClassLoader); + baseClass.mClass.getCanonicalName() + ';'; + loaded = new ClassClass(Class.forName(realClassName, false, mClassLoader)); mClassCache.put(className, loaded); } else { loaded = loadRecursively(className); @@ -345,14 +347,24 @@ public class ClassAnalyzer { } } Preconditions.checkNotNull(loaded, "Tried to load " + className + " but could not find :/"); - L.d("loaded class %s", loaded.getCanonicalName()); + L.d("loaded class %s", loaded.mClass.getCanonicalName()); return loaded; } - public Class loadRecursively(String className) throws ClassNotFoundException { + @Override + public boolean isNullable(ReflectionClass reflectionClass) { + return false; + } + + @Override + public ReflectionClass findClass(Class classType) { + return new ClassClass(classType); + } + + private ClassClass loadRecursively(String className) throws ClassNotFoundException { try { L.d("recursively checking %s", className); - return mClassLoader.loadClass(className); + return new ClassClass(mClassLoader.loadClass(className)); } catch (ClassNotFoundException ex) { int lastIndexOfDot = className.lastIndexOf("."); if (lastIndexOfDot == -1) { @@ -370,50 +382,20 @@ public class ClassAnalyzer { } } - public static boolean isNullable(Class klass) { - return Object.class.isAssignableFrom(klass); - } - - - public static class Callable { - - public static enum Type { - METHOD, - FIELD - } - - public final Type type; - - public final String name; - - public final Class resolvedType; - - public final boolean isDynamic; - - public final boolean canBeInvalidated; - - public Callable(Type type, String name, Class resolvedType, boolean isDynamic, - boolean canBeInvalidated) { - this.type = type; - this.name = name; - this.resolvedType = resolvedType; - this.isDynamic = isDynamic; - this.canBeInvalidated = canBeInvalidated; - } - - public String getTypeCodeName() { - return ClassAnalyzer.toCodeName(resolvedType); - } - - @Override - public String toString() { - return "Callable{" + - "type=" + type + - ", name='" + name + '\'' + - ", resolvedType=" + resolvedType + - ", isDynamic=" + isDynamic + - ", canBeInvalidated=" + canBeInvalidated + - '}'; + @Override + public List getResources(String name) { + List urlList = new ArrayList(); + Enumeration urls = null; + try { + urls = mClassLoader.getResources(name); + if (urls != null) { + while (urls.hasMoreElements()) { + urlList.add(urls.nextElement()); + } + } + } catch (IOException e) { + e.printStackTrace(); } + return urlList; } } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassClass.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassClass.java new file mode 100644 index 0000000000000..2ffa0e7c04512 --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassClass.java @@ -0,0 +1,230 @@ +/* + * 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 com.android.databinding.reflection; + +import java.lang.reflect.Method; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +public class ClassClass implements ReflectionClass { + + public final Class mClass; + + public ClassClass(Class clazz) { + mClass = clazz; + } + + @Override + public String toJavaCode() { + return toJavaCode(mClass); + } + + private static String toJavaCode(Class aClass) { + if (aClass.isArray()) { + Class component = aClass.getComponentType(); + return toJavaCode(component) + "[]"; + } else { + return aClass.getCanonicalName().replace('$', '.'); + } + } + + @Override + public boolean isArray() { + return mClass.isArray(); + } + + @Override + public ClassClass getComponentType() { + if (mClass.isArray()) { + return new ClassClass(mClass.getComponentType()); + } else if (isList() || isMap()) { + return new ClassClass(Object.class); + } else { + return null; + } + } + + @Override + public boolean isList() { + return List.class.isAssignableFrom(mClass); + } + + @Override + public boolean isMap() { + return Map.class.isAssignableFrom(mClass); + } + + @Override + public boolean isString() { + return String.class.equals(mClass); + } + + @Override + public boolean isNullable() { + return Object.class.isAssignableFrom(mClass); + } + + @Override + public boolean isPrimitive() { + return mClass.isPrimitive(); + } + + @Override + public boolean isBoolean() { + return boolean.class.equals(mClass); + } + + @Override + public boolean isChar() { + return char.class.equals(mClass); + } + + @Override + public boolean isByte() { + return byte.class.equals(mClass); + } + + @Override + public boolean isShort() { + return short.class.equals(mClass); + } + + @Override + public boolean isInt() { + return int.class.equals(mClass); + } + + @Override + public boolean isLong() { + return long.class.equals(mClass); + } + + @Override + public boolean isFloat() { + return float.class.equals(mClass); + } + + @Override + public boolean isDouble() { + return double.class.equals(mClass); + } + + @Override + public boolean isObject() { + return Object.class.equals(mClass); + } + + @Override + public boolean isVoid() { + return void.class.equals(mClass); + } + + @Override + public ClassClass unbox() { + if (mClass.isPrimitive()) { + return this; + } + if (Integer.class.equals(mClass)) { + return new ClassClass(int.class); + } else if (Long.class.equals(mClass)) { + return new ClassClass(long.class); + } else if (Short.class.equals(mClass)) { + return new ClassClass(short.class); + } else if (Byte.class.equals(mClass)) { + return new ClassClass(byte.class); + } else if (Character.class.equals(mClass)) { + return new ClassClass(char.class); + } else if (Double.class.equals(mClass)) { + return new ClassClass(double.class); + } else if (Float.class.equals(mClass)) { + return new ClassClass(float.class); + } else if (Boolean.class.equals(mClass)) { + return new ClassClass(boolean.class); + } else { + // not a boxed type + return this; + } + + } + + @Override + public ReflectionClass box() { + if (!mClass.isPrimitive()) { + return this; + } + if (int.class.equals(mClass)) { + return new ClassClass(Integer.class); + } else if (long.class.equals(mClass)) { + return new ClassClass(Long.class); + } else if (short.class.equals(mClass)) { + return new ClassClass(Short.class); + } else if (byte.class.equals(mClass)) { + return new ClassClass(Byte.class); + } else if (char.class.equals(mClass)) { + return new ClassClass(Character.class); + } else if (double.class.equals(mClass)) { + return new ClassClass(Double.class); + } else if (float.class.equals(mClass)) { + return new ClassClass(Float.class); + } else if (boolean.class.equals(mClass)) { + return new ClassClass(Boolean.class); + } else { + // not a valid type? + return this; + } + } + + @Override + public boolean isAssignableFrom(ReflectionClass that) { + Class thatClass = ((ClassClass) that).mClass; + return mClass.isAssignableFrom(thatClass); + } + + @Override + public ReflectionMethod[] getMethods(String name, int numParameters) { + Method[] methods = mClass.getMethods(); + ArrayList matching = new ArrayList<>(); + for (Method method : methods) { + if (method.getName().equals(name) && + method.getParameterTypes().length == numParameters) { + matching.add(new ClassMethod(method)); + } + } + return matching.toArray(new ReflectionMethod[matching.size()]); + } + + @Override + public ClassClass getSuperclass() { + return new ClassClass(mClass.getSuperclass()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ClassClass) { + return mClass.equals(((ClassClass) obj).mClass); + } else { + return false; + } + } + + @Override + public int hashCode() { + return mClass.hashCode(); + } +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassField.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassField.java new file mode 100644 index 0000000000000..b5ea8f0a4a36b --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassField.java @@ -0,0 +1,27 @@ +/* + * 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 com.android.databinding.reflection; + +import java.lang.reflect.Field; + +public class ClassField implements ReflectionField { + + public final Field mField; + + public ClassField(Field field) { + mField = field; + } +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassMethod.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassMethod.java new file mode 100644 index 0000000000000..bbf6c3e6d0d6f --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ClassMethod.java @@ -0,0 +1,64 @@ +/* + * 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 com.android.databinding.reflection; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public class ClassMethod implements ReflectionMethod { + + public final Method mMethod; + + public ClassMethod(Method method) { + mMethod = method; + } + + + @Override + public ReflectionClass getDeclaringClass() { + return new ClassClass(mMethod.getDeclaringClass()); + } + + @Override + public ReflectionClass[] getParameterTypes() { + Class[] parameterTypes = mMethod.getParameterTypes(); + ReflectionClass[] parameterClasses = new ReflectionClass[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i++) { + parameterClasses[i] = new ClassClass(parameterTypes[i]); + } + return parameterClasses; + } + + @Override + public String getName() { + return mMethod.getName(); + } + + @Override + public ReflectionClass getReturnType() { + return new ClassClass(mMethod.getReturnType()); + } + + @Override + public boolean isPublic() { + return Modifier.isPublic(mMethod.getModifiers()); + } + + @Override + public boolean isStatic() { + return Modifier.isStatic(mMethod.getModifiers()); + } +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionAnalyzer.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionAnalyzer.java new file mode 100644 index 0000000000000..4d5d49abc90fb --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionAnalyzer.java @@ -0,0 +1,88 @@ +/* + * 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 com.android.databinding.reflection; + +import java.net.URL; +import java.util.List; + +public abstract class ReflectionAnalyzer { + private static ReflectionAnalyzer sAnalyzer; + + public abstract boolean isDataBinder(ReflectionClass reflectionClass); + + public abstract Callable findMethod(ReflectionClass reflectionClass, String name, + List args); + + public abstract boolean isObservable(ReflectionClass reflectionClass); + + public abstract boolean isObservableField(ReflectionClass reflectionClass); + + public abstract boolean isBindable(ReflectionField field); + + public abstract boolean isBindable(ReflectionMethod method); + + public abstract Callable findMethodOrField(ReflectionClass klass, String name); + + public abstract ReflectionClass findCommonParentOf(ReflectionClass reflectionClass1, + ReflectionClass reflectionClass2); + + public abstract ReflectionClass loadPrimitive(String className); + + public static ReflectionAnalyzer getInstance() { + return sAnalyzer; + } + + public static void setClassLoader(ClassLoader classLoader) { + ClassAnalyzer.setClassLoader(classLoader); + sAnalyzer = ClassAnalyzer.getInstance(); + } + + public String getDefaultValue(String className) { + if("int".equals(className)) { + return "0"; + } + if("short".equals(className)) { + return "0"; + } + if("long".equals(className)) { + return "0L"; + } + if("float".equals(className)) { + return "0f"; + } + if("double".equals(className)) { + return "0.0"; + } + if("boolean".equals(className)) { + return "false"; + } + if ("char".equals(className)) { + return "'\\u0000'"; + } + if ("byte".equals(className)) { + return "0"; + } + return "null"; + } + + public abstract ReflectionClass findClass(String className); + + public abstract boolean isNullable(ReflectionClass reflectionClass); + + public abstract List getResources(String name); + + public abstract ReflectionClass findClass(Class classType); +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionClass.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionClass.java new file mode 100644 index 0000000000000..ef13ab2b86950 --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionClass.java @@ -0,0 +1,68 @@ +/* + * 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 com.android.databinding.reflection; + +import java.net.URL; +import java.util.List; + +public interface ReflectionClass { + + String toJavaCode(); + + boolean isArray(); + + ReflectionClass getComponentType(); + + boolean isList(); + + boolean isMap(); + + boolean isString(); + + boolean isNullable(); + + boolean isPrimitive(); + + boolean isBoolean(); + + boolean isChar(); + + boolean isByte(); + + boolean isShort(); + + boolean isInt(); + + boolean isLong(); + + boolean isFloat(); + + boolean isDouble(); + + boolean isObject(); + + boolean isVoid(); + + ReflectionClass unbox(); + + ReflectionClass box(); + + boolean isAssignableFrom(ReflectionClass that); + + ReflectionMethod[] getMethods(String name, int numParameters); + + ReflectionClass getSuperclass(); +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionField.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionField.java new file mode 100644 index 0000000000000..78dfeca999ea2 --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionField.java @@ -0,0 +1,20 @@ +/* + * 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 com.android.databinding.reflection; + +public interface ReflectionField { + +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionMethod.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionMethod.java new file mode 100644 index 0000000000000..9f682ea2d54df --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/reflection/ReflectionMethod.java @@ -0,0 +1,30 @@ +/* + * 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 com.android.databinding.reflection; + +public interface ReflectionMethod { + ReflectionClass getDeclaringClass(); + + ReflectionClass[] getParameterTypes(); + + String getName(); + + ReflectionClass getReturnType(); + + boolean isPublic(); + + boolean isStatic(); +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java index b85d73f96abed..58ac3b40be67c 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java @@ -15,7 +15,9 @@ */ package com.android.databinding.store; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; +import com.android.databinding.reflection.ReflectionClass; +import com.android.databinding.reflection.ReflectionMethod; import java.io.File; import java.io.IOException; @@ -51,10 +53,10 @@ public class SetterStore { private static SetterStore sStore; private final IntermediateV1 mStore; - private final ClassAnalyzer mClassAnalyzer; + private final ReflectionAnalyzer mClassAnalyzer; - private SetterStore(ClassAnalyzer classAnalyzer, IntermediateV1 store) { - mClassAnalyzer = classAnalyzer; + private SetterStore(ReflectionAnalyzer reflectionAnalyzer, IntermediateV1 store) { + mClassAnalyzer = reflectionAnalyzer; mStore = store; } @@ -91,24 +93,22 @@ public class SetterStore { return sStore; } - public static SetterStore get(ClassAnalyzer classAnalyzer) { + public static SetterStore get(ReflectionAnalyzer reflectionAnalyzer) { if (sStore == null) { - sStore = load(classAnalyzer); + sStore = load(reflectionAnalyzer); } return sStore; } - private static SetterStore load(ClassAnalyzer classAnalyzer) { + private static SetterStore load(ReflectionAnalyzer reflectionAnalyzer) { IntermediateV1 store = new IntermediateV1(); String resourceName = SetterStore.class.getPackage().getName().replace('.', '/') + "/setter_store.bin"; try { - Enumeration resources = classAnalyzer.getClassLoader().getResources(resourceName); - while (resources.hasMoreElements()) { - URL resource = resources.nextElement(); + for (URL resource : reflectionAnalyzer.getResources(resourceName)) { merge(store, resource); } - return new SetterStore(classAnalyzer, store); + return new SetterStore(reflectionAnalyzer, store); } catch (IOException e) { System.err.println("Could not read SetterStore intermediate file: " + e.getLocalizedMessage()); @@ -118,7 +118,7 @@ public class SetterStore { e.getLocalizedMessage()); e.printStackTrace(); } - return new SetterStore(classAnalyzer, store); + return new SetterStore(reflectionAnalyzer, store); } private static SetterStore load(InputStream inputStream) @@ -282,8 +282,8 @@ public class SetterStore { } } - public String getSetterCall(String attribute, Class viewType, - Class valueType, String viewExpression, String valueExpression) { + public String getSetterCall(String attribute, ReflectionClass viewType, + ReflectionClass valueType, String viewExpression, String valueExpression) { if (!attribute.startsWith("android:")) { int colon = attribute.indexOf(':'); if (colon >= 0) { @@ -293,9 +293,9 @@ public class SetterStore { HashMap adapters = mStore.adapterMethods.get(attribute); MethodDescription adapter = null; String setterName = null; - Method bestSetterMethod = getBestSetter(viewType, valueType, attribute); - Class bestViewType = null; - Class bestValueType = null; + ReflectionMethod bestSetterMethod = getBestSetter(viewType, valueType, attribute); + ReflectionClass bestViewType = null; + ReflectionClass bestValueType = null; if (bestSetterMethod != null) { bestViewType = bestSetterMethod.getDeclaringClass(); bestValueType = bestSetterMethod.getParameterTypes()[0]; @@ -305,10 +305,10 @@ public class SetterStore { if (adapters != null) { for (AccessorKey key : adapters.keySet()) { try { - Class adapterViewType = mClassAnalyzer.findClass(key.viewType); + ReflectionClass adapterViewType = mClassAnalyzer.findClass(key.viewType); if (adapterViewType.isAssignableFrom(viewType)) { try { - Class adapterValueType = mClassAnalyzer.findClass(key.valueType); + ReflectionClass adapterValueType = mClassAnalyzer.findClass(key.valueType); boolean isBetterView = bestViewType == null || bestValueType.isAssignableFrom(adapterValueType); if (isBetterParameter(valueType, adapterValueType, bestValueType, @@ -327,8 +327,8 @@ public class SetterStore { } } - if (Object.class.equals(valueType) && !bestValueType.isAssignableFrom(valueType)) { - valueExpression = "(" + bestValueType.getCanonicalName() + ") " + valueExpression; + if (valueType.isObject() && !bestValueType.isAssignableFrom(valueType)) { + valueExpression = "(" + bestValueType.toJavaCode() + ") " + valueExpression; } MethodDescription conversionMethod = getConversionMethod(valueType, bestValueType); if (conversionMethod != null) { @@ -346,14 +346,15 @@ public class SetterStore { } } - private Method getBestSetter(Class viewType, Class argumentType, String attribute) { + private ReflectionMethod getBestSetter(ReflectionClass viewType, ReflectionClass argumentType, + String attribute) { String setterName = null; HashMap renamed = mStore.renamedMethods.get(attribute); if (renamed != null) { for (String className : renamed.keySet()) { try { - Class renamedViewType = mClassAnalyzer.findClass(className); + ReflectionClass renamedViewType = mClassAnalyzer.findClass(className); if (renamedViewType.isAssignableFrom(viewType)) { setterName = renamed.get(className).method; break; @@ -366,17 +367,14 @@ public class SetterStore { if (setterName == null) { setterName = getDefaultSetter(attribute); } - Method[] methods = viewType.getMethods(); + ReflectionMethod[] methods = viewType.getMethods(setterName, 1); - Class bestParameterType = null; - Method bestMethod = null; - for (Method method : methods) { - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length == 1 && setterName.equals(method.getName()) && - void.class.equals(method.getReturnType()) && - !Modifier.isStatic(method.getModifiers()) && - Modifier.isPublic(method.getModifiers())) { - Class param = parameterTypes[0]; + ReflectionClass bestParameterType = null; + ReflectionMethod bestMethod = null; + for (ReflectionMethod method : methods) { + ReflectionClass[] parameterTypes = method.getParameterTypes(); + if (method.getReturnType().isVoid() && !method.isStatic() && method.isPublic()) { + ReflectionClass param = parameterTypes[0]; if (isBetterParameter(argumentType, param, bestParameterType, true)) { bestParameterType = param; bestMethod = method; @@ -394,8 +392,8 @@ public class SetterStore { return "set" + propertyName; } - private boolean isBetterParameter(Class argument, Class parameter, Class oldParameter, - boolean isBetterViewTypeMatch) { + private boolean isBetterParameter(ReflectionClass argument, ReflectionClass parameter, + ReflectionClass oldParameter, boolean isBetterViewTypeMatch) { // Right view type. Check the value if (!isBetterViewTypeMatch && oldParameter.equals(argument)) { return false; @@ -430,15 +428,14 @@ public class SetterStore { if (getConversionMethod(argument, oldParameter) != null) { return false; } - return argument.equals(Object.class) && !parameter.isPrimitive(); + return argument.isObject() && !parameter.isPrimitive(); } } } - private static boolean isImplicitConversion(Class from, Class to) { + private static boolean isImplicitConversion(ReflectionClass from, ReflectionClass to) { if (from != null && to != null && from.isPrimitive() && to.isPrimitive()) { - if (from.equals(boolean.class) || to.equals(boolean.class) || - to.equals(char.class)) { + if (from.isBoolean() || to.isBoolean() || to.isChar()) { return false; } int fromConversionLevel = getConversionLevel(from); @@ -449,17 +446,17 @@ public class SetterStore { } } - private MethodDescription getConversionMethod(Class from, Class to) { + private MethodDescription getConversionMethod(ReflectionClass from, ReflectionClass to) { if (from != null && to != null) { for (String fromClassName : mStore.conversionMethods.keySet()) { try { - Class convertFrom = mClassAnalyzer.findClass(fromClassName); + ReflectionClass convertFrom = mClassAnalyzer.findClass(fromClassName); if (canUseForConversion(from, convertFrom)) { HashMap conversion = mStore.conversionMethods.get(fromClassName); for (String toClassName : conversion.keySet()) { try { - Class convertTo = mClassAnalyzer.findClass(toClassName); + ReflectionClass convertTo = mClassAnalyzer.findClass(toClassName); if (canUseForConversion(convertTo, to)) { return conversion.get(toClassName); } @@ -476,90 +473,40 @@ public class SetterStore { return null; } - private static boolean canUseForConversion(Class from, Class to) { + private boolean canUseForConversion(ReflectionClass from, ReflectionClass to) { return from.equals(to) || isBoxingConversion(from, to) || to.isAssignableFrom(from); } - private static int getConversionLevel(Class primitive) { - if (byte.class.equals(primitive)) { + private static int getConversionLevel(ReflectionClass primitive) { + if (primitive == null) { + return -1; + } else if (primitive.isByte()) { return 0; - } else if (char.class.equals(primitive)) { + } else if (primitive.isChar()) { return 1; - } else if (short.class.equals(primitive)) { + } else if (primitive.isShort()) { return 2; - } else if (int.class.equals(primitive)) { + } else if (primitive.isInt()) { return 3; - } else if (long.class.equals(primitive)) { + } else if (primitive.isLong()) { return 4; - } else if (float.class.equals(primitive)) { + } else if (primitive.isFloat()) { return 5; - } else if (double.class.equals(primitive)) { + } else if (primitive.isDouble()) { return 6; } else { return -1; } } - public static boolean isBoxingConversion(Class class1, Class class2) { + public static boolean isBoxingConversion(ReflectionClass class1, ReflectionClass class2) { if (class1.isPrimitive() != class2.isPrimitive()) { - return (getWrappedType(class1).equals(getWrappedType(class2))); + return (class1.box().equals(class2.box())); } else { return false; } } - public static Class getWrappedType(Class type) { - if (!type.isPrimitive()) { - return type; - } - if (int.class.equals(type)) { - return Integer.class; - } else if (long.class.equals(type)) { - return Long.class; - } else if (short.class.equals(type)) { - return Short.class; - } else if (byte.class.equals(type)) { - return Byte.class; - } else if (char.class.equals(type)) { - return Character.class; - } else if (double.class.equals(type)) { - return Double.class; - } else if (float.class.equals(type)) { - return Float.class; - } else if (boolean.class.equals(type)) { - return Boolean.class; - } else { - // what type is this? - return type; - } - } - - public static Class getPrimitiveType(Class type) { - if (type.isPrimitive()) { - return type; - } - if (Integer.class.equals(type)) { - return int.class; - } else if (Long.class.equals(type)) { - return long.class; - } else if (Short.class.equals(type)) { - return short.class; - } else if (Byte.class.equals(type)) { - return byte.class; - } else if (Character.class.equals(type)) { - return char.class; - } else if (Double.class.equals(type)) { - return double.class; - } else if (Float.class.equals(type)) { - return float.class; - } else if (Boolean.class.equals(type)) { - return boolean.class; - } else { - // what type is this? - return type; - } - } - private static void merge(IntermediateV1 store, URL nextUrl) throws IOException, ClassNotFoundException { InputStream inputStream = null; diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt index 946c7ccdb7d27..f870ca44930c0 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt @@ -17,7 +17,9 @@ import kotlin.properties.ReadOnlyProperty import kotlin.properties.Delegates import com.android.databinding.ext.joinToCamelCase import com.android.databinding.ext.joinToCamelCaseAsVar -import com.android.databinding.ClassAnalyzer +import com.android.databinding.reflection.ReflectionAnalyzer +import com.android.databinding.reflection.ReflectionClass +import com.android.databinding.reflection.ReflectionAnalyzer private class LazyExt(private val initializer: (k : K) -> T) : ReadOnlyProperty { private val mapping = hashMapOf() @@ -76,7 +78,3 @@ public fun String.toCamelCaseAsVar() : String { public fun String.br() : String = "android.binding.BR.${if (this == "") "_all" else this}" - -public fun Class<*>.getCodeName() : String = getName().replace("$", ".") - -public fun Class<*>.isObservable() : Boolean = ClassAnalyzer.getInstance().isObservable(this) diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt index 4fdefe2eb23f2..0b5dd11f3e87f 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt @@ -50,7 +50,7 @@ import com.android.databinding.util.Log import com.android.databinding.LayoutBinder import com.android.databinding.DataBinder import com.android.databinding.writer.DataBinderWriter -import com.android.databinding.ClassAnalyzer +import com.android.databinding.reflection.ReflectionAnalyzer import com.android.databinding.util.ParserHelper import com.google.common.base.Preconditions @@ -59,7 +59,7 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite val outputBaseDir : File, val outputResBaseDir : File) { var dbr : DataBinderWriter by Delegates.notNull() var processed = false - public var classAnalyzer : ClassAnalyzer by Delegates.notNull() + public var reflectionAnalyzer : ReflectionAnalyzer by Delegates.notNull() val jDataBinder = DataBinder(); diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt index 9d6a95cc6897d..1c2ec3c5fdab0 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt @@ -15,7 +15,7 @@ package com.android.databinding.writer import com.android.databinding.LayoutBinder import com.android.databinding.expr.Expr -import com.android.databinding.ClassAnalyzer +import com.android.databinding.reflection.ReflectionAnalyzer import kotlin.properties.Delegates import com.android.databinding.ext.joinToCamelCaseAsVar import com.android.databinding.BindingTarget @@ -42,9 +42,9 @@ import com.android.databinding.ext.androidId import com.android.databinding.ext.lazy import com.android.databinding.ext.br import com.android.databinding.ext.toJavaCode -import com.android.databinding.ext.isObservable import com.android.databinding.expr.ResourceExpr import com.android.databinding.expr.BracketExpr +import com.android.databinding.reflection.Callable fun String.stripNonJava() = this.split("[^a-zA-Z0-9]").map{ it.trim() }.joinToCamelCaseAsVar() @@ -160,7 +160,7 @@ fun Expr.toCode(full : Boolean = false) : KCode { } is FieldAccessExpr -> kcode("") { app("", it.getParent().toCode()) - if (it.getGetter().type == com.android.databinding.ClassAnalyzer.Callable.Type.FIELD) { + if (it.getGetter().type == Callable.Type.FIELD) { app(".", it.getGetter().name) } else { app(".", it.getGetter().name).app("()") @@ -602,8 +602,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { tab("// read ${expr.getUniqueKey()}") // create an if case for all dependencies that might be null val nullables = expr.getDependencies().filter { - it.isMandatory() && - ClassAnalyzer.isNullable(it.getOther().getResolvedType()) + it.isMandatory() && it.getOther().getResolvedType().isNullable() } .map { it.getOther() } if (!expr.isEqualityCheck() && nullables.isNotEmpty()) { diff --git a/tools/data-binding/compiler/src/test/java/com/android/databinding/ExpressionVisitorTest.java b/tools/data-binding/compiler/src/test/java/com/android/databinding/ExpressionVisitorTest.java index f4d0e237c192b..fa1e111aadb60 100644 --- a/tools/data-binding/compiler/src/test/java/com/android/databinding/ExpressionVisitorTest.java +++ b/tools/data-binding/compiler/src/test/java/com/android/databinding/ExpressionVisitorTest.java @@ -16,8 +16,6 @@ package com.android.databinding; -import com.android.databinding.ClassAnalyzer; -import com.android.databinding.ExpressionParser; import com.android.databinding.expr.ComparisonExpr; import com.android.databinding.expr.Dependency; import com.android.databinding.expr.Expr; @@ -27,6 +25,8 @@ import com.android.databinding.expr.IdentifierExpr; import com.android.databinding.expr.MethodCallExpr; import com.android.databinding.expr.SymbolExpr; import com.android.databinding.expr.TernaryExpr; +import com.android.databinding.reflection.Callable; +import com.android.databinding.reflection.ReflectionAnalyzer; import org.junit.Before; import org.junit.Test; @@ -43,7 +43,7 @@ public class ExpressionVisitorTest { @Before public void setUp() throws Exception { - ClassAnalyzer.initForTests(); + ReflectionAnalyzer.initForTests(); } private T parse(String input, Class klass) { @@ -69,7 +69,7 @@ public class ExpressionVisitorTest { @Before public void setUp() throws Exception { - ClassAnalyzer.initForTests(); + ReflectionAnalyzer.initForTests(); } @Parameterized.Parameters @@ -143,8 +143,8 @@ public class ExpressionVisitorTest { final IdentifierExpr id = (IdentifierExpr) parsed.getParent(); id.setUserDefinedType("java.lang.String"); assertSame(int.class, parsed.getResolvedType()); - ClassAnalyzer.Callable getter = parsed.getGetter(); - assertEquals(ClassAnalyzer.Callable.Type.METHOD, getter.type); + Callable getter = parsed.getGetter(); + assertEquals(Callable.Type.METHOD, getter.type); assertEquals("length", getter.name); assertEquals(1, parsed.getDependencies().size()); final Dependency dep = parsed.getDependencies().get(0); @@ -159,8 +159,8 @@ public class ExpressionVisitorTest { final IdentifierExpr id = (IdentifierExpr) parsed.getParent(); id.setUserDefinedType("java.lang.String"); assertSame(byte[].class, parsed.getResolvedType()); - ClassAnalyzer.Callable getter = parsed.getGetter(); - assertEquals(ClassAnalyzer.Callable.Type.METHOD, getter.type); + Callable getter = parsed.getGetter(); + assertEquals(Callable.Type.METHOD, getter.type); assertEquals("getBytes", getter.name); assertEquals(1, parsed.getDependencies().size()); final Dependency dep = parsed.getDependencies().get(0); diff --git a/tools/data-binding/compiler/src/test/java/com/android/databinding/LayoutBinderTest.java b/tools/data-binding/compiler/src/test/java/com/android/databinding/LayoutBinderTest.java index 0431d19a3a6ff..8859d3601c9e5 100644 --- a/tools/data-binding/compiler/src/test/java/com/android/databinding/LayoutBinderTest.java +++ b/tools/data-binding/compiler/src/test/java/com/android/databinding/LayoutBinderTest.java @@ -14,13 +14,13 @@ package com.android.databinding; -import com.android.databinding.ClassAnalyzer; -import com.android.databinding.LayoutBinder; import com.android.databinding.expr.Expr; import com.android.databinding.expr.ExprModel; import com.android.databinding.expr.FieldAccessExpr; import com.android.databinding.expr.IdentifierExpr; import com.android.databinding.expr.StaticIdentifierExpr; +import com.android.databinding.reflection.Callable; +import com.android.databinding.reflection.ReflectionAnalyzer; import org.junit.Before; import org.junit.Test; @@ -35,7 +35,7 @@ public class LayoutBinderTest { ExprModel mExprModel; @Before public void setUp() throws Exception { - ClassAnalyzer.initForTests(); + ReflectionAnalyzer.initForTests(); mLayoutBinder = new LayoutBinder(null); mExprModel = mLayoutBinder.getModel(); } @@ -91,8 +91,8 @@ public class LayoutBinderTest { IdentifierExpr id = mExprModel.identifier("user"); FieldAccessExpr fa = (FieldAccessExpr) item; fa.getResolvedType(); - final ClassAnalyzer.Callable getter = fa.getGetter(); - assertTrue(getter.type == ClassAnalyzer.Callable.Type.METHOD); + final Callable getter = fa.getGetter(); + assertTrue(getter.type == Callable.Type.METHOD); assertSame(id, fa.getParent()); assertTrue(fa.isDynamic()); } diff --git a/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprModelTest.java b/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprModelTest.java index 96d1a2f1f165c..f2b2236ffbfdd 100644 --- a/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprModelTest.java +++ b/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprModelTest.java @@ -19,7 +19,7 @@ package com.android.databinding.expr; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; import com.android.databinding.LayoutBinder; import com.android.databinding.util.L; @@ -45,7 +45,7 @@ public class ExprModelTest { } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected Class resolveType(ReflectionAnalyzer reflectionAnalyzer) { return Integer.class; } @@ -77,7 +77,7 @@ public class ExprModelTest { @Before public void setUp() throws Exception { - ClassAnalyzer.initForTests(); + ReflectionAnalyzer.initForTests(); mExprModel = new ExprModel(); } diff --git a/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprTest.java b/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprTest.java index dd21d25480f43..fd6daf87d52d6 100644 --- a/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprTest.java +++ b/tools/data-binding/compiler/src/test/java/com/android/databinding/expr/ExprTest.java @@ -16,7 +16,7 @@ package com.android.databinding.expr; -import com.android.databinding.ClassAnalyzer; +import com.android.databinding.reflection.ReflectionAnalyzer; import org.junit.Before; import org.junit.Test; @@ -37,7 +37,7 @@ public class ExprTest{ } @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected Class resolveType(ReflectionAnalyzer reflectionAnalyzer) { return Integer.class; } @@ -59,14 +59,14 @@ public class ExprTest{ @Before public void setUp() throws Exception { - ClassAnalyzer.initForTests(); + ReflectionAnalyzer.initForTests(); } @Test(expected=IllegalStateException.class) public void testBadExpr() { Expr expr = new Expr() { @Override - protected Class resolveType(ClassAnalyzer classAnalyzer) { + protected Class resolveType(ReflectionAnalyzer reflectionAnalyzer) { return Integer.class; } diff --git a/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt b/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt index 3725616d99faa..4b66e77101199 100644 --- a/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt +++ b/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt @@ -44,6 +44,7 @@ import javax.tools.JavaCompiler import javax.tools.ToolProvider import java.util.Arrays import org.apache.commons.io.FileUtils +import com.android.databinding.reflection.ReflectionAnalyzer class DataBinderPlugin : Plugin { var parser: KLayoutParser by Delegates.notNull() @@ -177,8 +178,8 @@ class DataBinderPlugin : Plugin { log("generated urls: ${urls} len: ${urls.size}") val classLoader = URLClassLoader(urls, androidClassLoader) log("created class loader") - ClassAnalyzer.setClassLoader(classLoader) - parser.classAnalyzer = ClassAnalyzer.getInstance() + ReflectionAnalyzer.setClassLoader(classLoader) + parser.reflectionAnalyzer = ReflectionAnalyzer.getInstance() project.task("compileGenerated", MethodClosure(this, "compileGenerated")) }