11b9940e612fc73202837fbe9db2f9035f307b5d1George Mount/* 21b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * Copyright (C) 2015 The Android Open Source Project 31b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * 41b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * Licensed under the Apache License, Version 2.0 (the "License"); 51b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * you may not use this file except in compliance with the License. 61b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * You may obtain a copy of the License at 71b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * 81b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * http://www.apache.org/licenses/LICENSE-2.0 91b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * 101b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * Unless required by applicable law or agreed to in writing, software 111b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * distributed under the License is distributed on an "AS IS" BASIS, 121b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * See the License for the specific language governing permissions and 141b9940e612fc73202837fbe9db2f9035f307b5d1George Mount * limitations under the License. 151b9940e612fc73202837fbe9db2f9035f307b5d1George Mount */ 16fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.reflection; 171b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 188ec9696461abb5ad0b95024edc3f3ccb9ace85beGeorge Mountimport android.databinding.tool.reflection.Callable.Type; 19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L; 204ba16229a40e9758db86d4fb1df5119fdcb8aa2aDeepanshu Guptaimport android.databinding.tool.util.StringUtils; 211b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 22fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mountimport java.util.ArrayList; 23716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport java.util.Arrays; 24fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mountimport java.util.List; 251b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 26716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport static android.databinding.tool.reflection.Callable.CAN_BE_INVALIDATED; 27716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport static android.databinding.tool.reflection.Callable.DYNAMIC; 28716ba89e7f459f49ea85070d4710c1d79d715298George Mountimport static android.databinding.tool.reflection.Callable.STATIC; 29716ba89e7f459f49ea85070d4710c1d79d715298George Mount 30fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mountpublic abstract class ModelClass { 31fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract String toJavaCode(); 321b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 33fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 34fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether this ModelClass represents an array. 35fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 36fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isArray(); 371b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 38fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 39fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * For arrays, lists, and maps, this returns the contained value. For other types, null 40fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * is returned. 41fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 42fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return The component type for arrays, the value type for maps, and the element type 43fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * for lists. 44fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 45fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract ModelClass getComponentType(); 461b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 47fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 48fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return Whether or not this ModelClass can be treated as a List. This means 49fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * it is a java.util.List, or one of the Sparse*Array classes. 50fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 51fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public boolean isList() { 52fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (ModelClass listType : ModelAnalyzer.getInstance().getListTypes()) { 53fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (listType != null) { 54fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (listType.isAssignableFrom(this)) { 55fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return true; 56fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 57fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 58fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 59fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return false; 60fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 611b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 62fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 63fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass can be considered a Map or not. 64fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 65fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public boolean isMap() { 66fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return ModelAnalyzer.getInstance().getMapType().isAssignableFrom(erasure()); 67fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 681b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 69fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 70fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass is a java.lang.String. 71fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 72fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public boolean isString() { 73fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return ModelAnalyzer.getInstance().getStringType().equals(this); 74fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 751b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 76fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 77fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Reference type. 78fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 79fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isNullable(); 80fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 81fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 82fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a primitive type. 83fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 84fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isPrimitive(); 851b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 86fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 87fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java boolean 88fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 89fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isBoolean(); 90fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 91fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 92fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java char 93fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 94fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isChar(); 95fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 96fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 97fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java byte 98fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 99fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isByte(); 100fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 101fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 102fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java short 103fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 104fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isShort(); 105fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 106fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 107fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java int 108fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 109fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isInt(); 110fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 111fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 112fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java long 113fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 114fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isLong(); 115fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 116fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 117fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java float 118fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 119fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isFloat(); 120fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 121fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 122fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a Java double 123fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 124fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isDouble(); 125fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 126fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 12791d538470c011e19fa4375cc3531b5dd9ae01d55George Mount * @return whether or not this has type parameters 12891d538470c011e19fa4375cc3531b5dd9ae01d55George Mount */ 12991d538470c011e19fa4375cc3531b5dd9ae01d55George Mount public abstract boolean isGeneric(); 13091d538470c011e19fa4375cc3531b5dd9ae01d55George Mount 13191d538470c011e19fa4375cc3531b5dd9ae01d55George Mount /** 132b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount * @return a list of Generic type paramters for the class. For example, if the class 133b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount * is List<T>, then the return value will be a list containing T. null is returned 134b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount * if this is not a generic type 135b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount */ 136b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount public abstract List<ModelClass> getTypeArguments(); 137b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount 138b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount /** 139b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount * @return whether this is a type variable. For example, in List<T>, T is a type variable. 140b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount * However, List<String>, String is not a type variable. 141b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount */ 142b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount public abstract boolean isTypeVar(); 143b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount 144b9e4aa96812692a7dcf468445e64bc5b30d3c79aGeorge Mount /** 145bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount * @return whether this is a wildcard type argument or not. 146bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount */ 147bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount public abstract boolean isWildcard(); 148bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount 149bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount /** 150fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass is java.lang.Object and not a primitive or subclass. 151fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 152fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public boolean isObject() { 153fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return ModelAnalyzer.getInstance().getObjectType().equals(this); 154fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 1551b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 156fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 157716ba89e7f459f49ea85070d4710c1d79d715298George Mount * @return whether or not this ModelClass is an interface 158716ba89e7f459f49ea85070d4710c1d79d715298George Mount */ 159716ba89e7f459f49ea85070d4710c1d79d715298George Mount public abstract boolean isInterface(); 160716ba89e7f459f49ea85070d4710c1d79d715298George Mount 161716ba89e7f459f49ea85070d4710c1d79d715298George Mount /** 1625f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount * @return whether or not his is a ViewDataBinding subclass. 1635f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount */ 1645f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount public boolean isViewDataBinding() { 1655f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount return ModelAnalyzer.getInstance().getViewDataBindingType().isAssignableFrom(this); 1665f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount } 1675f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount 1685f3aae011cc291c2abbb90215c2e6f89a5f2626dGeorge Mount /** 169de38dd3ef0577d25b2d59863603abe5750d0c231George Mount * @return whether or not this ModelClass type extends ViewStub. 170de38dd3ef0577d25b2d59863603abe5750d0c231George Mount */ 171de38dd3ef0577d25b2d59863603abe5750d0c231George Mount public boolean extendsViewStub() { 172de38dd3ef0577d25b2d59863603abe5750d0c231George Mount return ModelAnalyzer.getInstance().getViewStubType().isAssignableFrom(this); 173de38dd3ef0577d25b2d59863603abe5750d0c231George Mount } 174de38dd3ef0577d25b2d59863603abe5750d0c231George Mount 175de38dd3ef0577d25b2d59863603abe5750d0c231George Mount /** 176fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this is an Observable type such as ObservableMap, ObservableList, 177fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * or Observable. 178fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 179fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public boolean isObservable() { 180fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance(); 181fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return modelAnalyzer.getObservableType().isAssignableFrom(this) || 182fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount modelAnalyzer.getObservableListType().isAssignableFrom(this) || 183fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount modelAnalyzer.getObservableMapType().isAssignableFrom(this); 1841b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 185fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 1861b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 187fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 188fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this is an ObservableField, or any of the primitive versions 189fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * such as ObservableBoolean and ObservableInt 190fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 191fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public boolean isObservableField() { 192fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelClass erasure = erasure(); 193fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (ModelClass observableField : ModelAnalyzer.getInstance().getObservableFieldTypes()) { 194fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (observableField.isAssignableFrom(erasure)) { 195fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return true; 196fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 197fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 198fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return false; 199fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 2001b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 201fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 202fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return whether or not this ModelClass represents a void 203fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 204fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isVoid(); 2051b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 206fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 207fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * When this is a boxed type, such as Integer, this will return the unboxed value, 208fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * such as int. If this is not a boxed type, this is returned. 209fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 210fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return The unboxed type of the class that this ModelClass represents or this if it isn't a 211fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * boxed type. 212fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 213fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract ModelClass unbox(); 2141b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 215fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 216fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * When this is a primitive type, such as boolean, this will return the boxed value, 217fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * such as Boolean. If this is not a primitive type, this is returned. 218fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 219fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return The boxed type of the class that this ModelClass represents or this if it isn't a 220fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * primitive type. 221fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 222fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract ModelClass box(); 2231b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 224fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 225fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * Returns whether or not the type associated with <code>that</code> can be assigned to 226fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * the type associated with this ModelClass. If this and that only require boxing or unboxing 227fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * then true is returned. 228fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 229fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param that the ModelClass to compare. 230fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return true if <code>that</code> requires only boxing or if <code>that</code> is an 231fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * implementation of or subclass of <code>this</code>. 232fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 233fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract boolean isAssignableFrom(ModelClass that); 2341b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 235fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 236fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * Returns an array containing all public methods on the type represented by this ModelClass 237fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * with the name <code>name</code> and can take the passed-in types as arguments. This will 238fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * also work if the arguments match VarArgs parameter. 239fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 240fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param name The name of the method to find. 241fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param args The types that the method should accept. 242ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * @param staticOnly Whether only static methods should be returned or both instance methods 243ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * and static methods are valid. 244ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * 245fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return An array containing all public methods with the name <code>name</code> and taking 246fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * <code>args</code> parameters. 247fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 248ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar public ModelMethod[] getMethods(String name, List<ModelClass> args, boolean staticOnly) { 249fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelMethod[] methods = getDeclaredMethods(); 250fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ArrayList<ModelMethod> matching = new ArrayList<ModelMethod>(); 251fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (ModelMethod method : methods) { 252ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (method.isPublic() && (!staticOnly || method.isStatic()) && 253fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount name.equals(method.getName()) && method.acceptsArguments(args)) { 254fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount matching.add(method); 255fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 256fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 257fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return matching.toArray(new ModelMethod[matching.size()]); 258fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 2591b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 260fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 261fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * Returns all public instance methods with the given name and number of parameters. 262fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 263fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param name The name of the method to find. 264fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param numParameters The number of parameters that the method should take 265fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return An array containing all public methods with the given name and number of parameters. 266fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 267fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public ModelMethod[] getMethods(String name, int numParameters) { 268fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelMethod[] methods = getDeclaredMethods(); 269fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ArrayList<ModelMethod> matching = new ArrayList<ModelMethod>(); 270fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (ModelMethod method : methods) { 271fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (method.isPublic() && !method.isStatic() && 272fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount name.equals(method.getName()) && 273fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount method.getParameterTypes().length == numParameters) { 274fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount matching.add(method); 275fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 276fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 277fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return matching.toArray(new ModelMethod[matching.size()]); 278fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 2791b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 280fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 281fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * Returns the public method with the name <code>name</code> with the parameters that 282ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * best match args. <code>staticOnly</code> governs whether a static or instance method 283fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * will be returned. If no matching method was found, null is returned. 284fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 285fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param name The method name to find 286fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param args The arguments that the method should accept 287ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * @param staticOnly true if the returned method must be static or false if it does not 288ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * matter. 289fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 290ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar public ModelMethod getMethod(String name, List<ModelClass> args, boolean staticOnly) { 291ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar ModelMethod[] methods = getMethods(name, args, staticOnly); 292ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar L.d("looking methods for %s. static only ? %s . method count: %d", name, staticOnly, 293ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar methods.length); 294ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar for (ModelMethod method : methods) { 295ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar L.d("method: %s, %s", method.getName(), method.isStatic()); 296ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } 297fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (methods.length == 0) { 298fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return null; 299fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 300fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelMethod bestMethod = methods[0]; 301fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (int i = 1; i < methods.length; i++) { 302fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (methods[i].isBetterArgMatchThan(bestMethod, args)) { 303fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount bestMethod = methods[i]; 304fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 305fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 306fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return bestMethod; 307fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 3081b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 309fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 310fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * If this represents a class, the super class that it extends is returned. If this 311fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * represents an interface, the interface that this extends is returned. 312fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * <code>null</code> is returned if this is not a class or interface, such as an int, or 313fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * if it is java.lang.Object or an interface that does not extend any other type. 314fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * 315fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return The class or interface that this ModelClass extends or null. 316fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 317fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract ModelClass getSuperclass(); 3181b9940e612fc73202837fbe9db2f9035f307b5d1George Mount 319fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 320fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return A String representation of the class or interface that this represents, not 321fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * including any type arguments. 322fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 323fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public String getCanonicalName() { 324fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return erasure().toJavaCode(); 325fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 32697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 327fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 328793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount * @return The class or interface name of this type or the primitive type if it isn't a 329793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount * reference type. 330793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount */ 331793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount public String getSimpleName() { 332793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount final String canonicalName = getCanonicalName(); 333793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount final int dotIndex = canonicalName.lastIndexOf('.'); 334793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount if (dotIndex >= 0) { 335793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount return canonicalName.substring(dotIndex + 1); 336793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount } 337793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount return canonicalName; 338793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount } 339793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount 340793e979f25e190162eacf46d6a4efc3efc1d2f91George Mount /** 341fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * Returns this class type without any generic type arguments. 342fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @return this class type without any generic type arguments. 343fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 344fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract ModelClass erasure(); 34597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 34697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar /** 34797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Since when this class is available. Important for Binding expressions so that we don't 34897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * call non-existing APIs when setting UI. 34997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * 35097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * @return The SDK_INT where this method was added. If it is not a framework method, should 35197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * return 1. 35297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */ 353fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public int getMinApi() { 354fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return SdkUtil.getMinApi(this); 355fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 35697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 35797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar /** 35897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Returns the JNI description of the method which can be used to lookup it in SDK. 359fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount * @see TypeUtil 36097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */ 361fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public abstract String getJniDescription(); 362fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 363fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount /** 364716ba89e7f459f49ea85070d4710c1d79d715298George Mount * Returns a list of all abstract methods in the type. 365716ba89e7f459f49ea85070d4710c1d79d715298George Mount */ 366716ba89e7f459f49ea85070d4710c1d79d715298George Mount public List<ModelMethod> getAbstractMethods() { 367716ba89e7f459f49ea85070d4710c1d79d715298George Mount ArrayList<ModelMethod> abstractMethods = new ArrayList<ModelMethod>(); 368716ba89e7f459f49ea85070d4710c1d79d715298George Mount ModelMethod[] methods = getDeclaredMethods(); 369716ba89e7f459f49ea85070d4710c1d79d715298George Mount for (ModelMethod method : methods) { 370716ba89e7f459f49ea85070d4710c1d79d715298George Mount if (method.isAbstract()) { 371716ba89e7f459f49ea85070d4710c1d79d715298George Mount abstractMethods.add(method); 372716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 373716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 374716ba89e7f459f49ea85070d4710c1d79d715298George Mount return abstractMethods; 375716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 376716ba89e7f459f49ea85070d4710c1d79d715298George Mount 377716ba89e7f459f49ea85070d4710c1d79d715298George Mount /** 378fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * Returns the getter method or field that the name refers to. 379fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * @param name The name of the field or the body of the method name -- can be name(), 380fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * getName(), or isName(). 381ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar * @param staticOnly Whether this should look for static methods and fields or instance 382fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount * versions 383716ba89e7f459f49ea85070d4710c1d79d715298George Mount * @return the getter method or field that the name refers to or null if none can be found. 384fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount */ 385ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar public Callable findGetterOrField(String name, boolean staticOnly) { 3868ec9696461abb5ad0b95024edc3f3ccb9ace85beGeorge Mount if ("length".equals(name) && isArray()) { 387d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return new Callable(Type.FIELD, name, null, 388d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount ModelAnalyzer.getInstance().loadPrimitive("int"), 0, 0); 3898ec9696461abb5ad0b95024edc3f3ccb9ace85beGeorge Mount } 390fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount String capitalized = StringUtils.capitalize(name); 391fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount String[] methodNames = { 392fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount "get" + capitalized, 393fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount "is" + capitalized, 394fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount name 395fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount }; 396fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (String methodName : methodNames) { 397ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar ModelMethod[] methods = getMethods(methodName, new ArrayList<ModelClass>(), staticOnly); 398fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (ModelMethod method : methods) { 399716ba89e7f459f49ea85070d4710c1d79d715298George Mount if (method.isPublic() && (!staticOnly || method.isStatic()) && 400716ba89e7f459f49ea85070d4710c1d79d715298George Mount !method.getReturnType(Arrays.asList(method.getParameterTypes())).isVoid()) { 401019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar int flags = DYNAMIC; 402019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar if (method.isStatic()) { 403019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar flags |= STATIC; 404019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar } 405ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (method.isBindable()) { 406019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar flags |= CAN_BE_INVALIDATED; 407ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } else { 408ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar // if method is not bindable, look for a backing field 409ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar final ModelField backingField = getField(name, true, method.isStatic()); 410ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar L.d("backing field for method %s is %s", method.getName(), 411ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar backingField == null ? "NOT FOUND" : backingField.getName()); 412ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (backingField != null && backingField.isBindable()) { 413ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar flags |= CAN_BE_INVALIDATED; 414ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } 415019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar } 416d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final ModelMethod setterMethod = findSetter(method, name); 417d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final String setterName = setterMethod == null ? null : setterMethod.getName(); 418fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount final Callable result = new Callable(Callable.Type.METHOD, methodName, 419d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount setterName, method.getReturnType(null), method.getParameterTypes().length, 42088ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar flags); 421fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return result; 422fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 423fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 424fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 425fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 426ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar // could not find a method. Look for a public field 427ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar ModelField publicField = null; 428ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (staticOnly) { 429ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar publicField = getField(name, false, true); 430ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } else { 431ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar // first check non-static 432ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar publicField = getField(name, false, false); 433ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (publicField == null) { 434ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar // check for static 435ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar publicField = getField(name, false, true); 436019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar } 437019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar } 438716ba89e7f459f49ea85070d4710c1d79d715298George Mount if (publicField == null) { 439716ba89e7f459f49ea85070d4710c1d79d715298George Mount return null; 440716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 441ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar ModelClass fieldType = publicField.getFieldType(); 442ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar int flags = 0; 443d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount String setterFieldName = name; 444d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (publicField.isStatic()) { 445d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount flags |= STATIC; 446d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 447ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (!publicField.isFinal()) { 448d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount setterFieldName = null; 449ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar flags |= DYNAMIC; 450fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 451ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (publicField.isBindable()) { 452ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar flags |= CAN_BE_INVALIDATED; 453ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } 454d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return new Callable(Callable.Type.FIELD, name, setterFieldName, fieldType, 0, flags); 455d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 456d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 457d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public ModelMethod findInstanceGetter(String name) { 458d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount String capitalized = StringUtils.capitalize(name); 459d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount String[] methodNames = { 460d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount "get" + capitalized, 461d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount "is" + capitalized, 462d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount name 463d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount }; 464d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount for (String methodName : methodNames) { 465d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount ModelMethod[] methods = getMethods(methodName, new ArrayList<ModelClass>(), false); 466d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount for (ModelMethod method : methods) { 467d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (method.isPublic() && !method.isStatic() && 468d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount !method.getReturnType(Arrays.asList(method.getParameterTypes())).isVoid()) { 469d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return method; 470d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 471d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 472ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } 473d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return null; 474fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 475fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 476ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar private ModelField getField(String name, boolean allowPrivate, boolean isStatic) { 477fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelField[] fields = getDeclaredFields(); 478fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount for (ModelField field : fields) { 4790d6e2b8ac5e9e8635adf95c4166dd26441c51997Yigit Boyar boolean nameMatch = name.equals(field.getName()) || 4800d6e2b8ac5e9e8635adf95c4166dd26441c51997Yigit Boyar name.equals(stripFieldName(field.getName())); 4810d6e2b8ac5e9e8635adf95c4166dd26441c51997Yigit Boyar if (nameMatch && field.isStatic() == isStatic && 482019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar (allowPrivate || field.isPublic())) { 483fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return field; 484fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 485fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 486fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return null; 487fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 488fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 489d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private ModelMethod findSetter(ModelMethod getter, String originalName) { 490d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final String capitalized = StringUtils.capitalize(originalName); 491d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final String[] possibleNames; 492d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (originalName.equals(getter.getName())) { 493d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount possibleNames = new String[] { originalName, "set" + capitalized }; 494d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } else if (getter.getName().startsWith("is")){ 495d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount possibleNames = new String[] { "set" + capitalized, "setIs" + capitalized }; 496d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } else { 497d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount possibleNames = new String[] { "set" + capitalized }; 498d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 499d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount for (String name : possibleNames) { 500d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount List<ModelMethod> methods = findMethods(name, getter.isStatic()); 501d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (methods != null) { 502d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount ModelClass param = getter.getReturnType(null); 503d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount for (ModelMethod method : methods) { 504d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount ModelClass[] parameterTypes = method.getParameterTypes(); 505d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (parameterTypes != null && parameterTypes.length == 1 && 506d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount parameterTypes[0].equals(param) && 507d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount method.isStatic() == getter.isStatic()) { 508d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return method; 509d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 510d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 511d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 512d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 513d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return null; 514d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 515d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 516716ba89e7f459f49ea85070d4710c1d79d715298George Mount /** 517716ba89e7f459f49ea85070d4710c1d79d715298George Mount * Finds public methods that matches the given name exactly. These may be resolved into 518716ba89e7f459f49ea85070d4710c1d79d715298George Mount * listener methods during Expr.resolveListeners. 519716ba89e7f459f49ea85070d4710c1d79d715298George Mount */ 520716ba89e7f459f49ea85070d4710c1d79d715298George Mount public List<ModelMethod> findMethods(String name, boolean staticOnly) { 521716ba89e7f459f49ea85070d4710c1d79d715298George Mount ModelMethod[] methods = getDeclaredMethods(); 522716ba89e7f459f49ea85070d4710c1d79d715298George Mount ArrayList<ModelMethod> matching = new ArrayList<ModelMethod>(); 523716ba89e7f459f49ea85070d4710c1d79d715298George Mount for (ModelMethod method : methods) { 524716ba89e7f459f49ea85070d4710c1d79d715298George Mount if (method.getName().equals(name) && (!staticOnly || method.isStatic()) && 525716ba89e7f459f49ea85070d4710c1d79d715298George Mount method.isPublic()) { 526716ba89e7f459f49ea85070d4710c1d79d715298George Mount matching.add(method); 527716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 528716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 529716ba89e7f459f49ea85070d4710c1d79d715298George Mount if (matching.isEmpty()) { 530716ba89e7f459f49ea85070d4710c1d79d715298George Mount return null; 531716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 532716ba89e7f459f49ea85070d4710c1d79d715298George Mount return matching; 533716ba89e7f459f49ea85070d4710c1d79d715298George Mount } 534716ba89e7f459f49ea85070d4710c1d79d715298George Mount 535bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount public boolean isIncomplete() { 536bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount if (isTypeVar() || isWildcard()) { 537bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount return true; 538bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount } 539bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount List<ModelClass> typeArgs = getTypeArguments(); 540bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount if (typeArgs != null) { 541bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount for (ModelClass typeArg : typeArgs) { 542bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount if (typeArg.isIncomplete()) { 543bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount return true; 544bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount } 545bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount } 546bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount } 547bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount return false; 548bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount } 549bd42d20f70b1f88e27e3b3c9c3a9c55ec155d128George Mount 550fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount protected abstract ModelField[] getDeclaredFields(); 551fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 552fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount protected abstract ModelMethod[] getDeclaredMethods(); 553fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount 554fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount private static String stripFieldName(String fieldName) { 555fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount // TODO: Make this configurable through IntelliJ 556fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (fieldName.length() > 2) { 557fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount final char start = fieldName.charAt(2); 558fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (fieldName.startsWith("m_") && Character.isJavaIdentifierStart(start)) { 559fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return Character.toLowerCase(start) + fieldName.substring(3); 560fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 561fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 562fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (fieldName.length() > 1) { 563fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount final char start = fieldName.charAt(1); 564fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount final char fieldIdentifier = fieldName.charAt(0); 565fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount final boolean strip; 566fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (fieldIdentifier == '_') { 567fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount strip = true; 568fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } else if (fieldIdentifier == 'm' && Character.isJavaIdentifierStart(start) && 569fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount !Character.isLowerCase(start)) { 570fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount strip = true; 571fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } else { 572fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount strip = false; // not mUppercase format 573fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 574fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (strip) { 575fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return Character.toLowerCase(start) + fieldName.substring(2); 576fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 577fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 578fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount return fieldName; 579fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 5801b9940e612fc73202837fbe9db2f9035f307b5d1George Mount} 581