Removed reflection-based implementations and renamed classes.
Renamed Model* classes to Annotation* Renamed Reflection* classes to Model* Removed Class* classes -- they are no longer needed. The names were confusing. I think this is better.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package com.android.databinding.annotationprocessor;
|
||||
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
|
||||
import android.binding.Bindable;
|
||||
|
||||
@@ -18,7 +17,6 @@ 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;
|
||||
@@ -28,15 +26,11 @@ 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.PackageElement;
|
||||
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;
|
||||
@@ -54,7 +48,7 @@ public class ProcessBindable extends AbstractProcessor {
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
super.init(processingEnv);
|
||||
ReflectionAnalyzer.setProcessingEnvironment(processingEnv);
|
||||
ModelAnalyzer.setProcessingEnvironment(processingEnv);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.android.databinding;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
import com.android.databinding.store.SetterStore;
|
||||
import com.android.databinding.expr.Expr;
|
||||
|
||||
@@ -39,15 +39,15 @@ public class Binding {
|
||||
}
|
||||
|
||||
public String toJavaCode(String targetViewName, String expressionCode) {
|
||||
ReflectionClass viewType = mTarget.getResolvedType();
|
||||
return SetterStore.get(ReflectionAnalyzer.getInstance()).getSetterCall(mName, viewType,
|
||||
ModelClass viewType = mTarget.getResolvedType();
|
||||
return SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName, viewType,
|
||||
mExpr.getResolvedType(), targetViewName, expressionCode);
|
||||
}
|
||||
|
||||
// private String resolveJavaCode(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
// private String resolveJavaCode(ModelAnalyzer modelAnalyzer) {
|
||||
//
|
||||
// }
|
||||
//// return reflectionAnalyzer.findMethod(mTarget.getResolvedType(), mName,
|
||||
//// return modelAnalyzer.findMethod(mTarget.getResolvedType(), mName,
|
||||
//// Arrays.asList(mExpr.getResolvedType()));
|
||||
// //}
|
||||
//
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.android.databinding;
|
||||
|
||||
import com.android.databinding.expr.Expr;
|
||||
import com.android.databinding.expr.ExprModel;
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
import com.android.databinding.store.ResourceBundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
public class BindingTarget {
|
||||
List<Binding> mBindings = new ArrayList<>();
|
||||
ExprModel mModel;
|
||||
ReflectionClass mResolvedClass;
|
||||
ModelClass mResolvedClass;
|
||||
// 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.
|
||||
private ResourceBundle.BindingTargetBundle mBundle;
|
||||
@@ -57,9 +57,9 @@ public class BindingTarget {
|
||||
return mBundle.getFullClassName();
|
||||
}
|
||||
|
||||
public ReflectionClass getResolvedType() {
|
||||
public ModelClass getResolvedType() {
|
||||
if (mResolvedClass == null) {
|
||||
mResolvedClass = ReflectionAnalyzer.getInstance().findClass(mBundle.getFullClassName());
|
||||
mResolvedClass = ModelAnalyzer.getInstance().findClass(mBundle.getFullClassName());
|
||||
}
|
||||
return mResolvedClass;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ 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;
|
||||
@@ -241,8 +240,8 @@ public class ExpressionVisitor extends BindingExpressionBaseVisitor<Expr> {
|
||||
// @org.jetbrains.annotations.NotNull
|
||||
// @Override
|
||||
// public Class<? extends Object> resolveValueType(
|
||||
// @org.jetbrains.annotations.NotNull ReflectionAnalyzer reflectionAnalyzer) {
|
||||
// return reflectionAnalyzer.commonParentOf(aggregate.getResolvedClass(), nextResult.getResolvedClass());
|
||||
// @org.jetbrains.annotations.NotNull ModelAnalyzer modelAnalyzer) {
|
||||
// return modelAnalyzer.commonParentOf(aggregate.getResolvedClass(), nextResult.getResolvedClass());
|
||||
// }
|
||||
//
|
||||
// @org.jetbrains.annotations.NotNull
|
||||
|
||||
@@ -16,12 +16,10 @@
|
||||
|
||||
package com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ClassClass;
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BracketExpr extends Expr {
|
||||
|
||||
@@ -38,8 +36,8 @@ public class BracketExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
ReflectionClass targetType = getTarget().resolveType(reflectionAnalyzer);
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
ModelClass targetType = getTarget().resolveType(modelAnalyzer);
|
||||
if (targetType.isArray()) {
|
||||
mAccessor = BracketAccessor.ARRAY;
|
||||
} else if (targetType.isList()) {
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -34,8 +34,8 @@ public class ComparisonExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
return reflectionAnalyzer.loadPrimitive("boolean");
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return modelAnalyzer.loadPrimitive("boolean");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
abstract public class Expr {
|
||||
|
||||
@@ -41,7 +41,7 @@ abstract public class Expr {
|
||||
|
||||
private Boolean mIsDynamic;
|
||||
|
||||
private ReflectionClass mResolvedType;
|
||||
private ModelClass mResolvedType;
|
||||
|
||||
private String mUniqueKey;
|
||||
|
||||
@@ -145,7 +145,7 @@ abstract public class Expr {
|
||||
}
|
||||
|
||||
public boolean isObservable() {
|
||||
return ReflectionAnalyzer.getInstance().isObservable(getResolvedType());
|
||||
return ModelAnalyzer.getInstance().isObservable(getResolvedType());
|
||||
}
|
||||
|
||||
public BitSet getShouldReadFlags() {
|
||||
@@ -278,15 +278,15 @@ abstract public class Expr {
|
||||
|
||||
}
|
||||
|
||||
public ReflectionClass getResolvedType() {
|
||||
public ModelClass getResolvedType() {
|
||||
if (mResolvedType == null) {
|
||||
// TODO not get instance
|
||||
mResolvedType = resolveType(ReflectionAnalyzer.getInstance());
|
||||
mResolvedType = resolveType(ModelAnalyzer.getInstance());
|
||||
}
|
||||
return mResolvedType;
|
||||
}
|
||||
|
||||
abstract protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer);
|
||||
abstract protected ModelClass resolveType(ModelAnalyzer modelAnalyzer);
|
||||
|
||||
abstract protected List<Dependency> constructDependencies();
|
||||
|
||||
@@ -535,7 +535,7 @@ abstract public class Expr {
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return ReflectionAnalyzer.getInstance().getDefaultValue(getResolvedType().toJavaCode());
|
||||
return ModelAnalyzer.getInstance().getDefaultValue(getResolvedType().toJavaCode());
|
||||
}
|
||||
|
||||
protected BitSet getPredicateInvalidFlags() {
|
||||
@@ -569,7 +569,7 @@ abstract public class Expr {
|
||||
return mIsUsed;
|
||||
}
|
||||
|
||||
public void updateExpr(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
public void updateExpr(ModelAnalyzer modelAnalyzer) {
|
||||
}
|
||||
|
||||
static class Node {
|
||||
|
||||
@@ -21,8 +21,7 @@ import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.util.L;
|
||||
import com.android.databinding.writer.FlagSet;
|
||||
|
||||
@@ -192,7 +191,7 @@ public class ExprModel {
|
||||
public void seal() {
|
||||
List<Expr> notifiableExpressions = new ArrayList<>();
|
||||
//ensure class analyzer. We need to know observables at this point
|
||||
final ReflectionAnalyzer reflectionAnalyzer = ReflectionAnalyzer.getInstance();
|
||||
final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
|
||||
|
||||
ArrayList<Expr> processedExprs = new ArrayList<>();
|
||||
ArrayList<Expr> exprs = new ArrayList<>();
|
||||
@@ -201,13 +200,13 @@ public class ExprModel {
|
||||
exprs.addAll(mExprMap.values());
|
||||
exprs.removeAll(processedExprs);
|
||||
for (Expr expr: exprs) {
|
||||
expr.updateExpr(reflectionAnalyzer);
|
||||
expr.updateExpr(modelAnalyzer);
|
||||
}
|
||||
processedExprs.addAll(exprs);
|
||||
} while (!exprs.isEmpty());
|
||||
|
||||
int counter = 0;
|
||||
final Iterable<Expr> observables = filterObservables(reflectionAnalyzer);
|
||||
final Iterable<Expr> observables = filterObservables(modelAnalyzer);
|
||||
List<String> flagMapping = Lists.newArrayList();
|
||||
mObservables = Lists.newArrayList();
|
||||
for (Expr expr : observables) {
|
||||
@@ -220,7 +219,7 @@ public class ExprModel {
|
||||
}
|
||||
|
||||
// non-observable identifiers gets next ids
|
||||
final Iterable<Expr> nonObservableIds = filterNonObservableIds(reflectionAnalyzer);
|
||||
final Iterable<Expr> nonObservableIds = filterNonObservableIds(modelAnalyzer);
|
||||
for (Expr expr : nonObservableIds) {
|
||||
flagMapping.add(expr.getUniqueKey());
|
||||
expr.setId(counter++);
|
||||
@@ -337,23 +336,23 @@ public class ExprModel {
|
||||
return mFlagMapping[id];
|
||||
}
|
||||
|
||||
private Iterable<Expr> filterNonObservableIds(final ReflectionAnalyzer reflectionAnalyzer) {
|
||||
private Iterable<Expr> filterNonObservableIds(final ModelAnalyzer modelAnalyzer) {
|
||||
return Iterables.filter(mExprMap.values(), new Predicate<Expr>() {
|
||||
@Override
|
||||
public boolean apply(Expr input) {
|
||||
return input instanceof IdentifierExpr
|
||||
&& !input.hasId()
|
||||
&& !reflectionAnalyzer.isObservable(input.getResolvedType())
|
||||
&& !modelAnalyzer.isObservable(input.getResolvedType())
|
||||
&& input.isDynamic();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Iterable<Expr> filterObservables(final ReflectionAnalyzer reflectionAnalyzer) {
|
||||
private Iterable<Expr> filterObservables(final ModelAnalyzer modelAnalyzer) {
|
||||
return Iterables.filter(mExprMap.values(), new Predicate<Expr>() {
|
||||
@Override
|
||||
public boolean apply(Expr input) {
|
||||
return reflectionAnalyzer.isObservable(input.getResolvedType());
|
||||
return modelAnalyzer.isObservable(input.getResolvedType());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
package com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.Callable;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class FieldAccessExpr extends Expr {
|
||||
@@ -87,10 +86,10 @@ public class FieldAccessExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExpr(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
public void updateExpr(ModelAnalyzer modelAnalyzer) {
|
||||
if (mGetter == null) {
|
||||
mGetter = reflectionAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName);
|
||||
if (reflectionAnalyzer.isObservableField(mGetter.resolvedType)) {
|
||||
mGetter = modelAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName);
|
||||
if (modelAnalyzer.isObservableField(mGetter.resolvedType)) {
|
||||
// Make this the ".get()" and add an extra field access for the observable field
|
||||
Expr parent = getParent();
|
||||
parent.getParents().remove(this);
|
||||
@@ -101,16 +100,16 @@ public class FieldAccessExpr extends Expr {
|
||||
|
||||
getChildren().add(observableField);
|
||||
observableField.getParents().add(this);
|
||||
mGetter = reflectionAnalyzer.findMethodOrField(mGetter.resolvedType, "get");
|
||||
mGetter = modelAnalyzer.findMethodOrField(mGetter.resolvedType, "get");
|
||||
mName = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
if (mGetter == null) {
|
||||
mGetter = reflectionAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName);
|
||||
mGetter = modelAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName);
|
||||
}
|
||||
return mGetter.resolvedType;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,8 +27,8 @@ public class GroupExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
return getWrapped().resolveType(reflectionAnalyzer);
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return getWrapped().resolveType(modelAnalyzer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.android.databinding.expr;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -58,10 +58,10 @@ public class IdentifierExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(final ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected ModelClass resolveType(final ModelAnalyzer modelAnalyzer) {
|
||||
Preconditions.checkNotNull(mUserDefinedType,
|
||||
"Identifiers must have user defined types from the XML file. %s is missing it", mName);
|
||||
return reflectionAnalyzer.findClass(mUserDefinedType);
|
||||
return modelAnalyzer.findClass(mUserDefinedType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -34,15 +34,15 @@ public class MathExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
if ("+".equals(mOp)) {
|
||||
// TODO we need upper casting etc.
|
||||
if (getLeft().getResolvedType().isString()
|
||||
|| getRight().getResolvedType().isString()) {
|
||||
return reflectionAnalyzer.findClass(String.class);
|
||||
return modelAnalyzer.findClass(String.class);
|
||||
}
|
||||
}
|
||||
return reflectionAnalyzer.findCommonParentOf(getLeft().getResolvedType(),
|
||||
return modelAnalyzer.findCommonParentOf(getLeft().getResolvedType(),
|
||||
getRight().getResolvedType());
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.android.databinding.expr;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.Callable;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -37,13 +37,13 @@ public class MethodCallExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
if (mGetter == null) {
|
||||
List<ReflectionClass> args = new ArrayList<>();
|
||||
List<ModelClass> args = new ArrayList<>();
|
||||
for (Expr expr : getArgs()) {
|
||||
args.add(expr.getResolvedType());
|
||||
}
|
||||
mGetter = reflectionAnalyzer.findMethod(getTarget().getResolvedType(), mName, args);
|
||||
mGetter = modelAnalyzer.findMethod(getTarget().getResolvedType(), mName, args);
|
||||
}
|
||||
return mGetter.resolvedType;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ package com.android.databinding.expr;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -60,7 +60,7 @@ public class ResourceExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
String type;
|
||||
switch (mResourceType) {
|
||||
case "anim":
|
||||
@@ -70,7 +70,7 @@ public class ResourceExpr extends Expr {
|
||||
type = "android.animation.Animator";
|
||||
break;
|
||||
case "bool":
|
||||
return reflectionAnalyzer.findClass(boolean.class);
|
||||
return modelAnalyzer.findClass(boolean.class);
|
||||
case "color":
|
||||
case "dimenOffset":
|
||||
case "dimenSize":
|
||||
@@ -78,18 +78,18 @@ public class ResourceExpr extends Expr {
|
||||
case "integer":
|
||||
case "layout":
|
||||
case "plurals":
|
||||
return reflectionAnalyzer.findClass(int.class);
|
||||
return modelAnalyzer.findClass(int.class);
|
||||
case "colorStateList":
|
||||
type = "android.content.res.ColorStateList";
|
||||
break;
|
||||
case "dimen":
|
||||
case "fraction":
|
||||
return reflectionAnalyzer.findClass(float.class);
|
||||
return modelAnalyzer.findClass(float.class);
|
||||
case "drawable":
|
||||
type = "android.graphics.drawable.Drawable";
|
||||
break;
|
||||
case "intArray":
|
||||
return reflectionAnalyzer.findClass(int[].class);
|
||||
return modelAnalyzer.findClass(int[].class);
|
||||
case "interpolator":
|
||||
type = "";
|
||||
break;
|
||||
@@ -97,9 +97,9 @@ public class ResourceExpr extends Expr {
|
||||
type = "android.animation.StateListAnimator";
|
||||
break;
|
||||
case "string":
|
||||
return reflectionAnalyzer.findClass(String.class);
|
||||
return modelAnalyzer.findClass(String.class);
|
||||
case "stringArray":
|
||||
return reflectionAnalyzer.findClass(String[].class);
|
||||
return modelAnalyzer.findClass(String[].class);
|
||||
case "transition":
|
||||
type = "android.transition.Transition";
|
||||
break;
|
||||
@@ -110,7 +110,7 @@ public class ResourceExpr extends Expr {
|
||||
type = mResourceType;
|
||||
break;
|
||||
}
|
||||
return reflectionAnalyzer.findClass(type);
|
||||
return modelAnalyzer.findClass(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.android.databinding.expr;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -38,8 +38,8 @@ public class SymbolExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
return reflectionAnalyzer.findClass(mType);
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return modelAnalyzer.findClass(mType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.android.databinding.expr;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
@@ -47,8 +47,8 @@ public class TernaryExpr extends Expr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReflectionClass resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
return reflectionAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(),
|
||||
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return modelAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(),
|
||||
getIfFalse().getResolvedType());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* 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 com.google.common.collect.ImmutableMap;
|
||||
|
||||
import com.android.databinding.util.L;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import android.binding.Bindable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
public class AnnotationAnalyzer extends ModelAnalyzer {
|
||||
|
||||
public static final String LIST_CLASS_NAME = "java.util.List";
|
||||
|
||||
public static final String MAP_CLASS_NAME = "java.util.Map";
|
||||
|
||||
public static final String STRING_CLASS_NAME = "java.lang.String";
|
||||
|
||||
public static final String OBJECT_CLASS_NAME = "java.lang.Object";
|
||||
|
||||
static AnnotationAnalyzer instance;
|
||||
private static final String OBSERVABLE_CLASS_NAME = "android.binding.Observable";
|
||||
private static final String OBSERVABLE_LIST_CLASS_NAME = "android.binding.ObservableList";
|
||||
private static final String OBSERVABLE_MAP_CLASS_NAME = "android.binding.ObservableMap";
|
||||
private static final String[] OBSERVABLE_FIELDS = {
|
||||
"com.android.databinding.library.ObservableBoolean",
|
||||
"com.android.databinding.library.ObservableByte",
|
||||
"com.android.databinding.library.ObservableChar",
|
||||
"com.android.databinding.library.ObservableShort",
|
||||
"com.android.databinding.library.ObservableInt",
|
||||
"com.android.databinding.library.ObservableLong",
|
||||
"com.android.databinding.library.ObservableFloat",
|
||||
"com.android.databinding.library.ObservableDouble",
|
||||
"com.android.databinding.library.ObservableField",
|
||||
};
|
||||
private static final String I_VIEW_DATA_BINDER = "com.android.databinding.library.IViewDataBinder";
|
||||
private static final Map<String, TypeKind> PRIMITIVE_TYPES =
|
||||
new ImmutableMap.Builder<String, TypeKind>()
|
||||
.put("boolean", TypeKind.BOOLEAN)
|
||||
.put("byte", TypeKind.BYTE)
|
||||
.put("short", TypeKind.SHORT)
|
||||
.put("char", TypeKind.CHAR)
|
||||
.put("int", TypeKind.INT)
|
||||
.put("long", TypeKind.LONG)
|
||||
.put("float", TypeKind.FLOAT)
|
||||
.put("double", TypeKind.DOUBLE)
|
||||
.build();
|
||||
|
||||
public final ProcessingEnvironment processingEnv;
|
||||
public final TypeMirror listType;
|
||||
public final TypeMirror mapType;
|
||||
public final TypeMirror stringType;
|
||||
public final TypeMirror objectType;
|
||||
|
||||
private final AnnotationClass mObservableType;
|
||||
private final AnnotationClass mObservableListType;
|
||||
private final AnnotationClass mObservableMapType;
|
||||
private final AnnotationClass[] mObservableFieldTypes;
|
||||
private final AnnotationClass mIViewDataBinderType;
|
||||
|
||||
public AnnotationAnalyzer(ProcessingEnvironment processingEnvironment) {
|
||||
processingEnv = processingEnvironment;
|
||||
instance = this;
|
||||
Types typeUtil = processingEnv.getTypeUtils();
|
||||
listType = typeUtil.erasure(findType(LIST_CLASS_NAME).asType());
|
||||
mapType = typeUtil.erasure(findType(MAP_CLASS_NAME).asType());
|
||||
stringType = typeUtil.erasure(findType(STRING_CLASS_NAME).asType());
|
||||
objectType = typeUtil.erasure(findType(OBJECT_CLASS_NAME).asType());
|
||||
mObservableType = new AnnotationClass(findType(OBSERVABLE_CLASS_NAME).asType());
|
||||
mObservableListType = new AnnotationClass(typeUtil.erasure(
|
||||
findType(OBSERVABLE_LIST_CLASS_NAME).asType()));
|
||||
mObservableMapType = new AnnotationClass(typeUtil.erasure(
|
||||
findType(OBSERVABLE_MAP_CLASS_NAME).asType()));
|
||||
mIViewDataBinderType = new AnnotationClass(findType(I_VIEW_DATA_BINDER).asType());
|
||||
mObservableFieldTypes = new AnnotationClass[OBSERVABLE_FIELDS.length];
|
||||
for (int i = 0; i < OBSERVABLE_FIELDS.length; i++) {
|
||||
mObservableFieldTypes[i] = new AnnotationClass(findType(OBSERVABLE_FIELDS[i]).asType());
|
||||
}
|
||||
}
|
||||
|
||||
TypeElement findType(String type) {
|
||||
return processingEnv.getElementUtils().getTypeElement(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataBinder(ModelClass modelClass) {
|
||||
return mIViewDataBinderType.isAssignableFrom(modelClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable findMethod(ModelClass modelClass, String name,
|
||||
List<ModelClass> args) {
|
||||
AnnotationClass clazz = (AnnotationClass)modelClass;
|
||||
// TODO implement properly
|
||||
for (String methodName : new String[]{"set" + StringUtils.capitalize(name), name}) {
|
||||
for (ModelMethod method : clazz.getMethods(methodName, args.size())) {
|
||||
ModelClass[] parameters = method.getParameterTypes();
|
||||
boolean parametersMatch = true;
|
||||
boolean isVarArgs = ((AnnotationMethod)method).mMethod.isVarArgs();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (isVarArgs && i == parameters.length - 1) {
|
||||
ModelClass component = parameters[i].getComponentType();
|
||||
for (int j = i; j < args.size(); j++) {
|
||||
if (!component.isAssignableFrom(args.get(j))) {
|
||||
parametersMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!parameters[i].isAssignableFrom(args.get(i))) {
|
||||
parametersMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parametersMatch) {
|
||||
return new Callable(Callable.Type.METHOD, methodName,
|
||||
method.getReturnType(args), true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
String message = "cannot find method " + name + " at class " + clazz.toJavaCode();
|
||||
printMessage(Diagnostic.Kind.ERROR, message);
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObservable(ModelClass modelClass) {
|
||||
AnnotationClass annotationClass = (AnnotationClass)modelClass;
|
||||
return mObservableType.isAssignableFrom(annotationClass) ||
|
||||
mObservableListType.isAssignableFrom(annotationClass) ||
|
||||
mObservableMapType.isAssignableFrom(annotationClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObservableField(ModelClass modelClass) {
|
||||
AnnotationClass annotationClass = (AnnotationClass)modelClass;
|
||||
AnnotationClass erasure = new AnnotationClass(getTypeUtils().erasure(annotationClass.mTypeMirror));
|
||||
for (AnnotationClass observableField : mObservableFieldTypes) {
|
||||
if (observableField.isAssignableFrom(erasure)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBindable(ModelField field) {
|
||||
VariableElement fieldElement = ((AnnotationField) field).mField;
|
||||
return fieldElement.getAnnotation(Bindable.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBindable(ModelMethod method) {
|
||||
ExecutableElement methodElement = ((AnnotationMethod) method).mMethod;
|
||||
return methodElement.getAnnotation(Bindable.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable findMethodOrField(ModelClass modelClass, String name) {
|
||||
AnnotationClass annotationClass = (AnnotationClass)modelClass;
|
||||
for (String methodName :
|
||||
new String[]{"get" + StringUtils.capitalize(name),
|
||||
"is" + StringUtils.capitalize(name), name}) {
|
||||
ModelMethod[] methods = modelClass.getMethods(methodName, 0);
|
||||
for (ModelMethod modelMethod : methods) {
|
||||
AnnotationMethod method = (AnnotationMethod) modelMethod;
|
||||
if (method.isPublic()) {
|
||||
final AnnotationField backingField = findField(annotationClass, name, true);
|
||||
final Callable result = new Callable(Callable.Type.METHOD, methodName,
|
||||
method.getReturnType(null), true, isBindable(method) ||
|
||||
(backingField != null && isBindable(backingField)));
|
||||
L.d("backing field for %s is %s", result, backingField);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationField field = findField(annotationClass, name, false);
|
||||
if (field != null && field.mField.getModifiers().contains(Modifier.PUBLIC)) {
|
||||
AnnotationClass fieldType = new AnnotationClass(field.mField.asType());
|
||||
return new Callable(Callable.Type.FIELD, name, fieldType,
|
||||
!field.mField.getModifiers().contains(Modifier.FINAL)
|
||||
|| isObservable(fieldType), isBindable(field));
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"cannot find " + name + " in " +
|
||||
((DeclaredType) annotationClass.mTypeMirror).asElement().getSimpleName());
|
||||
}
|
||||
|
||||
private AnnotationField findField(AnnotationClass clazz, String name, boolean allowNonPublic) {
|
||||
if (clazz == null || clazz.mTypeMirror.getKind() != TypeKind.DECLARED) {
|
||||
return null;
|
||||
}
|
||||
TypeElement typeElement = (TypeElement) ((DeclaredType) clazz.mTypeMirror).asElement();
|
||||
for (VariableElement field : ElementFilter.fieldsIn(
|
||||
getElementUtils().getAllMembers(typeElement))) {
|
||||
if (name.equals(stripFieldName(field.getSimpleName().toString()))) {
|
||||
if (allowNonPublic || field.getModifiers().contains(Modifier.PUBLIC)) {
|
||||
return new AnnotationField(typeElement, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null; // nothing found
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationClass loadPrimitive(String className) {
|
||||
TypeKind typeKind = PRIMITIVE_TYPES.get(className);
|
||||
if (typeKind == null) {
|
||||
return null;
|
||||
} else {
|
||||
Types typeUtils = getTypeUtils();
|
||||
return new AnnotationClass(typeUtils.getPrimitiveType(typeKind));
|
||||
}
|
||||
}
|
||||
|
||||
private static String stripFieldName(String fieldName) {
|
||||
if (fieldName.length() > 2) {
|
||||
final char start = fieldName.charAt(2);
|
||||
if (fieldName.startsWith("m_") && Character.isJavaIdentifierStart(start)) {
|
||||
return Character.toLowerCase(start) + fieldName.substring(3);
|
||||
}
|
||||
}
|
||||
if (fieldName.length() > 1) {
|
||||
final char start = fieldName.charAt(1);
|
||||
final char fieldIdentifier = fieldName.charAt(0);
|
||||
final boolean strip;
|
||||
if (fieldIdentifier == '_') {
|
||||
strip = true;
|
||||
} else if (fieldIdentifier == 'm' && Character.isJavaIdentifierStart(start) &&
|
||||
!Character.isLowerCase(start)) {
|
||||
strip = true;
|
||||
} else {
|
||||
strip = false; // not mUppercase format
|
||||
}
|
||||
if (strip) {
|
||||
return Character.toLowerCase(start) + fieldName.substring(2);
|
||||
}
|
||||
}
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationClass findClass(String className) {
|
||||
className = className.trim();
|
||||
int numDimensions = 0;
|
||||
while (className.endsWith("[]")) {
|
||||
numDimensions++;
|
||||
className = className.substring(0, className.length() - 2);
|
||||
}
|
||||
AnnotationClass primitive = loadPrimitive(className);
|
||||
if (primitive != null) {
|
||||
return addDimension(primitive.mTypeMirror, numDimensions);
|
||||
}
|
||||
int templateOpenIndex = className.indexOf('<');
|
||||
DeclaredType declaredType;
|
||||
if (templateOpenIndex < 0) {
|
||||
Elements elementUtils = getElementUtils();
|
||||
TypeElement typeElement = elementUtils.getTypeElement(className);
|
||||
declaredType = (DeclaredType) typeElement.asType();
|
||||
} else {
|
||||
int templateCloseIndex = className.lastIndexOf('>');
|
||||
String paramStr = className.substring(templateOpenIndex + 1, templateCloseIndex - 1);
|
||||
|
||||
Elements elementUtils = getElementUtils();
|
||||
String baseClassName = className.substring(0, templateOpenIndex);
|
||||
TypeElement typeElement = elementUtils.getTypeElement(baseClassName);
|
||||
|
||||
ArrayList<String> templateParameters = splitTemplateParameters(paramStr);
|
||||
TypeMirror[] typeArgs = new TypeMirror[templateParameters.size()];
|
||||
for (int i = 0; i < typeArgs.length; i++) {
|
||||
typeArgs[i] = findClass(templateParameters.get(i)).mTypeMirror;
|
||||
}
|
||||
|
||||
Types typeUtils = getTypeUtils();
|
||||
declaredType = typeUtils.getDeclaredType(typeElement, typeArgs);
|
||||
}
|
||||
return addDimension(declaredType, numDimensions);
|
||||
}
|
||||
|
||||
private AnnotationClass addDimension(TypeMirror type, int numDimensions) {
|
||||
while (numDimensions > 0) {
|
||||
type = getTypeUtils().getArrayType(type);
|
||||
numDimensions--;
|
||||
}
|
||||
return new AnnotationClass(type);
|
||||
}
|
||||
|
||||
private ArrayList<String> splitTemplateParameters(String templateParameters) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
int index = 0;
|
||||
int openCount = 0;
|
||||
StringBuilder arg = new StringBuilder();
|
||||
while (index < templateParameters.length()) {
|
||||
char c = templateParameters.charAt(index);
|
||||
if (c == ',' && openCount == 0) {
|
||||
list.add(arg.toString());
|
||||
arg.delete(0, arg.length());
|
||||
} else if (!Character.isWhitespace(c)) {
|
||||
arg.append(c);
|
||||
if (c == '<') {
|
||||
openCount++;
|
||||
} else if (c == '>') {
|
||||
openCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
list.add(arg.toString());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> getResources(String name) {
|
||||
ArrayList<URL> urls = new ArrayList<>();
|
||||
try {
|
||||
Enumeration<URL> resources = getClass().getClassLoader().getResources(name);
|
||||
while (resources.hasMoreElements()) {
|
||||
urls.add(resources.nextElement());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
printMessage(Diagnostic.Kind.ERROR, "IOException while getting resources: " +
|
||||
e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass findClass(Class classType) {
|
||||
return findClass(classType.getCanonicalName());
|
||||
}
|
||||
|
||||
public Types getTypeUtils() {
|
||||
return processingEnv.getTypeUtils();
|
||||
}
|
||||
|
||||
public Elements getElementUtils() {
|
||||
return processingEnv.getElementUtils();
|
||||
}
|
||||
|
||||
public void printMessage(Diagnostic.Kind kind, String message) {
|
||||
processingEnv.getMessager().printMessage(kind, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.ArrayType;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.PrimitiveType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
public class AnnotationClass implements ModelClass {
|
||||
|
||||
final TypeMirror mTypeMirror;
|
||||
|
||||
public AnnotationClass(TypeMirror typeMirror) {
|
||||
mTypeMirror = typeMirror;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJavaCode() {
|
||||
return toJavaCode(mTypeMirror);
|
||||
}
|
||||
|
||||
private static String toJavaCode(TypeMirror typeElement) {
|
||||
return typeElement.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return mTypeMirror.getKind() == TypeKind.ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationClass getComponentType() {
|
||||
TypeMirror component;
|
||||
if (isArray()) {
|
||||
component = ((ArrayType) mTypeMirror).getComponentType();
|
||||
} else if (isList()) {
|
||||
DeclaredType listType = findInterface(getListType());
|
||||
if (listType == null) {
|
||||
return null;
|
||||
}
|
||||
component = listType.getTypeArguments().get(0);
|
||||
} else {
|
||||
DeclaredType mapType = findInterface(getMapType());
|
||||
if (mapType == null) {
|
||||
return null;
|
||||
}
|
||||
component = mapType.getTypeArguments().get(1);
|
||||
}
|
||||
|
||||
return new AnnotationClass(component);
|
||||
}
|
||||
|
||||
private DeclaredType findInterface(TypeMirror interfaceType) {
|
||||
Types typeUtil = getTypeUtils();
|
||||
TypeMirror foundInterface = null;
|
||||
if (typeUtil.isSameType(interfaceType, typeUtil.erasure(mTypeMirror))) {
|
||||
foundInterface = mTypeMirror;
|
||||
} else if (mTypeMirror.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) mTypeMirror;
|
||||
TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
for (TypeMirror type : typeElement.getInterfaces()) {
|
||||
if (typeUtil.isSameType(interfaceType, typeUtil.erasure(type))) {
|
||||
foundInterface = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundInterface == null) {
|
||||
printMessage(Diagnostic.Kind.ERROR,
|
||||
"Detected " + interfaceType + " type for " + mTypeMirror +
|
||||
", but not able to find the implemented interface.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (foundInterface.getKind() != TypeKind.DECLARED) {
|
||||
printMessage(Diagnostic.Kind.ERROR,
|
||||
"Found " + interfaceType + " type for " + mTypeMirror +
|
||||
", but it isn't a declared type: " + foundInterface);
|
||||
return null;
|
||||
}
|
||||
return (DeclaredType) foundInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isList() {
|
||||
AnnotationAnalyzer analyzer = AnnotationAnalyzer.instance;
|
||||
Types typeUtil = getTypeUtils();
|
||||
return typeUtil.isAssignable(typeUtil.erasure(mTypeMirror), getListType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMap() {
|
||||
AnnotationAnalyzer analyzer = AnnotationAnalyzer.instance;
|
||||
Types typeUtil = getTypeUtils();
|
||||
return typeUtil.isAssignable(typeUtil.erasure(mTypeMirror), getMapType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isString() {
|
||||
return getTypeUtils().isSameType(mTypeMirror, getStringType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
switch (mTypeMirror.getKind()) {
|
||||
case ARRAY:
|
||||
case DECLARED:
|
||||
case NULL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimitive() {
|
||||
switch (mTypeMirror.getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INT:
|
||||
case LONG:
|
||||
case CHAR:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoolean() {
|
||||
return mTypeMirror.getKind() == TypeKind.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChar() {
|
||||
return mTypeMirror.getKind() == TypeKind.CHAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isByte() {
|
||||
return mTypeMirror.getKind() == TypeKind.BYTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShort() {
|
||||
return mTypeMirror.getKind() == TypeKind.SHORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInt() {
|
||||
return mTypeMirror.getKind() == TypeKind.INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLong() {
|
||||
return mTypeMirror.getKind() == TypeKind.LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFloat() {
|
||||
return mTypeMirror.getKind() == TypeKind.FLOAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDouble() {
|
||||
return mTypeMirror.getKind() == TypeKind.DOUBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return getTypeUtils().isSameType(mTypeMirror, getObjectType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVoid() {
|
||||
return mTypeMirror.getKind() == TypeKind.VOID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationClass unbox() {
|
||||
if (!isNullable()) {
|
||||
return this;
|
||||
}
|
||||
try {
|
||||
return new AnnotationClass(getTypeUtils().unboxedType(mTypeMirror));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// I'm being lazy. This is much easier than checking every type.
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass box() {
|
||||
if (!isPrimitive()) {
|
||||
return this;
|
||||
}
|
||||
return new AnnotationClass(getTypeUtils().boxedClass((PrimitiveType) mTypeMirror).asType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssignableFrom(ModelClass that) {
|
||||
TypeMirror thatType = ((AnnotationClass)that).mTypeMirror;
|
||||
return getTypeUtils().isAssignable(thatType, mTypeMirror);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelMethod[] getMethods(String name, int numParameters) {
|
||||
ArrayList<AnnotationMethod> matching = new ArrayList<>();
|
||||
if (mTypeMirror.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) mTypeMirror;
|
||||
getMethods(declaredType, matching, name, numParameters);
|
||||
}
|
||||
return matching.toArray(new ModelMethod[matching.size()]);
|
||||
}
|
||||
|
||||
private static void getMethods(DeclaredType declaredType, ArrayList<AnnotationMethod> methods,
|
||||
String name, int numParameters) {
|
||||
Elements elementUtils = getElementUtils();
|
||||
for (ExecutableElement element :
|
||||
ElementFilter.methodsIn(elementUtils.getAllMembers((TypeElement)declaredType.asElement()))) {
|
||||
if (element.getSimpleName().toString().equals(name)) {
|
||||
List<? extends VariableElement> parameters = element.getParameters();
|
||||
if (parameters.size() == numParameters ||
|
||||
(element.isVarArgs() && parameters.size() <= numParameters - 1)) {
|
||||
methods.add(new AnnotationMethod(declaredType, element));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationClass getSuperclass() {
|
||||
if (mTypeMirror.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) mTypeMirror;
|
||||
TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
TypeMirror superClass = typeElement.getSuperclass();
|
||||
if (superClass.getKind() == TypeKind.DECLARED) {
|
||||
return new AnnotationClass(superClass);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AnnotationClass) {
|
||||
return getTypeUtils().isSameType(mTypeMirror, ((AnnotationClass) obj).mTypeMirror);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mTypeMirror.toString().hashCode();
|
||||
}
|
||||
|
||||
private static Types getTypeUtils() {
|
||||
return AnnotationAnalyzer.instance.processingEnv.getTypeUtils();
|
||||
}
|
||||
|
||||
private static Elements getElementUtils() {
|
||||
return AnnotationAnalyzer.instance.processingEnv.getElementUtils();
|
||||
}
|
||||
|
||||
private static TypeMirror getListType() {
|
||||
return AnnotationAnalyzer.instance.listType;
|
||||
}
|
||||
|
||||
private static TypeMirror getMapType() {
|
||||
return AnnotationAnalyzer.instance.mapType;
|
||||
}
|
||||
|
||||
private static TypeMirror getStringType() {
|
||||
return AnnotationAnalyzer.instance.stringType;
|
||||
}
|
||||
|
||||
private static TypeMirror getObjectType() {
|
||||
return AnnotationAnalyzer.instance.objectType;
|
||||
}
|
||||
|
||||
private static void printMessage(Diagnostic.Kind kind, String message) {
|
||||
AnnotationAnalyzer.instance.printMessage(kind, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTypeMirror.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.databinding.reflection;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
|
||||
public class AnnotationField implements ModelField {
|
||||
|
||||
final VariableElement mField;
|
||||
|
||||
final TypeElement mDeclaredClass;
|
||||
|
||||
public AnnotationField(TypeElement declaredClass, VariableElement field) {
|
||||
mDeclaredClass = declaredClass;
|
||||
mField = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mField.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AnnotationField) {
|
||||
AnnotationField that = (AnnotationField) obj;
|
||||
return mDeclaredClass.equals(that.mDeclaredClass) && AnnotationAnalyzer.instance
|
||||
.getTypeUtils().isSameType(mField.asType(), that.mField.asType());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.util.List;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.ExecutableType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
public class AnnotationMethod implements ModelMethod {
|
||||
final ExecutableElement mMethod;
|
||||
final DeclaredType mDeclaringType;
|
||||
|
||||
public AnnotationMethod(DeclaredType declaringType, ExecutableElement method) {
|
||||
mDeclaringType = declaringType;
|
||||
mMethod = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass getDeclaringClass() {
|
||||
return new AnnotationClass(mDeclaringType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass[] getParameterTypes() {
|
||||
List<? extends VariableElement> parameters = mMethod.getParameters();
|
||||
ModelClass[] parameterTypes = new ModelClass[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
parameterTypes[i] = new AnnotationClass(parameters.get(i).asType());
|
||||
}
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mMethod.getSimpleName().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass getReturnType(List<ModelClass> args) {
|
||||
ExecutableType executableType = (ExecutableType) AnnotationAnalyzer.instance.getTypeUtils().asMemberOf(mDeclaringType, mMethod);
|
||||
TypeMirror returnType = executableType.getReturnType();
|
||||
// TODO: support argument-supplied types
|
||||
// for example: public T[] toArray(T[] arr)
|
||||
return new AnnotationClass(returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
return mMethod.getModifiers().contains(Modifier.PUBLIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return mMethod.getModifiers().contains(Modifier.STATIC);
|
||||
}
|
||||
}
|
||||
@@ -26,13 +26,13 @@ public class Callable {
|
||||
|
||||
public final String name;
|
||||
|
||||
public final ReflectionClass resolvedType;
|
||||
public final ModelClass resolvedType;
|
||||
|
||||
public final boolean isDynamic;
|
||||
|
||||
public final boolean canBeInvalidated;
|
||||
|
||||
public Callable(Type type, String name, ReflectionClass resolvedType, boolean isDynamic,
|
||||
public Callable(Type type, String name, ModelClass resolvedType, boolean isDynamic,
|
||||
boolean canBeInvalidated) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* 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 com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import com.android.databinding.store.SetterStore;
|
||||
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 extends ReflectionAnalyzer {
|
||||
|
||||
private static final String OBSERVABLE_CLASS_NAME = "android.binding.Observable";
|
||||
private static final String OBSERVABLE_LIST_CLASS_NAME = "android.binding.ObservableList";
|
||||
private static final String OBSERVABLE_MAP_CLASS_NAME = "android.binding.ObservableMap";
|
||||
private static final String BINDABLE_ANNOTATION_NAME = "android.binding.Bindable";
|
||||
private static final String[] OBSERVABLE_FIELDS = {
|
||||
"com.android.databinding.library.ObservableBoolean",
|
||||
"com.android.databinding.library.ObservableByte",
|
||||
"com.android.databinding.library.ObservableChar",
|
||||
"com.android.databinding.library.ObservableShort",
|
||||
"com.android.databinding.library.ObservableInt",
|
||||
"com.android.databinding.library.ObservableLong",
|
||||
"com.android.databinding.library.ObservableFloat",
|
||||
"com.android.databinding.library.ObservableDouble",
|
||||
"com.android.databinding.library.ObservableField",
|
||||
};
|
||||
private static final String I_VIEW_DATA_BINDER = "com.android.databinding.library.IViewDataBinder";
|
||||
|
||||
private static Map<String, String> sTestClassNameMapping = ImmutableMap.of(
|
||||
OBSERVABLE_CLASS_NAME, "com.android.databinding.MockObservable",
|
||||
BINDABLE_ANNOTATION_NAME, "com.android.databinding.MockBindable",
|
||||
OBSERVABLE_LIST_CLASS_NAME, "com.android.databinding.MockObservableLsit",
|
||||
OBSERVABLE_MAP_CLASS_NAME, "com.android.databinding.MockObservableMap",
|
||||
I_VIEW_DATA_BINDER, "com.android.databinding.MockIViewDataBinder"
|
||||
);
|
||||
|
||||
private static ClassAnalyzer sClassAnalyzer;
|
||||
|
||||
private static ClassLoader sClassLoader;
|
||||
|
||||
private HashMap<String, ClassClass> mClassCache = new HashMap<>();
|
||||
|
||||
private final ClassLoader mClassLoader;
|
||||
|
||||
private final Class mObservable;
|
||||
|
||||
private final Class mObservableList;
|
||||
|
||||
private final Class mObservableMap;
|
||||
|
||||
private final Class[] mObservableFields;
|
||||
|
||||
private final Class mBindable;
|
||||
|
||||
private final boolean mTestMode;
|
||||
|
||||
private final Class mIViewDataBinder;
|
||||
|
||||
private ClassAnalyzer(ClassLoader classLoader, boolean testMode) {
|
||||
mClassLoader = classLoader;
|
||||
mTestMode = testMode;
|
||||
try {
|
||||
mIViewDataBinder = classLoader.loadClass(getClassName(I_VIEW_DATA_BINDER));
|
||||
mObservable = classLoader.loadClass(getClassName(OBSERVABLE_CLASS_NAME));
|
||||
mObservableList = classLoader.loadClass(getClassName(OBSERVABLE_LIST_CLASS_NAME));
|
||||
mObservableMap = classLoader.loadClass(getClassName(OBSERVABLE_MAP_CLASS_NAME));
|
||||
mBindable = classLoader.loadClass(getClassName(BINDABLE_ANNOTATION_NAME));
|
||||
mObservableFields = new Class[OBSERVABLE_FIELDS.length];
|
||||
for (int i = 0; i < OBSERVABLE_FIELDS.length; i++) {
|
||||
mObservableFields[i] = classLoader.loadClass(getClassName(OBSERVABLE_FIELDS[i]));
|
||||
}
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setClassLoader(ClassLoader classLoader) {
|
||||
if (sClassAnalyzer != null) {
|
||||
throw new IllegalStateException("class analyzer is already created, you cannot "
|
||||
+ "change class loader after that");
|
||||
}
|
||||
L.d("setting class loader to %s", classLoader);
|
||||
sClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public static ClassAnalyzer getInstance() {
|
||||
if (sClassAnalyzer == null) {
|
||||
Preconditions.checkNotNull(sClassLoader,
|
||||
"cannot access class analyzer before class loader is ready");
|
||||
sClassAnalyzer = new ClassAnalyzer(sClassLoader, false);
|
||||
}
|
||||
return sClassAnalyzer;
|
||||
}
|
||||
|
||||
private String getClassName(String name) {
|
||||
if (mTestMode && sTestClassNameMapping.containsKey(name)) {
|
||||
return sTestClassNameMapping.get(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataBinder(ReflectionClass reflectionClass) {
|
||||
ClassClass classClass = (ClassClass) reflectionClass;
|
||||
return mIViewDataBinder.isAssignableFrom(classClass.mClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable findMethod(ReflectionClass reflectionClass, String name,
|
||||
List<ReflectionClass> argClasses) {
|
||||
Class klass = ((ClassClass) reflectionClass).mClass;
|
||||
ArrayList<Class> 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,
|
||||
new ClassClass(method.getReturnType()), true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
L.e(new Exception(), "cannot find method %s in %s", name, klass);
|
||||
throw new IllegalArgumentException(
|
||||
"cannot find method " + name + " at class " + klass.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObservable(ReflectionClass reflectionClass) {
|
||||
Class klass = ((ClassClass) reflectionClass).mClass;
|
||||
return isObservable(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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
private boolean isBindable(Method method) {
|
||||
return method.getAnnotation(mBindable) != null;
|
||||
}
|
||||
|
||||
@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}) {
|
||||
try {
|
||||
Method method = klass.getMethod(methodName);
|
||||
Field backingField = findField(klass, name, true);
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
final Callable result = new Callable(Callable.Type.METHOD, methodName,
|
||||
new ClassClass(method.getReturnType()), true,
|
||||
isBindable(method) || (backingField != null && isBindable(backingField)) );
|
||||
L.d("backing field for %s is %s", result, backingField);
|
||||
return result;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
try {
|
||||
Field field = findField(klass, name, false);
|
||||
if (Modifier.isPublic(field.getModifiers())) {
|
||||
return new Callable(Callable.Type.FIELD, name, new ClassClass(field.getType()),
|
||||
!Modifier.isFinal(field.getModifiers())
|
||||
|| isObservable(field.getType()), isBindable(field));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"cannot find " + name + " in " + klass.getCanonicalName());
|
||||
}
|
||||
|
||||
private Field findField(Class klass, String name, boolean allowNonPublic) {
|
||||
try {
|
||||
return getField(klass, name, allowNonPublic);
|
||||
} catch (NoSuchFieldException e) {
|
||||
|
||||
}
|
||||
String capitalizedName = StringUtils.capitalize(name);
|
||||
|
||||
try {
|
||||
return getField(klass, "m" + capitalizedName, allowNonPublic);
|
||||
} catch (Throwable t){}
|
||||
try {
|
||||
return getField(klass, "_" + name, allowNonPublic);
|
||||
} catch (Throwable t){}
|
||||
try {
|
||||
return getField(klass, "_" + capitalizedName, allowNonPublic);
|
||||
} catch (Throwable t){}
|
||||
try {
|
||||
return getField(klass, "m_" + name, allowNonPublic);
|
||||
} catch (Throwable t){}
|
||||
try {
|
||||
return getField(klass, "m_" + capitalizedName, allowNonPublic);
|
||||
} catch (Throwable t){}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Field getField(Class klass, String exactName, boolean allowNonPublic)
|
||||
throws NoSuchFieldException {
|
||||
try {
|
||||
return klass.getField(exactName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
if (allowNonPublic) {
|
||||
return klass.getDeclaredField(exactName);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ClassClass loadPrimitive(String className) {
|
||||
if ("int".equals(className)) {
|
||||
return new ClassClass(int.class);
|
||||
}
|
||||
if ("short".equals(className)) {
|
||||
return new ClassClass(short.class);
|
||||
}
|
||||
if ("long".equals(className)) {
|
||||
return new ClassClass(long.class);
|
||||
}
|
||||
if ("float".equals(className)) {
|
||||
return new ClassClass(float.class);
|
||||
}
|
||||
if ("double".equals(className)) {
|
||||
return new ClassClass(double.class);
|
||||
}
|
||||
if ("boolean".equals(className) || "bool".equals(className)) {
|
||||
return new ClassClass(boolean.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassClass findClass(String className) {
|
||||
ClassClass loaded = mClassCache.get(className);
|
||||
if (loaded != null) {
|
||||
return loaded;
|
||||
}
|
||||
L.d("trying to load class %s from %s", className, mClassLoader.toString());
|
||||
loaded = loadPrimitive(className);
|
||||
if (loaded == null) {
|
||||
try {
|
||||
if (className.startsWith("[") && className.contains("L")) {
|
||||
int indexOfL = className.indexOf('L');
|
||||
ClassClass baseClass = findClass(
|
||||
className.substring(indexOfL + 1, className.length() - 1));
|
||||
String realClassName = className.substring(0, indexOfL + 1) +
|
||||
baseClass.mClass.getCanonicalName() + ';';
|
||||
loaded = new ClassClass(Class.forName(realClassName, false, mClassLoader));
|
||||
mClassCache.put(className, loaded);
|
||||
} else {
|
||||
loaded = loadRecursively(className);
|
||||
mClassCache.put(className, loaded);
|
||||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
L.e(t, "cannot load class " + className);
|
||||
}
|
||||
}
|
||||
Preconditions.checkNotNull(loaded, "Tried to load " + className + " but could not find :/");
|
||||
L.d("loaded class %s", loaded.mClass.getCanonicalName());
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@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 new ClassClass(mClassLoader.loadClass(className));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
int lastIndexOfDot = className.lastIndexOf(".");
|
||||
if (lastIndexOfDot == -1) {
|
||||
throw ex;
|
||||
}
|
||||
return loadRecursively(className.substring(0, lastIndexOfDot) + "$" + className
|
||||
.substring(lastIndexOfDot + 1));
|
||||
}
|
||||
}
|
||||
|
||||
public static void initForTests() {
|
||||
if (sClassAnalyzer == null) {
|
||||
setClassLoader(ClassLoader.getSystemClassLoader());
|
||||
sClassAnalyzer = new ClassAnalyzer(sClassLoader, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> getResources(String name) {
|
||||
List<URL> urlList = new ArrayList<URL>();
|
||||
Enumeration<URL> urls = null;
|
||||
try {
|
||||
urls = mClassLoader.getResources(name);
|
||||
if (urls != null) {
|
||||
while (urls.hasMoreElements()) {
|
||||
urlList.add(urls.nextElement());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return urlList;
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* 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<ReflectionMethod> 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();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
import java.util.List;
|
||||
|
||||
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(List<ReflectionClass> args) {
|
||||
return new ClassClass(mMethod.getReturnType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
return Modifier.isPublic(mMethod.getModifiers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return Modifier.isStatic(mMethod.getModifiers());
|
||||
}
|
||||
}
|
||||
@@ -15,381 +15,92 @@
|
||||
*/
|
||||
package com.android.databinding.reflection;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import com.android.databinding.util.L;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import android.binding.Bindable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
public class ModelAnalyzer extends ReflectionAnalyzer {
|
||||
public abstract class ModelAnalyzer {
|
||||
private static ModelAnalyzer sAnalyzer;
|
||||
|
||||
public static final String LIST_CLASS_NAME = "java.util.List";
|
||||
public abstract boolean isDataBinder(ModelClass modelClass);
|
||||
|
||||
public static final String MAP_CLASS_NAME = "java.util.Map";
|
||||
public abstract Callable findMethod(ModelClass modelClass, String name,
|
||||
List<ModelClass> args);
|
||||
|
||||
public static final String STRING_CLASS_NAME = "java.lang.String";
|
||||
public abstract boolean isObservable(ModelClass modelClass);
|
||||
|
||||
public static final String OBJECT_CLASS_NAME = "java.lang.Object";
|
||||
public abstract boolean isObservableField(ModelClass modelClass);
|
||||
|
||||
static ModelAnalyzer instance;
|
||||
private static final String OBSERVABLE_CLASS_NAME = "android.binding.Observable";
|
||||
private static final String OBSERVABLE_LIST_CLASS_NAME = "android.binding.ObservableList";
|
||||
private static final String OBSERVABLE_MAP_CLASS_NAME = "android.binding.ObservableMap";
|
||||
private static final String[] OBSERVABLE_FIELDS = {
|
||||
"com.android.databinding.library.ObservableBoolean",
|
||||
"com.android.databinding.library.ObservableByte",
|
||||
"com.android.databinding.library.ObservableChar",
|
||||
"com.android.databinding.library.ObservableShort",
|
||||
"com.android.databinding.library.ObservableInt",
|
||||
"com.android.databinding.library.ObservableLong",
|
||||
"com.android.databinding.library.ObservableFloat",
|
||||
"com.android.databinding.library.ObservableDouble",
|
||||
"com.android.databinding.library.ObservableField",
|
||||
};
|
||||
private static final String I_VIEW_DATA_BINDER = "com.android.databinding.library.IViewDataBinder";
|
||||
private static final Map<String, TypeKind> PRIMITIVE_TYPES =
|
||||
new ImmutableMap.Builder<String, TypeKind>()
|
||||
.put("boolean", TypeKind.BOOLEAN)
|
||||
.put("byte", TypeKind.BYTE)
|
||||
.put("short", TypeKind.SHORT)
|
||||
.put("char", TypeKind.CHAR)
|
||||
.put("int", TypeKind.INT)
|
||||
.put("long", TypeKind.LONG)
|
||||
.put("float", TypeKind.FLOAT)
|
||||
.put("double", TypeKind.DOUBLE)
|
||||
.build();
|
||||
public abstract boolean isBindable(ModelField field);
|
||||
|
||||
public final ProcessingEnvironment processingEnv;
|
||||
public final TypeMirror listType;
|
||||
public final TypeMirror mapType;
|
||||
public final TypeMirror stringType;
|
||||
public final TypeMirror objectType;
|
||||
public abstract boolean isBindable(ModelMethod method);
|
||||
|
||||
private final ModelClass mObservableType;
|
||||
private final ModelClass mObservableListType;
|
||||
private final ModelClass mObservableMapType;
|
||||
private final ModelClass[] mObservableFieldTypes;
|
||||
private final ModelClass mIViewDataBinderType;
|
||||
public abstract Callable findMethodOrField(ModelClass modelClass, String name);
|
||||
|
||||
public ModelAnalyzer(ProcessingEnvironment processingEnvironment) {
|
||||
processingEnv = processingEnvironment;
|
||||
instance = this;
|
||||
Types typeUtil = processingEnv.getTypeUtils();
|
||||
listType = typeUtil.erasure(findType(LIST_CLASS_NAME).asType());
|
||||
mapType = typeUtil.erasure(findType(MAP_CLASS_NAME).asType());
|
||||
stringType = typeUtil.erasure(findType(STRING_CLASS_NAME).asType());
|
||||
objectType = typeUtil.erasure(findType(OBJECT_CLASS_NAME).asType());
|
||||
mObservableType = new ModelClass(findType(OBSERVABLE_CLASS_NAME).asType());
|
||||
mObservableListType = new ModelClass(typeUtil.erasure(findType(OBSERVABLE_LIST_CLASS_NAME).asType()));
|
||||
mObservableMapType = new ModelClass(typeUtil.erasure(
|
||||
findType(OBSERVABLE_MAP_CLASS_NAME).asType()));
|
||||
mIViewDataBinderType = new ModelClass(findType(I_VIEW_DATA_BINDER).asType());
|
||||
mObservableFieldTypes = new ModelClass[OBSERVABLE_FIELDS.length];
|
||||
for (int i = 0; i < OBSERVABLE_FIELDS.length; i++) {
|
||||
mObservableFieldTypes[i] = new ModelClass(findType(OBSERVABLE_FIELDS[i]).asType());
|
||||
public ModelClass findCommonParentOf(ModelClass modelClass1,
|
||||
ModelClass modelClass2) {
|
||||
ModelClass curr = modelClass1;
|
||||
while (curr != null && !curr.isAssignableFrom(modelClass2)) {
|
||||
curr = curr.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
TypeElement findType(String type) {
|
||||
return processingEnv.getElementUtils().getTypeElement(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataBinder(ReflectionClass reflectionClass) {
|
||||
return mIViewDataBinderType.isAssignableFrom(reflectionClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflectionClass findCommonParentOf(ReflectionClass reflectionClass1,
|
||||
ReflectionClass reflectionClass2) {
|
||||
return super.findCommonParentOf(toModel(reflectionClass1), toModel(reflectionClass2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable findMethod(ReflectionClass reflectionClass, String name,
|
||||
List<ReflectionClass> args) {
|
||||
ModelClass clazz = toModel(reflectionClass);
|
||||
// TODO implement properly
|
||||
for (String methodName : new String[]{"set" + StringUtils.capitalize(name), name}) {
|
||||
for (ReflectionMethod method : clazz.getMethods(methodName, args.size())) {
|
||||
ReflectionClass[] parameters = method.getParameterTypes();
|
||||
boolean parametersMatch = true;
|
||||
boolean isVarArgs = ((ModelMethod)method).mMethod.isVarArgs();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (isVarArgs && i == parameters.length - 1) {
|
||||
ReflectionClass component = parameters[i].getComponentType();
|
||||
for (int j = i; j < args.size(); j++) {
|
||||
if (!component.isAssignableFrom(args.get(j))) {
|
||||
parametersMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!parameters[i].isAssignableFrom(args.get(i))) {
|
||||
parametersMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parametersMatch) {
|
||||
return new Callable(Callable.Type.METHOD, methodName,
|
||||
method.getReturnType(args), true, false);
|
||||
}
|
||||
if (curr == null) {
|
||||
ModelClass primitive1 = modelClass1.unbox();
|
||||
ModelClass primitive2 = modelClass2.unbox();
|
||||
if (!modelClass1.equals(primitive1) || !modelClass2.equals(primitive2)) {
|
||||
return findCommonParentOf(primitive1, primitive2);
|
||||
}
|
||||
}
|
||||
String message = "cannot find method " + name + " at class " + clazz.toJavaCode();
|
||||
printMessage(Diagnostic.Kind.ERROR, message);
|
||||
throw new IllegalArgumentException(message);
|
||||
Preconditions.checkNotNull(curr,
|
||||
"must be able to find a common parent for " + modelClass1 + " and " + modelClass2);
|
||||
return curr;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObservable(ReflectionClass reflectionClass) {
|
||||
return mObservableType.isAssignableFrom(reflectionClass) ||
|
||||
mObservableListType.isAssignableFrom(reflectionClass) ||
|
||||
mObservableMapType.isAssignableFrom(reflectionClass);
|
||||
public abstract ModelClass loadPrimitive(String className);
|
||||
|
||||
public static ModelAnalyzer getInstance() {
|
||||
return sAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObservableField(ReflectionClass reflectionClass) {
|
||||
ModelClass modelClass = toModel(reflectionClass);
|
||||
ModelClass erasure = new ModelClass(getTypeUtils().erasure(modelClass.mTypeMirror));
|
||||
for (ModelClass observableField : mObservableFieldTypes) {
|
||||
if (observableField.isAssignableFrom(erasure)) {
|
||||
return true;
|
||||
}
|
||||
public static void setProcessingEnvironment(ProcessingEnvironment processingEnvironment) {
|
||||
AnnotationAnalyzer annotationAnalyzer = new AnnotationAnalyzer(processingEnvironment);
|
||||
sAnalyzer = annotationAnalyzer;
|
||||
}
|
||||
|
||||
public String getDefaultValue(String className) {
|
||||
if("int".equals(className)) {
|
||||
return "0";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBindable(ReflectionField field) {
|
||||
VariableElement fieldElement = ((ModelField) field).mField;
|
||||
return fieldElement.getAnnotation(Bindable.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBindable(ReflectionMethod method) {
|
||||
ExecutableElement methodElement = ((ModelMethod) method).mMethod;
|
||||
return methodElement.getAnnotation(Bindable.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callable findMethodOrField(ReflectionClass reflectionClass, String name) {
|
||||
ModelClass modelClass = toModel(reflectionClass);
|
||||
for (String methodName :
|
||||
new String[]{"get" + StringUtils.capitalize(name),
|
||||
"is" + StringUtils.capitalize(name), name}) {
|
||||
ReflectionMethod[] methods = reflectionClass.getMethods(methodName, 0);
|
||||
for (ReflectionMethod reflectionMethod : methods) {
|
||||
ModelMethod method = (ModelMethod) reflectionMethod;
|
||||
if (method.isPublic()) {
|
||||
final ModelField backingField = findField(modelClass, name, true);
|
||||
final Callable result = new Callable(Callable.Type.METHOD, methodName,
|
||||
method.getReturnType(null), true, isBindable(method) ||
|
||||
(backingField != null && isBindable(backingField)));
|
||||
L.d("backing field for %s is %s", result, backingField);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if("short".equals(className)) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
ModelField field = findField(modelClass, name, false);
|
||||
if (field != null && field.mField.getModifiers().contains(Modifier.PUBLIC)) {
|
||||
ModelClass fieldType = new ModelClass(field.mField.asType());
|
||||
return new Callable(Callable.Type.FIELD, name, fieldType,
|
||||
!field.mField.getModifiers().contains(Modifier.FINAL)
|
||||
|| isObservable(fieldType), isBindable(field));
|
||||
if("long".equals(className)) {
|
||||
return "0L";
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"cannot find " + name + " in " +
|
||||
((DeclaredType)modelClass.mTypeMirror).asElement().getSimpleName());
|
||||
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";
|
||||
}
|
||||
|
||||
private ModelField findField(ModelClass clazz, String name, boolean allowNonPublic) {
|
||||
if (clazz == null || clazz.mTypeMirror.getKind() != TypeKind.DECLARED) {
|
||||
return null;
|
||||
}
|
||||
TypeElement typeElement = (TypeElement) ((DeclaredType) clazz.mTypeMirror).asElement();
|
||||
for (VariableElement field : ElementFilter.fieldsIn(
|
||||
getElementUtils().getAllMembers(typeElement))) {
|
||||
if (name.equals(stripFieldName(field.getSimpleName().toString()))) {
|
||||
if (allowNonPublic || field.getModifiers().contains(Modifier.PUBLIC)) {
|
||||
return new ModelField(typeElement, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null; // nothing found
|
||||
}
|
||||
public abstract ModelClass findClass(String className);
|
||||
|
||||
@Override
|
||||
public ModelClass loadPrimitive(String className) {
|
||||
TypeKind typeKind = PRIMITIVE_TYPES.get(className);
|
||||
if (typeKind == null) {
|
||||
return null;
|
||||
} else {
|
||||
Types typeUtils = getTypeUtils();
|
||||
return new ModelClass(typeUtils.getPrimitiveType(typeKind));
|
||||
}
|
||||
}
|
||||
public abstract List<URL> getResources(String name);
|
||||
|
||||
private static String stripFieldName(String fieldName) {
|
||||
if (fieldName.length() > 2) {
|
||||
final char start = fieldName.charAt(2);
|
||||
if (fieldName.startsWith("m_") && Character.isJavaIdentifierStart(start)) {
|
||||
return Character.toLowerCase(start) + fieldName.substring(3);
|
||||
}
|
||||
}
|
||||
if (fieldName.length() > 1) {
|
||||
final char start = fieldName.charAt(1);
|
||||
final char fieldIdentifier = fieldName.charAt(0);
|
||||
final boolean strip;
|
||||
if (fieldIdentifier == '_') {
|
||||
strip = true;
|
||||
} else if (fieldIdentifier == 'm' && Character.isJavaIdentifierStart(start) &&
|
||||
!Character.isLowerCase(start)) {
|
||||
strip = true;
|
||||
} else {
|
||||
strip = false; // not mUppercase format
|
||||
}
|
||||
if (strip) {
|
||||
return Character.toLowerCase(start) + fieldName.substring(2);
|
||||
}
|
||||
}
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass findClass(String className) {
|
||||
className = className.trim();
|
||||
int numDimensions = 0;
|
||||
while (className.endsWith("[]")) {
|
||||
numDimensions++;
|
||||
className = className.substring(0, className.length() - 2);
|
||||
}
|
||||
ModelClass primitive = loadPrimitive(className);
|
||||
if (primitive != null) {
|
||||
return addDimension(primitive.mTypeMirror, numDimensions);
|
||||
}
|
||||
int templateOpenIndex = className.indexOf('<');
|
||||
DeclaredType declaredType;
|
||||
if (templateOpenIndex < 0) {
|
||||
Elements elementUtils = getElementUtils();
|
||||
TypeElement typeElement = elementUtils.getTypeElement(className);
|
||||
declaredType = (DeclaredType) typeElement.asType();
|
||||
} else {
|
||||
int templateCloseIndex = className.lastIndexOf('>');
|
||||
String paramStr = className.substring(templateOpenIndex + 1, templateCloseIndex - 1);
|
||||
|
||||
Elements elementUtils = getElementUtils();
|
||||
String baseClassName = className.substring(0, templateOpenIndex);
|
||||
TypeElement typeElement = elementUtils.getTypeElement(baseClassName);
|
||||
|
||||
ArrayList<String> templateParameters = splitTemplateParameters(paramStr);
|
||||
TypeMirror[] typeArgs = new TypeMirror[templateParameters.size()];
|
||||
for (int i = 0; i < typeArgs.length; i++) {
|
||||
typeArgs[i] = findClass(templateParameters.get(i)).mTypeMirror;
|
||||
}
|
||||
|
||||
Types typeUtils = getTypeUtils();
|
||||
declaredType = typeUtils.getDeclaredType(typeElement, typeArgs);
|
||||
}
|
||||
return addDimension(declaredType, numDimensions);
|
||||
}
|
||||
|
||||
private ModelClass addDimension(TypeMirror type, int numDimensions) {
|
||||
while (numDimensions > 0) {
|
||||
type = getTypeUtils().getArrayType(type);
|
||||
numDimensions--;
|
||||
}
|
||||
return new ModelClass(type);
|
||||
}
|
||||
|
||||
private ArrayList<String> splitTemplateParameters(String templateParameters) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
int index = 0;
|
||||
int openCount = 0;
|
||||
StringBuilder arg = new StringBuilder();
|
||||
while (index < templateParameters.length()) {
|
||||
char c = templateParameters.charAt(index);
|
||||
if (c == ',' && openCount == 0) {
|
||||
list.add(arg.toString());
|
||||
arg.delete(0, arg.length());
|
||||
} else if (!Character.isWhitespace(c)) {
|
||||
arg.append(c);
|
||||
if (c == '<') {
|
||||
openCount++;
|
||||
} else if (c == '>') {
|
||||
openCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
list.add(arg.toString());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> getResources(String name) {
|
||||
ArrayList<URL> urls = new ArrayList<>();
|
||||
try {
|
||||
Enumeration<URL> resources = getClass().getClassLoader().getResources(name);
|
||||
while (resources.hasMoreElements()) {
|
||||
urls.add(resources.nextElement());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
printMessage(Diagnostic.Kind.ERROR, "IOException while getting resources: " +
|
||||
e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflectionClass findClass(Class classType) {
|
||||
return new ClassClass(classType);
|
||||
}
|
||||
|
||||
public Types getTypeUtils() {
|
||||
return processingEnv.getTypeUtils();
|
||||
}
|
||||
|
||||
public Elements getElementUtils() {
|
||||
return processingEnv.getElementUtils();
|
||||
}
|
||||
|
||||
public void printMessage(Diagnostic.Kind kind, String message) {
|
||||
processingEnv.getMessager().printMessage(kind, message);
|
||||
}
|
||||
|
||||
public ModelClass toModel(ReflectionClass reflectionClass) {
|
||||
if (reflectionClass instanceof ClassClass) {
|
||||
String name = ((ClassClass) reflectionClass).mClass.getCanonicalName();
|
||||
return findClass(name);
|
||||
} else {
|
||||
return (ModelClass) reflectionClass;
|
||||
}
|
||||
}
|
||||
public abstract ModelClass findClass(Class classType);
|
||||
}
|
||||
|
||||
@@ -15,305 +15,51 @@
|
||||
*/
|
||||
package com.android.databinding.reflection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
public interface ModelClass {
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.ArrayType;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.PrimitiveType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic;
|
||||
String toJavaCode();
|
||||
|
||||
public class ModelClass implements ReflectionClass {
|
||||
boolean isArray();
|
||||
|
||||
final TypeMirror mTypeMirror;
|
||||
ModelClass getComponentType();
|
||||
|
||||
public ModelClass(TypeMirror typeMirror) {
|
||||
mTypeMirror = typeMirror;
|
||||
}
|
||||
boolean isList();
|
||||
|
||||
@Override
|
||||
public String toJavaCode() {
|
||||
return toJavaCode(mTypeMirror);
|
||||
}
|
||||
boolean isMap();
|
||||
|
||||
private static String toJavaCode(TypeMirror typeElement) {
|
||||
return typeElement.toString();
|
||||
}
|
||||
boolean isString();
|
||||
|
||||
@Override
|
||||
public boolean isArray() {
|
||||
return mTypeMirror.getKind() == TypeKind.ARRAY;
|
||||
}
|
||||
boolean isNullable();
|
||||
|
||||
@Override
|
||||
public ModelClass getComponentType() {
|
||||
TypeMirror component;
|
||||
if (isArray()) {
|
||||
component = ((ArrayType) mTypeMirror).getComponentType();
|
||||
} else if (isList()) {
|
||||
DeclaredType listType = findInterface(getListType());
|
||||
if (listType == null) {
|
||||
return null;
|
||||
}
|
||||
component = listType.getTypeArguments().get(0);
|
||||
} else {
|
||||
DeclaredType mapType = findInterface(getMapType());
|
||||
if (mapType == null) {
|
||||
return null;
|
||||
}
|
||||
component = mapType.getTypeArguments().get(1);
|
||||
}
|
||||
boolean isPrimitive();
|
||||
|
||||
return new ModelClass(component);
|
||||
}
|
||||
boolean isBoolean();
|
||||
|
||||
private DeclaredType findInterface(TypeMirror interfaceType) {
|
||||
Types typeUtil = getTypeUtils();
|
||||
TypeMirror foundInterface = null;
|
||||
if (typeUtil.isSameType(interfaceType, typeUtil.erasure(mTypeMirror))) {
|
||||
foundInterface = mTypeMirror;
|
||||
} else if (mTypeMirror.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) mTypeMirror;
|
||||
TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
for (TypeMirror type : typeElement.getInterfaces()) {
|
||||
if (typeUtil.isSameType(interfaceType, typeUtil.erasure(type))) {
|
||||
foundInterface = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundInterface == null) {
|
||||
printMessage(Diagnostic.Kind.ERROR,
|
||||
"Detected " + interfaceType + " type for " + mTypeMirror +
|
||||
", but not able to find the implemented interface.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (foundInterface.getKind() != TypeKind.DECLARED) {
|
||||
printMessage(Diagnostic.Kind.ERROR,
|
||||
"Found " + interfaceType + " type for " + mTypeMirror +
|
||||
", but it isn't a declared type: " + foundInterface);
|
||||
return null;
|
||||
}
|
||||
return (DeclaredType) foundInterface;
|
||||
}
|
||||
boolean isChar();
|
||||
|
||||
@Override
|
||||
public boolean isList() {
|
||||
ModelAnalyzer analyzer = ModelAnalyzer.instance;
|
||||
Types typeUtil = getTypeUtils();
|
||||
return typeUtil.isAssignable(typeUtil.erasure(mTypeMirror), getListType());
|
||||
}
|
||||
boolean isByte();
|
||||
|
||||
@Override
|
||||
public boolean isMap() {
|
||||
ModelAnalyzer analyzer = ModelAnalyzer.instance;
|
||||
Types typeUtil = getTypeUtils();
|
||||
return typeUtil.isAssignable(typeUtil.erasure(mTypeMirror), getMapType());
|
||||
}
|
||||
boolean isShort();
|
||||
|
||||
@Override
|
||||
public boolean isString() {
|
||||
return getTypeUtils().isSameType(mTypeMirror, getStringType());
|
||||
}
|
||||
boolean isInt();
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
switch (mTypeMirror.getKind()) {
|
||||
case ARRAY:
|
||||
case DECLARED:
|
||||
case NULL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean isLong();
|
||||
|
||||
@Override
|
||||
public boolean isPrimitive() {
|
||||
switch (mTypeMirror.getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INT:
|
||||
case LONG:
|
||||
case CHAR:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean isFloat();
|
||||
|
||||
@Override
|
||||
public boolean isBoolean() {
|
||||
return mTypeMirror.getKind() == TypeKind.BOOLEAN;
|
||||
}
|
||||
boolean isDouble();
|
||||
|
||||
@Override
|
||||
public boolean isChar() {
|
||||
return mTypeMirror.getKind() == TypeKind.CHAR;
|
||||
}
|
||||
boolean isObject();
|
||||
|
||||
@Override
|
||||
public boolean isByte() {
|
||||
return mTypeMirror.getKind() == TypeKind.BYTE;
|
||||
}
|
||||
boolean isVoid();
|
||||
|
||||
@Override
|
||||
public boolean isShort() {
|
||||
return mTypeMirror.getKind() == TypeKind.SHORT;
|
||||
}
|
||||
ModelClass unbox();
|
||||
|
||||
@Override
|
||||
public boolean isInt() {
|
||||
return mTypeMirror.getKind() == TypeKind.INT;
|
||||
}
|
||||
ModelClass box();
|
||||
|
||||
@Override
|
||||
public boolean isLong() {
|
||||
return mTypeMirror.getKind() == TypeKind.LONG;
|
||||
}
|
||||
boolean isAssignableFrom(ModelClass that);
|
||||
|
||||
@Override
|
||||
public boolean isFloat() {
|
||||
return mTypeMirror.getKind() == TypeKind.FLOAT;
|
||||
}
|
||||
ModelMethod[] getMethods(String name, int numParameters);
|
||||
|
||||
@Override
|
||||
public boolean isDouble() {
|
||||
return mTypeMirror.getKind() == TypeKind.DOUBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isObject() {
|
||||
return getTypeUtils().isSameType(mTypeMirror, getObjectType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVoid() {
|
||||
return mTypeMirror.getKind() == TypeKind.VOID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass unbox() {
|
||||
if (!isNullable()) {
|
||||
return this;
|
||||
}
|
||||
try {
|
||||
return new ModelClass(getTypeUtils().unboxedType(mTypeMirror));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// I'm being lazy. This is much easier than checking every type.
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflectionClass box() {
|
||||
if (!isPrimitive()) {
|
||||
return this;
|
||||
}
|
||||
return new ModelClass(getTypeUtils().boxedClass((PrimitiveType) mTypeMirror).asType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssignableFrom(ReflectionClass that) {
|
||||
TypeMirror thatType = ModelAnalyzer.instance.toModel(that).mTypeMirror;
|
||||
return getTypeUtils().isAssignable(thatType, mTypeMirror);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflectionMethod[] getMethods(String name, int numParameters) {
|
||||
ArrayList<ModelMethod> matching = new ArrayList<>();
|
||||
if (mTypeMirror.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) mTypeMirror;
|
||||
getMethods(declaredType, matching, name, numParameters);
|
||||
}
|
||||
return matching.toArray(new ReflectionMethod[matching.size()]);
|
||||
}
|
||||
|
||||
private static void getMethods(DeclaredType declaredType, ArrayList<ModelMethod> methods,
|
||||
String name, int numParameters) {
|
||||
Elements elementUtils = getElementUtils();
|
||||
for (ExecutableElement element :
|
||||
ElementFilter.methodsIn(elementUtils.getAllMembers((TypeElement)declaredType.asElement()))) {
|
||||
if (element.getSimpleName().toString().equals(name)) {
|
||||
List<? extends VariableElement> parameters = element.getParameters();
|
||||
if (parameters.size() == numParameters ||
|
||||
(element.isVarArgs() && parameters.size() <= numParameters - 1)) {
|
||||
methods.add(new ModelMethod(declaredType, element));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelClass getSuperclass() {
|
||||
if (mTypeMirror.getKind() == TypeKind.DECLARED) {
|
||||
DeclaredType declaredType = (DeclaredType) mTypeMirror;
|
||||
TypeElement typeElement = (TypeElement) declaredType.asElement();
|
||||
TypeMirror superClass = typeElement.getSuperclass();
|
||||
if (superClass.getKind() == TypeKind.DECLARED) {
|
||||
return new ModelClass(superClass);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ModelClass) {
|
||||
return getTypeUtils().isSameType(mTypeMirror, ((ModelClass) obj).mTypeMirror);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mTypeMirror.toString().hashCode();
|
||||
}
|
||||
|
||||
private static Types getTypeUtils() {
|
||||
return ModelAnalyzer.instance.processingEnv.getTypeUtils();
|
||||
}
|
||||
|
||||
private static Elements getElementUtils() {
|
||||
return ModelAnalyzer.instance.processingEnv.getElementUtils();
|
||||
}
|
||||
|
||||
private static TypeMirror getListType() {
|
||||
return ModelAnalyzer.instance.listType;
|
||||
}
|
||||
|
||||
private static TypeMirror getMapType() {
|
||||
return ModelAnalyzer.instance.mapType;
|
||||
}
|
||||
|
||||
private static TypeMirror getStringType() {
|
||||
return ModelAnalyzer.instance.stringType;
|
||||
}
|
||||
|
||||
private static TypeMirror getObjectType() {
|
||||
return ModelAnalyzer.instance.objectType;
|
||||
}
|
||||
|
||||
private static void printMessage(Diagnostic.Kind kind, String message) {
|
||||
ModelAnalyzer.instance.printMessage(kind, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTypeMirror.toString();
|
||||
}
|
||||
ModelClass getSuperclass();
|
||||
}
|
||||
|
||||
@@ -15,33 +15,5 @@
|
||||
*/
|
||||
package com.android.databinding.reflection;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
|
||||
public class ModelField implements ReflectionField {
|
||||
|
||||
final VariableElement mField;
|
||||
|
||||
final TypeElement mDeclaredClass;
|
||||
|
||||
public ModelField(TypeElement declaredClass, VariableElement field) {
|
||||
mDeclaredClass = declaredClass;
|
||||
mField = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mField.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ModelField) {
|
||||
ModelField that = (ModelField) obj;
|
||||
return mDeclaredClass.equals(that.mDeclaredClass) && ModelAnalyzer.instance
|
||||
.getTypeUtils().isSameType(mField.asType(), that.mField.asType());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public interface ModelField {
|
||||
}
|
||||
|
||||
@@ -17,62 +17,16 @@ package com.android.databinding.reflection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.TypeParameterElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.ExecutableType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
public interface ModelMethod {
|
||||
ModelClass getDeclaringClass();
|
||||
|
||||
public class ModelMethod implements ReflectionMethod {
|
||||
final ExecutableElement mMethod;
|
||||
final DeclaredType mDeclaringType;
|
||||
ModelClass[] getParameterTypes();
|
||||
|
||||
public ModelMethod(DeclaredType declaringType, ExecutableElement method) {
|
||||
mDeclaringType = declaringType;
|
||||
mMethod = method;
|
||||
}
|
||||
String getName();
|
||||
|
||||
@Override
|
||||
public ReflectionClass getDeclaringClass() {
|
||||
return new ModelClass(mDeclaringType);
|
||||
}
|
||||
ModelClass getReturnType(List<ModelClass> args);
|
||||
|
||||
@Override
|
||||
public ReflectionClass[] getParameterTypes() {
|
||||
List<? extends VariableElement> parameters = mMethod.getParameters();
|
||||
ReflectionClass[] parameterTypes = new ReflectionClass[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
parameterTypes[i] = new ModelClass(parameters.get(i).asType());
|
||||
}
|
||||
return parameterTypes;
|
||||
}
|
||||
boolean isPublic();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mMethod.getSimpleName().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflectionClass getReturnType(List<ReflectionClass> args) {
|
||||
ExecutableType executableType = (ExecutableType) ModelAnalyzer.instance.getTypeUtils().asMemberOf(mDeclaringType, mMethod);
|
||||
TypeMirror returnType = executableType.getReturnType();
|
||||
// TODO: support argument-supplied types
|
||||
// for example: public T[] toArray(T[] arr)
|
||||
return new ModelClass(returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
return mMethod.getModifiers().contains(Modifier.PUBLIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return mMethod.getModifiers().contains(Modifier.STATIC);
|
||||
}
|
||||
boolean isStatic();
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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 com.google.common.base.Preconditions;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
|
||||
public abstract class ReflectionAnalyzer {
|
||||
private static ReflectionAnalyzer sAnalyzer;
|
||||
|
||||
public abstract boolean isDataBinder(ReflectionClass reflectionClass);
|
||||
|
||||
public abstract Callable findMethod(ReflectionClass reflectionClass, String name,
|
||||
List<ReflectionClass> 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 reflectionClass, String name);
|
||||
|
||||
public ReflectionClass findCommonParentOf(ReflectionClass reflectionClass1,
|
||||
ReflectionClass reflectionClass2) {
|
||||
ReflectionClass curr = reflectionClass1;
|
||||
while (curr != null && !curr.isAssignableFrom(reflectionClass2)) {
|
||||
curr = curr.getSuperclass();
|
||||
}
|
||||
if (curr == null) {
|
||||
ReflectionClass primitive1 = reflectionClass1.unbox();
|
||||
ReflectionClass primitive2 = reflectionClass2.unbox();
|
||||
if (!reflectionClass1.equals(primitive1) || !reflectionClass2.equals(primitive2)) {
|
||||
return findCommonParentOf(primitive1, primitive2);
|
||||
}
|
||||
}
|
||||
Preconditions.checkNotNull(curr,
|
||||
"must be able to find a common parent for " + reflectionClass1 + " and " + reflectionClass2);
|
||||
return curr;
|
||||
|
||||
}
|
||||
|
||||
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 static void setProcessingEnvironment(ProcessingEnvironment processingEnvironment) {
|
||||
ModelAnalyzer modelAnalyzer = new ModelAnalyzer(processingEnvironment);
|
||||
sAnalyzer = modelAnalyzer;
|
||||
}
|
||||
|
||||
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 List<URL> getResources(String name);
|
||||
|
||||
public abstract ReflectionClass findClass(Class classType);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* 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 {
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.util.List;
|
||||
|
||||
public interface ReflectionMethod {
|
||||
ReflectionClass getDeclaringClass();
|
||||
|
||||
ReflectionClass[] getParameterTypes();
|
||||
|
||||
String getName();
|
||||
|
||||
ReflectionClass getReturnType(List<ReflectionClass> args);
|
||||
|
||||
boolean isPublic();
|
||||
|
||||
boolean isStatic();
|
||||
}
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package com.android.databinding.store;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ReflectionClass;
|
||||
import com.android.databinding.reflection.ReflectionMethod;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.reflection.ModelClass;
|
||||
import com.android.databinding.reflection.ModelMethod;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -27,7 +27,6 @@ import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -53,10 +52,10 @@ public class SetterStore {
|
||||
private static SetterStore sStore;
|
||||
|
||||
private final IntermediateV1 mStore;
|
||||
private final ReflectionAnalyzer mClassAnalyzer;
|
||||
private final ModelAnalyzer mClassAnalyzer;
|
||||
|
||||
private SetterStore(ReflectionAnalyzer reflectionAnalyzer, IntermediateV1 store) {
|
||||
mClassAnalyzer = reflectionAnalyzer;
|
||||
private SetterStore(ModelAnalyzer modelAnalyzer, IntermediateV1 store) {
|
||||
mClassAnalyzer = modelAnalyzer;
|
||||
mStore = store;
|
||||
}
|
||||
|
||||
@@ -93,22 +92,22 @@ public class SetterStore {
|
||||
return sStore;
|
||||
}
|
||||
|
||||
public static SetterStore get(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
public static SetterStore get(ModelAnalyzer modelAnalyzer) {
|
||||
if (sStore == null) {
|
||||
sStore = load(reflectionAnalyzer);
|
||||
sStore = load(modelAnalyzer);
|
||||
}
|
||||
return sStore;
|
||||
}
|
||||
|
||||
private static SetterStore load(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
private static SetterStore load(ModelAnalyzer modelAnalyzer) {
|
||||
IntermediateV1 store = new IntermediateV1();
|
||||
String resourceName = SetterStore.class.getPackage().getName().replace('.', '/') +
|
||||
'/' + SETTER_STORE_FILE_NAME;
|
||||
try {
|
||||
for (URL resource : reflectionAnalyzer.getResources(resourceName)) {
|
||||
for (URL resource : modelAnalyzer.getResources(resourceName)) {
|
||||
merge(store, resource);
|
||||
}
|
||||
return new SetterStore(reflectionAnalyzer, store);
|
||||
return new SetterStore(modelAnalyzer, store);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not read SetterStore intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
@@ -118,7 +117,7 @@ public class SetterStore {
|
||||
e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new SetterStore(reflectionAnalyzer, store);
|
||||
return new SetterStore(modelAnalyzer, store);
|
||||
}
|
||||
|
||||
private static SetterStore load(InputStream inputStream)
|
||||
@@ -255,8 +254,8 @@ public class SetterStore {
|
||||
}
|
||||
}
|
||||
|
||||
public String getSetterCall(String attribute, ReflectionClass viewType,
|
||||
ReflectionClass valueType, String viewExpression, String valueExpression) {
|
||||
public String getSetterCall(String attribute, ModelClass viewType,
|
||||
ModelClass valueType, String viewExpression, String valueExpression) {
|
||||
if (!attribute.startsWith("android:")) {
|
||||
int colon = attribute.indexOf(':');
|
||||
if (colon >= 0) {
|
||||
@@ -266,9 +265,9 @@ public class SetterStore {
|
||||
HashMap<AccessorKey, MethodDescription> adapters = mStore.adapterMethods.get(attribute);
|
||||
MethodDescription adapter = null;
|
||||
String setterName = null;
|
||||
ReflectionMethod bestSetterMethod = getBestSetter(viewType, valueType, attribute);
|
||||
ReflectionClass bestViewType = null;
|
||||
ReflectionClass bestValueType = null;
|
||||
ModelMethod bestSetterMethod = getBestSetter(viewType, valueType, attribute);
|
||||
ModelClass bestViewType = null;
|
||||
ModelClass bestValueType = null;
|
||||
if (bestSetterMethod != null) {
|
||||
bestViewType = bestSetterMethod.getDeclaringClass();
|
||||
bestValueType = bestSetterMethod.getParameterTypes()[0];
|
||||
@@ -278,10 +277,10 @@ public class SetterStore {
|
||||
if (adapters != null) {
|
||||
for (AccessorKey key : adapters.keySet()) {
|
||||
try {
|
||||
ReflectionClass adapterViewType = mClassAnalyzer.findClass(key.viewType);
|
||||
ModelClass adapterViewType = mClassAnalyzer.findClass(key.viewType);
|
||||
if (adapterViewType.isAssignableFrom(viewType)) {
|
||||
try {
|
||||
ReflectionClass adapterValueType = mClassAnalyzer.findClass(key.valueType);
|
||||
ModelClass adapterValueType = mClassAnalyzer.findClass(key.valueType);
|
||||
boolean isBetterView = bestViewType == null ||
|
||||
bestValueType.isAssignableFrom(adapterValueType);
|
||||
if (isBetterParameter(valueType, adapterValueType, bestValueType,
|
||||
@@ -317,7 +316,7 @@ public class SetterStore {
|
||||
}
|
||||
}
|
||||
|
||||
private ReflectionMethod getBestSetter(ReflectionClass viewType, ReflectionClass argumentType,
|
||||
private ModelMethod getBestSetter(ModelClass viewType, ModelClass argumentType,
|
||||
String attribute) {
|
||||
String setterName = null;
|
||||
|
||||
@@ -325,7 +324,7 @@ public class SetterStore {
|
||||
if (renamed != null) {
|
||||
for (String className : renamed.keySet()) {
|
||||
try {
|
||||
ReflectionClass renamedViewType = mClassAnalyzer.findClass(className);
|
||||
ModelClass renamedViewType = mClassAnalyzer.findClass(className);
|
||||
if (renamedViewType.isAssignableFrom(viewType)) {
|
||||
setterName = renamed.get(className).method;
|
||||
break;
|
||||
@@ -338,16 +337,16 @@ public class SetterStore {
|
||||
if (setterName == null) {
|
||||
setterName = getDefaultSetter(attribute);
|
||||
}
|
||||
ReflectionMethod[] methods = viewType.getMethods(setterName, 1);
|
||||
ModelMethod[] methods = viewType.getMethods(setterName, 1);
|
||||
|
||||
ReflectionClass bestParameterType = null;
|
||||
ReflectionMethod bestMethod = null;
|
||||
List<ReflectionClass> args = new ArrayList<>();
|
||||
ModelClass bestParameterType = null;
|
||||
ModelMethod bestMethod = null;
|
||||
List<ModelClass> args = new ArrayList<>();
|
||||
args.add(argumentType);
|
||||
for (ReflectionMethod method : methods) {
|
||||
ReflectionClass[] parameterTypes = method.getParameterTypes();
|
||||
for (ModelMethod method : methods) {
|
||||
ModelClass[] parameterTypes = method.getParameterTypes();
|
||||
if (method.getReturnType(args).isVoid() && !method.isStatic() && method.isPublic()) {
|
||||
ReflectionClass param = parameterTypes[0];
|
||||
ModelClass param = parameterTypes[0];
|
||||
if (isBetterParameter(argumentType, param, bestParameterType, true)) {
|
||||
bestParameterType = param;
|
||||
bestMethod = method;
|
||||
@@ -365,8 +364,8 @@ public class SetterStore {
|
||||
return "set" + propertyName;
|
||||
}
|
||||
|
||||
private boolean isBetterParameter(ReflectionClass argument, ReflectionClass parameter,
|
||||
ReflectionClass oldParameter, boolean isBetterViewTypeMatch) {
|
||||
private boolean isBetterParameter(ModelClass argument, ModelClass parameter,
|
||||
ModelClass oldParameter, boolean isBetterViewTypeMatch) {
|
||||
// Right view type. Check the value
|
||||
if (!isBetterViewTypeMatch && oldParameter.equals(argument)) {
|
||||
return false;
|
||||
@@ -406,7 +405,7 @@ public class SetterStore {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isImplicitConversion(ReflectionClass from, ReflectionClass to) {
|
||||
private static boolean isImplicitConversion(ModelClass from, ModelClass to) {
|
||||
if (from != null && to != null && from.isPrimitive() && to.isPrimitive()) {
|
||||
if (from.isBoolean() || to.isBoolean() || to.isChar()) {
|
||||
return false;
|
||||
@@ -419,17 +418,17 @@ public class SetterStore {
|
||||
}
|
||||
}
|
||||
|
||||
private MethodDescription getConversionMethod(ReflectionClass from, ReflectionClass to) {
|
||||
private MethodDescription getConversionMethod(ModelClass from, ModelClass to) {
|
||||
if (from != null && to != null) {
|
||||
for (String fromClassName : mStore.conversionMethods.keySet()) {
|
||||
try {
|
||||
ReflectionClass convertFrom = mClassAnalyzer.findClass(fromClassName);
|
||||
ModelClass convertFrom = mClassAnalyzer.findClass(fromClassName);
|
||||
if (canUseForConversion(from, convertFrom)) {
|
||||
HashMap<String, MethodDescription> conversion =
|
||||
mStore.conversionMethods.get(fromClassName);
|
||||
for (String toClassName : conversion.keySet()) {
|
||||
try {
|
||||
ReflectionClass convertTo = mClassAnalyzer.findClass(toClassName);
|
||||
ModelClass convertTo = mClassAnalyzer.findClass(toClassName);
|
||||
if (canUseForConversion(convertTo, to)) {
|
||||
return conversion.get(toClassName);
|
||||
}
|
||||
@@ -446,11 +445,11 @@ public class SetterStore {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean canUseForConversion(ReflectionClass from, ReflectionClass to) {
|
||||
private boolean canUseForConversion(ModelClass from, ModelClass to) {
|
||||
return from.equals(to) || isBoxingConversion(from, to) || to.isAssignableFrom(from);
|
||||
}
|
||||
|
||||
private static int getConversionLevel(ReflectionClass primitive) {
|
||||
private static int getConversionLevel(ModelClass primitive) {
|
||||
if (primitive == null) {
|
||||
return -1;
|
||||
} else if (primitive.isByte()) {
|
||||
@@ -472,7 +471,7 @@ public class SetterStore {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBoxingConversion(ReflectionClass class1, ReflectionClass class2) {
|
||||
public static boolean isBoxingConversion(ModelClass class1, ModelClass class2) {
|
||||
if (class1.isPrimitive() != class2.isPrimitive()) {
|
||||
return (class1.box().equals(class2.box()));
|
||||
} else {
|
||||
|
||||
@@ -17,9 +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.reflection.ReflectionAnalyzer
|
||||
import com.android.databinding.reflection.ReflectionClass
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer
|
||||
import com.android.databinding.reflection.ModelAnalyzer
|
||||
import com.android.databinding.reflection.ModelClass
|
||||
import com.android.databinding.reflection.ModelAnalyzer
|
||||
|
||||
private class LazyExt<K, T>(private val initializer: (k : K) -> T) : ReadOnlyProperty<K, T> {
|
||||
private val mapping = hashMapOf<K, T>()
|
||||
|
||||
@@ -15,7 +15,7 @@ package com.android.databinding.writer
|
||||
|
||||
import com.android.databinding.LayoutBinder
|
||||
import com.android.databinding.expr.Expr
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer
|
||||
import com.android.databinding.reflection.ModelAnalyzer
|
||||
import kotlin.properties.Delegates
|
||||
import com.android.databinding.ext.joinToCamelCaseAsVar
|
||||
import com.android.databinding.BindingTarget
|
||||
|
||||
@@ -26,7 +26,7 @@ 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 com.android.databinding.reflection.ModelAnalyzer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -43,7 +43,7 @@ public class ExpressionVisitorTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ReflectionAnalyzer.initForTests();
|
||||
ModelAnalyzer.initForTests();
|
||||
}
|
||||
|
||||
private <T extends Expr> T parse(String input, Class<T> klass) {
|
||||
@@ -69,7 +69,7 @@ public class ExpressionVisitorTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ReflectionAnalyzer.initForTests();
|
||||
ModelAnalyzer.initForTests();
|
||||
}
|
||||
|
||||
@Parameterized.Parameters
|
||||
|
||||
@@ -20,7 +20,7 @@ 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 com.android.databinding.reflection.ModelAnalyzer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -35,7 +35,7 @@ public class LayoutBinderTest {
|
||||
ExprModel mExprModel;
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ReflectionAnalyzer.initForTests();
|
||||
ModelAnalyzer.initForTests();
|
||||
mLayoutBinder = new LayoutBinder(null);
|
||||
mExprModel = mLayoutBinder.getModel();
|
||||
}
|
||||
|
||||
@@ -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.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
import com.android.databinding.LayoutBinder;
|
||||
import com.android.databinding.util.L;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ExprModelTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected Class resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ExprModelTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ReflectionAnalyzer.initForTests();
|
||||
ModelAnalyzer.initForTests();
|
||||
mExprModel = new ExprModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.databinding.expr;
|
||||
|
||||
import com.android.databinding.reflection.ReflectionAnalyzer;
|
||||
import com.android.databinding.reflection.ModelAnalyzer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -37,7 +37,7 @@ public class ExprTest{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected Class resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ public class ExprTest{
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ReflectionAnalyzer.initForTests();
|
||||
ModelAnalyzer.initForTests();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testBadExpr() {
|
||||
Expr expr = new Expr() {
|
||||
@Override
|
||||
protected Class resolveType(ReflectionAnalyzer reflectionAnalyzer) {
|
||||
protected Class resolveType(ModelAnalyzer modelAnalyzer) {
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,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
|
||||
import com.android.databinding.reflection.ModelAnalyzer
|
||||
import com.android.databinding.writer.JavaFileWriter
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
@@ -202,11 +202,6 @@ class DataBinderPlugin : Plugin<Project> {
|
||||
val cpFiles = arrayListOf<File>()
|
||||
cpFiles.addAll(dexTask.getInputFiles())
|
||||
cpFiles.addAll(jCompileTask.getClasspath().getFiles())
|
||||
val urls = cpFiles.map { it.toURI().toURL() }.copyToArray()
|
||||
log("generated urls: ${urls} len: ${urls.size}")
|
||||
val classLoader = URLClassLoader(urls, androidClassLoader)
|
||||
log("created class loader")
|
||||
ReflectionAnalyzer.setClassLoader(classLoader)
|
||||
//project.task("compileGenerated", MethodClosure(this, "compileGenerated"))
|
||||
}
|
||||
fun compileGenerated(o : Any?) {
|
||||
|
||||
Reference in New Issue
Block a user