Support static method and field access and improve method finding.

Bug 19425630
Bug 19336295

Change-Id: I4c04db32492edfa093e94c3c15bf7799128b1e03
diff --git a/TestApp/src/androidTest/java/com/android/databinding/testapp/FindMethodTest.java b/TestApp/src/androidTest/java/com/android/databinding/testapp/FindMethodTest.java
new file mode 100644
index 0000000..4e5ecd3
--- /dev/null
+++ b/TestApp/src/androidTest/java/com/android/databinding/testapp/FindMethodTest.java
@@ -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.testapp;
+
+import com.android.databinding.testapp.generated.FindMethodTestBinder;
+import com.android.databinding.testapp.vo.FindMethodBindingObject;
+
+import android.widget.TextView;
+
+public class FindMethodTest
+        extends BindingAdapterTestBase<FindMethodTestBinder, FindMethodBindingObject> {
+
+    public FindMethodTest() {
+        super(FindMethodTestBinder.class, FindMethodBindingObject.class, R.layout.find_method_test);
+    }
+
+    public void testNoArg() throws Throwable {
+        TextView textView = mBinder.getTextView6();
+        assertEquals("no arg", textView.getText().toString());
+    }
+
+    public void testIntArg() throws Throwable {
+        TextView textView = mBinder.getTextView0();
+        assertEquals("1", textView.getText().toString());
+    }
+
+    public void testFloatArg() throws Throwable {
+        TextView textView = mBinder.getTextView1();
+        assertEquals("1.25", textView.getText().toString());
+    }
+
+    public void testStringArg() throws Throwable {
+        TextView textView = mBinder.getTextView2();
+        assertEquals("hello", textView.getText().toString());
+    }
+
+    public void testBoxedArg() throws Throwable {
+        TextView textView = mBinder.getTextView3();
+        assertEquals("1", textView.getText().toString());
+    }
+
+    public void testInheritedMethod() throws Throwable {
+        TextView textView = mBinder.getTextView4();
+        assertEquals("base", textView.getText().toString());
+    }
+
+    public void testInheritedMethodInt() throws Throwable {
+        TextView textView = mBinder.getTextView5();
+        assertEquals("base 2", textView.getText().toString());
+    }
+
+    public void testStaticMethod() throws Throwable {
+        TextView textView = mBinder.getTextView7();
+        assertEquals("world", textView.getText().toString());
+    }
+
+    public void testStaticField() throws Throwable {
+        TextView textView = mBinder.getTextView8();
+        assertEquals("hello world", textView.getText().toString());
+    }
+}
diff --git a/TestApp/src/main/java/com/android/databinding/testapp/vo/FindMethodBindingObject.java b/TestApp/src/main/java/com/android/databinding/testapp/vo/FindMethodBindingObject.java
new file mode 100644
index 0000000..5c0a2ad
--- /dev/null
+++ b/TestApp/src/main/java/com/android/databinding/testapp/vo/FindMethodBindingObject.java
@@ -0,0 +1,35 @@
+/*
+ * 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.testapp.vo;
+
+public class FindMethodBindingObject extends FindMethodBindingObjectBase {
+    public String method() { return "no arg"; }
+
+    public String method(int i) { return String.valueOf(i); }
+
+    public String method(float f) { return String.valueOf(f); }
+
+    public String method(String value) { return value; }
+
+    public static String staticMethod() { return "world"; }
+
+    public static Foo foo = new Foo();
+
+
+    public static class Foo {
+        public final String bar = "hello world";
+    }
+}
diff --git a/TestApp/src/main/java/com/android/databinding/testapp/vo/FindMethodBindingObjectBase.java b/TestApp/src/main/java/com/android/databinding/testapp/vo/FindMethodBindingObjectBase.java
new file mode 100644
index 0000000..142a3fe
--- /dev/null
+++ b/TestApp/src/main/java/com/android/databinding/testapp/vo/FindMethodBindingObjectBase.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.databinding.testapp.vo;
+
+public class FindMethodBindingObjectBase extends BindingAdapterBindingObject {
+    public String inheritedMethod() {
+        return "base";
+    }
+
+    public String inheritedMethod(int i) {
+        return "base " + i;
+    }
+
+    @Override
+    public void changeValues() {
+    }
+}
diff --git a/TestApp/src/main/res/layout/find_method_test.xml b/TestApp/src/main/res/layout/find_method_test.xml
new file mode 100644
index 0000000..810c783
--- /dev/null
+++ b/TestApp/src/main/res/layout/find_method_test.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <variable name="obj" type="com.android.databinding.testapp.vo.FindMethodBindingObject"/>
+    <!--
+    <import name="FMBO" type=""/>
+-->
+    <TextView
+            android:id="@+id/textView0"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.method(1)}"/>
+    <TextView
+            android:id="@+id/textView1"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.method(1.25f}"/>
+    <TextView
+            android:id="@+id/textView2"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.method(`hello`}"/>
+    <TextView
+            android:id="@+id/textView3"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.method((java.lang.Integer) 1)}"/>
+    <TextView
+            android:id="@+id/textView4"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.inheritedMethod()}"/>
+    <TextView
+            android:id="@+id/textView5"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.inheritedMethod(2)}"/>
+    <TextView
+            android:id="@+id/textView6"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{obj.method()}"/>
+    <TextView
+            android:id="@+id/textView7"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{com.android.databinding.testapp.vo.FindMethodBindingObject.staticMethod()}"/>
+    <TextView
+            android:id="@+id/textView8"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:text="@{com.android.databinding.testapp.vo.FindMethodBindingObject.foo.bar}"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/compiler/src/main/java/com/android/databinding/expr/Expr.java b/compiler/src/main/java/com/android/databinding/expr/Expr.java
index 862a7b2..9129106 100644
--- a/compiler/src/main/java/com/android/databinding/expr/Expr.java
+++ b/compiler/src/main/java/com/android/databinding/expr/Expr.java
@@ -16,11 +16,6 @@
 
 package com.android.databinding.expr;
 
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Collections;
-import java.util.List;
-
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
@@ -31,6 +26,11 @@
 import com.android.databinding.reflection.ModelAnalyzer;
 import com.android.databinding.reflection.ModelClass;
 
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+
 abstract public class Expr {
 
     public static final int NO_ID = -1;
@@ -570,6 +570,41 @@
     }
 
     public void updateExpr(ModelAnalyzer modelAnalyzer) {
+        for (Expr child : mChildren) {
+            child.updateExpr(modelAnalyzer);
+        }
+    }
+
+    protected void replaceStaticAccess(ModelAnalyzer modelAnalyzer) {
+        for (int i = 0; i < mChildren.size(); i++) {
+            Expr child = mChildren.get(i);
+            String packageName = child.asPackage();
+            if (packageName != null) {
+                ModelClass modelClass = modelAnalyzer.findClass(packageName);
+                if (modelClass != null) {
+                    Expr staticAccessExpr = getModel().staticAccessExpr(modelClass);
+                    staticAccessExpr.getParents().add(this);
+                    mChildren.set(i, staticAccessExpr);
+                    child.removeParentAndUnregisterIfOrphan(this);
+                }
+            }
+        }
+    }
+
+    private void removeParentAndUnregisterIfOrphan(Expr parent) {
+        while (mParents.remove(parent)) {
+        }
+        if (getParents().isEmpty()) {
+            getModel().unregister(this);
+            for (Expr expr : mChildren) {
+                expr.removeParentAndUnregisterIfOrphan(this);
+            }
+            mChildren.clear();
+        }
+    }
+
+    protected String asPackage() {
+        return null;
     }
 
     static class Node {
diff --git a/compiler/src/main/java/com/android/databinding/expr/ExprModel.java b/compiler/src/main/java/com/android/databinding/expr/ExprModel.java
index f7ad56d..ce11da8 100644
--- a/compiler/src/main/java/com/android/databinding/expr/ExprModel.java
+++ b/compiler/src/main/java/com/android/databinding/expr/ExprModel.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.Lists;
 
 import com.android.databinding.reflection.ModelAnalyzer;
+import com.android.databinding.reflection.ModelClass;
 import com.android.databinding.util.L;
 import com.android.databinding.writer.FlagSet;
 
@@ -85,6 +86,10 @@
         return expr;
     }
 
+    public void unregister(Expr expr) {
+        mExprMap.remove(expr.getUniqueKey());
+    }
+
     public Map<String, Expr> getExprMap() {
         return mExprMap;
     }
@@ -141,6 +146,10 @@
         return register(new BracketExpr(variableExpr, argExpr));
     }
 
+    public Expr staticAccessExpr(ModelClass modelClass) {
+        return register(new StaticAccessExpr(modelClass));
+    }
+
     public Expr castExpr(String type, Expr expr) {
         return register(new CastExpr(type, expr));
     }
@@ -197,17 +206,10 @@
         //ensure class analyzer. We need to know observables at this point
         final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
 
-        ArrayList<Expr> processedExprs = new ArrayList<>();
-        ArrayList<Expr> exprs = new ArrayList<>();
-        do {
-            exprs.clear();
-            exprs.addAll(mExprMap.values());
-            exprs.removeAll(processedExprs);
-            for (Expr expr: exprs) {
-                expr.updateExpr(modelAnalyzer);
-            }
-            processedExprs.addAll(exprs);
-        } while (!exprs.isEmpty());
+        ArrayList<Expr> exprs = new ArrayList<>(mBindingExpressions);
+        for (Expr expr: exprs) {
+            expr.updateExpr(modelAnalyzer);
+        }
 
         int counter = 0;
         final Iterable<Expr> observables = filterObservables(modelAnalyzer);
diff --git a/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java b/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java
index c7cb8b0..8f3140a 100644
--- a/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java
+++ b/compiler/src/main/java/com/android/databinding/expr/FieldAccessExpr.java
@@ -87,11 +87,19 @@
 
     @Override
     public void updateExpr(ModelAnalyzer modelAnalyzer) {
+        resolveType(modelAnalyzer);
+        super.updateExpr(modelAnalyzer);
+    }
+
+    @Override
+    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
         if (mGetter == null) {
-            mGetter = modelAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName);
+            replaceStaticAccess(modelAnalyzer);
+            Expr parent = getParent();
+            boolean isStatic = parent instanceof StaticAccessExpr;
+            mGetter = modelAnalyzer.findMethodOrField(parent.getResolvedType(), mName, isStatic);
             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);
                 getChildren().remove(parent);
 
@@ -100,17 +108,16 @@
 
                 getChildren().add(observableField);
                 observableField.getParents().add(this);
-                mGetter = modelAnalyzer.findMethodOrField(mGetter.resolvedType, "get");
+                mGetter = modelAnalyzer.findMethodOrField(mGetter.resolvedType, "get", false);
                 mName = "";
             }
         }
+        return mGetter.resolvedType;
     }
 
     @Override
-    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
-        if (mGetter == null) {
-            mGetter = modelAnalyzer.findMethodOrField(mChildren.get(0).getResolvedType(), mName);
-        }
-        return mGetter.resolvedType;
+    protected String asPackage() {
+        String parentPackage = getParent().asPackage();
+        return parentPackage == null ? null : parentPackage + "." + mName;
     }
 }
diff --git a/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java b/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java
index cfcbc43..feb3567 100644
--- a/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java
+++ b/compiler/src/main/java/com/android/databinding/expr/IdentifierExpr.java
@@ -68,4 +68,9 @@
     protected List<Dependency> constructDependencies() {
         return Lists.newArrayList();
     }
+
+    @Override
+    protected String asPackage() {
+        return mUserDefinedType == null ? mName : null;
+    }
 }
diff --git a/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java b/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java
index dfae772..e2f33bf 100644
--- a/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java
+++ b/compiler/src/main/java/com/android/databinding/expr/MethodCallExpr.java
@@ -37,13 +37,23 @@
     }
 
     @Override
+    public void updateExpr(ModelAnalyzer modelAnalyzer) {
+        resolveType(modelAnalyzer);
+        super.updateExpr(modelAnalyzer);
+    }
+
+    @Override
     protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
         if (mGetter == null) {
+            replaceStaticAccess(modelAnalyzer);
             List<ModelClass> args = new ArrayList<>();
             for (Expr expr : getArgs()) {
                 args.add(expr.getResolvedType());
             }
-            mGetter = modelAnalyzer.findMethod(getTarget().getResolvedType(), mName, args);
+
+            Expr target = getTarget();
+            boolean isStatic = target instanceof StaticAccessExpr;
+            mGetter = modelAnalyzer.findMethod(target.getResolvedType(), mName, args, isStatic);
         }
         return mGetter.resolvedType;
     }
diff --git a/compiler/src/main/java/com/android/databinding/expr/StaticAccessExpr.java b/compiler/src/main/java/com/android/databinding/expr/StaticAccessExpr.java
new file mode 100644
index 0000000..adb7156
--- /dev/null
+++ b/compiler/src/main/java/com/android/databinding/expr/StaticAccessExpr.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.databinding.expr;
+
+import com.android.databinding.reflection.ModelAnalyzer;
+import com.android.databinding.reflection.ModelClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StaticAccessExpr extends Expr {
+    private ModelClass mStaticClass;
+
+    public StaticAccessExpr(ModelClass modelClass) {
+        mStaticClass = modelClass;
+    }
+
+    @Override
+    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        return mStaticClass;
+    }
+
+    @Override
+    protected List<Dependency> constructDependencies() {
+        return new ArrayList<>();
+    }
+
+    protected String computeUniqueKey() {
+        return mStaticClass.toJavaCode();
+    }
+
+}
diff --git a/compiler/src/main/java/com/android/databinding/reflection/AnnotationAnalyzer.java b/compiler/src/main/java/com/android/databinding/reflection/AnnotationAnalyzer.java
index 5616661..07fb936 100644
--- a/compiler/src/main/java/com/android/databinding/reflection/AnnotationAnalyzer.java
+++ b/compiler/src/main/java/com/android/databinding/reflection/AnnotationAnalyzer.java
@@ -124,31 +124,33 @@
 
     @Override
     public Callable findMethod(ModelClass modelClass, String name,
-            List<ModelClass> args) {
+            List<ModelClass> args, boolean staticAccess) {
         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;
+                if (method.isStatic() == staticAccess) {
+                    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;
                         }
-                    } 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 (parametersMatch) {
+                        return new Callable(Callable.Type.METHOD, methodName,
+                                method.getReturnType(args), true, false);
+                    }
                 }
             }
         }
@@ -190,7 +192,7 @@
     }
 
     @Override
-    public Callable findMethodOrField(ModelClass modelClass, String name) {
+    public Callable findMethodOrField(ModelClass modelClass, String name, boolean staticAccess) {
         AnnotationClass annotationClass = (AnnotationClass)modelClass;
         for (String methodName :
                 new String[]{"get" + StringUtils.capitalize(name),
@@ -198,7 +200,7 @@
             ModelMethod[] methods = modelClass.getMethods(methodName, 0);
             for (ModelMethod modelMethod : methods) {
                 AnnotationMethod method = (AnnotationMethod) modelMethod;
-                if (method.isPublic()) {
+                if (method.isPublic() && method.isStatic() == staticAccess) {
                     final AnnotationField backingField = findField(annotationClass, name, true);
                     final Callable result = new Callable(Callable.Type.METHOD, methodName,
                             method.getReturnType(null), true, isBindable(method) ||
@@ -210,7 +212,8 @@
         }
 
         AnnotationField field = findField(annotationClass, name, false);
-        if (field != null && field.mField.getModifiers().contains(Modifier.PUBLIC)) {
+        if (field != null && field.mField.getModifiers().contains(Modifier.PUBLIC) &&
+                field.mField.getModifiers().contains(Modifier.STATIC) == staticAccess) {
             AnnotationClass fieldType = new AnnotationClass(field.mField.asType());
             return new Callable(Callable.Type.FIELD, name, fieldType,
                     !field.mField.getModifiers().contains(Modifier.FINAL)
@@ -288,15 +291,17 @@
         }
         int templateOpenIndex = className.indexOf('<');
         DeclaredType declaredType;
+        Elements elementUtils = getElementUtils();
         if (templateOpenIndex < 0) {
-            Elements elementUtils = getElementUtils();
             TypeElement typeElement = elementUtils.getTypeElement(className);
+            if (typeElement == null) {
+                return null;
+            }
             declaredType = (DeclaredType) typeElement.asType();
         } else {
             int templateCloseIndex = className.lastIndexOf('>');
             String paramStr = className.substring(templateOpenIndex + 1, templateCloseIndex);
 
-            Elements elementUtils = getElementUtils();
             String baseClassName = className.substring(0, templateOpenIndex);
             TypeElement typeElement = elementUtils.getTypeElement(baseClassName);
 
diff --git a/compiler/src/main/java/com/android/databinding/reflection/AnnotationClass.java b/compiler/src/main/java/com/android/databinding/reflection/AnnotationClass.java
index facb4fb..5d5f813 100644
--- a/compiler/src/main/java/com/android/databinding/reflection/AnnotationClass.java
+++ b/compiler/src/main/java/com/android/databinding/reflection/AnnotationClass.java
@@ -105,20 +105,17 @@
                             ", but it isn't a declared type: " + foundInterface);
             return null;
         }
-        System.err.println("found interface: " + foundInterface);
         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());
     }
@@ -221,7 +218,7 @@
     }
 
     @Override
-    public ModelClass box() {
+    public AnnotationClass box() {
         if (!isPrimitive()) {
             return this;
         }
@@ -233,8 +230,10 @@
         if (that == null) {
             return false;
         }
-        TypeMirror thatType = ((AnnotationClass)that).mTypeMirror;
-        return getTypeUtils().isAssignable(thatType, mTypeMirror);
+        AnnotationClass thisBoxed = box();
+        AnnotationClass thatBoxed = (AnnotationClass) that.box();
+        final TypeMirror thatType = thatBoxed.mTypeMirror;
+        return getTypeUtils().isAssignable(thatType, thisBoxed.mTypeMirror);
     }
 
     @Override
diff --git a/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java b/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java
index 58c4266..2993fc5 100644
--- a/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java
+++ b/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java
@@ -28,7 +28,7 @@
     public abstract boolean isDataBinder(ModelClass modelClass);
 
     public abstract Callable findMethod(ModelClass modelClass, String name,
-            List<ModelClass> args);
+            List<ModelClass> args, boolean staticAccess);
 
     public abstract boolean isObservable(ModelClass modelClass);
 
@@ -38,7 +38,8 @@
 
     public abstract boolean isBindable(ModelMethod method);
 
-    public abstract Callable findMethodOrField(ModelClass modelClass, String name);
+    public abstract Callable findMethodOrField(ModelClass modelClass, String name,
+            boolean staticAccess);
 
     public ModelClass findCommonParentOf(ModelClass modelClass1,
             ModelClass modelClass2) {
diff --git a/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt b/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt
index f4300b6..5a27489 100644
--- a/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt
+++ b/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt
@@ -46,6 +46,7 @@
 import com.android.databinding.expr.BracketExpr
 import com.android.databinding.reflection.Callable
 import com.android.databinding.expr.CastExpr
+import com.android.databinding.expr.StaticAccessExpr
 
 fun String.stripNonJava() = this.split("[^a-zA-Z0-9]").map{ it.trim() }.joinToCamelCaseAsVar()
 
@@ -221,6 +222,9 @@
             app("(", it.getCastType())
             app(") ", it.getCastExpr().toCode())
         }
+        is StaticAccessExpr -> kcode("") {
+            app("", it.getResolvedType().toJavaCode())
+        }
         else -> kcode("//NOT IMPLEMENTED YET")
     }
 
@@ -422,24 +426,26 @@
             nl("}")
         }
         usedVariables.forEach {
-            nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableUniqueName}) {") {
-                if (it.isObservable()) {
-                    tab("updateRegistration(${it.getId()}, ${it.readableUniqueName});");
+            if (it.getUserDefinedType() != null) {
+                nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableUniqueName}) {") {
+                    if (it.isObservable()) {
+                        tab("updateRegistration(${it.getId()}, ${it.readableUniqueName});");
+                    }
+                    tab("this.${it.fieldName} = ${it.readableUniqueName};")
+                    // set dirty flags!
+                    val flagSet = it.invalidateFlagSet
+                    mDirtyFlags.mapOr(flagSet) { suffix, index ->
+                        tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
+                    }
+                    tab("super.requestRebind();")
                 }
-                tab("this.${it.fieldName} = ${it.readableUniqueName};")
-                // set dirty flags!
-                val flagSet = it.invalidateFlagSet
-                mDirtyFlags.mapOr(flagSet) { suffix, index ->
-                    tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
+                nl("}")
+                nl("")
+                nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
+                    tab("return ${it.fieldName};")
                 }
-                tab("super.requestRebind();")
+                nl("}")
             }
-            nl("}")
-            nl("")
-            nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
-                tab("return ${it.fieldName};")
-            }
-            nl("}")
         }
     }
 
@@ -667,8 +673,10 @@
 
             nl("public interface ${interfaceName} extends IViewDataBinder {")
             variables.forEach {
-                tab("@Bindable")
-                tab("public void ${it.setterName}(${it.getUserDefinedType()} ${it.readableUniqueName});")
+                if (it.getUserDefinedType() != null) {
+                    tab("@Bindable")
+                    tab("public void ${it.setterName}(${it.getUserDefinedType()} ${it.readableUniqueName});")
+                }
             }
             layoutBinder.getBindingTargets().forEach {
                 tab("public ${it.getInterfaceType()} ${it.getterName}();")