SetterStore.java revision 97758524d3953793b50e3e0121ef3cbdc047b35b
15a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt/* 25a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * Copyright (C) 2015 The Android Open Source Project 35a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * 45a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * Licensed under the Apache License, Version 2.0 (the "License"); 55a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * you may not use this file except in compliance with the License. 65a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * You may obtain a copy of the License at 75a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * 85a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * http://www.apache.org/licenses/LICENSE-2.0 95a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * 105a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * Unless required by applicable law or agreed to in writing, software 115a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * distributed under the License is distributed on an "AS IS" BASIS, 125a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * See the License for the specific language governing permissions and 145a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * limitations under the License. 155a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt */ 165a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtpackage android.databinding.tool.store; 175a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 185a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport org.apache.commons.lang3.StringUtils; 195a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 205a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport android.databinding.tool.reflection.ModelAnalyzer; 215a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport android.databinding.tool.reflection.ModelClass; 225a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport android.databinding.tool.reflection.ModelMethod; 235a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport android.databinding.tool.util.GenerationalClassUtil; 245a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport android.databinding.tool.util.L; 255a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport android.databinding.tool.util.Preconditions; 265a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 275a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.io.IOException; 285a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.io.Serializable; 295a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.ArrayList; 305a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.Arrays; 315a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.Collections; 325a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.Comparator; 335a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.HashMap; 345a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.Iterator; 355a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.List; 365a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.Map; 375a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.Set; 385a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport java.util.TreeMap; 395a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 405a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.annotation.processing.ProcessingEnvironment; 414ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidtimport javax.lang.model.element.ExecutableElement; 425a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.element.Modifier; 435a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.element.TypeElement; 445a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.element.VariableElement; 455a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.type.ArrayType; 465a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.type.DeclaredType; 475a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.type.TypeKind; 485a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtimport javax.lang.model.type.TypeMirror; 495a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 505a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtpublic class SetterStore { 515a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private static SetterStore sStore; 527d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 535a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private final IntermediateV1 mStore; 545a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private final ModelAnalyzer mClassAnalyzer; 555a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 565a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private Comparator<MultiAttributeSetter> COMPARE_MULTI_ATTRIBUTE_SETTERS = 575a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt new Comparator<MultiAttributeSetter>() { 587d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt @Override 595a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt public int compare(MultiAttributeSetter o1, MultiAttributeSetter o2) { 605a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (o1.attributes.length != o2.attributes.length) { 615a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return o2.attributes.length - o1.attributes.length; 625a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 635a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt ModelClass view1 = mClassAnalyzer.findClass(o1.mKey.viewType, null).erasure(); 645a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt ModelClass view2 = mClassAnalyzer.findClass(o2.mKey.viewType, null).erasure(); 655a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (!view1.equals(view2)) { 665a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (view1.isAssignableFrom(view2)) { 675a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return 1; 685a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else { 695a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return -1; 705a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 715a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 725a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (!o1.mKey.attributeIndices.keySet() 735a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt .equals(o2.mKey.attributeIndices.keySet())) { 745a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt // order by attribute name 755a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt Iterator<String> o1Keys = o1.mKey.attributeIndices.keySet().iterator(); 765a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt Iterator<String> o2Keys = o2.mKey.attributeIndices.keySet().iterator(); 775a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt while (o1Keys.hasNext()) { 785a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt String key1 = o1Keys.next(); 795a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt String key2 = o2Keys.next(); 805a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt int compare = key1.compareTo(key2); 815a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (compare != 0) { 825a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return compare; 835a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 845a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 855a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt Preconditions.check(false, 865a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt "The sets don't match! That means the keys shouldn't match also"); 875a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 885a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt // Same view type. Same attributes 895a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt for (String attribute : o1.mKey.attributeIndices.keySet()) { 905a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt final int index1 = o1.mKey.attributeIndices.get(attribute); 915a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt final int index2 = o2.mKey.attributeIndices.get(attribute); 925a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt ModelClass type1 = mClassAnalyzer 935a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt .findClass(o1.mKey.parameterTypes[index1], null); 945a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt ModelClass type2 = mClassAnalyzer 955a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt .findClass(o2.mKey.parameterTypes[index2], null); 96ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt if (type1.equals(type2)) { 975a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt continue; 985a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 995a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (o1.mCasts[index1] != null) { 1005a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (o2.mCasts[index2] == null) { 1015a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return 1; // o2 is better 1025a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else { 1035a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt continue; // both are casts 1045a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1055a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else if (o2.mCasts[index2] != null) { 1065a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return -1; // o1 is better 1075a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1085a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (o1.mConverters[index1] != null) { 1095a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (o2.mConverters[index2] == null) { 1105a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return 1; // o2 is better 1115a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else { 1125a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt continue; // both are conversions 1135a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1145a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else if (o2.mConverters[index2] != null) { 1155a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return -1; // o1 is better 1165a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1175a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 1185a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (type1.isPrimitive()) { 1195a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (type2.isPrimitive()) { 1205a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt int type1ConversionLevel = ModelMethod 1215a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt .getImplicitConversionLevel(type1); 1225a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt int type2ConversionLevel = ModelMethod 1235a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt .getImplicitConversionLevel(type2); 1245a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return type2ConversionLevel - type1ConversionLevel; 1255a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else { 1265a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt // type1 is primitive and has higher priority 1275a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return -1; 1285a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1295a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else if (type2.isPrimitive()) { 1305a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return 1; 1315a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1325a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (type1.isAssignableFrom(type2)) { 1335a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return 1; 1345a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else if (type2.isAssignableFrom(type1)) { 1355a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return -1; 1365a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1375a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1385a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt // hmmm... same view type, same attributes, same parameter types... ? 1395a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return 0; 1405a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1415a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt }; 1425a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 1435a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private SetterStore(ModelAnalyzer modelAnalyzer, IntermediateV1 store) { 1445a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt mClassAnalyzer = modelAnalyzer; 1455a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt mStore = store; 1465a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1475a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 1485a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt public static SetterStore get(ModelAnalyzer modelAnalyzer) { 1495a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (sStore == null) { 1505a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt sStore = load(modelAnalyzer); 1515a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1525a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return sStore; 1537d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 1545a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 1557d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt private static SetterStore load(ModelAnalyzer modelAnalyzer) { 1565a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt IntermediateV1 store = new IntermediateV1(); 1575a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt List<Intermediate> previousStores = GenerationalClassUtil 1587d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt .loadObjects(GenerationalClassUtil.ExtensionFilter.SETTER_STORE); 1597d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (Intermediate intermediate : previousStores) { 1605a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt merge(store, intermediate); 1617d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 1627d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt return new SetterStore(modelAnalyzer, store); 1635a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1645a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 1655a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt public void addRenamedMethod(String attribute, String declaringClass, String method, 1665a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt TypeElement declaredOn) { 1677d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt attribute = stripNamespace(attribute); 1685a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt HashMap<String, MethodDescription> renamed = mStore.renamedMethods.get(attribute); 1695a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (renamed == null) { 1705a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt renamed = new HashMap<String, MethodDescription>(); 1715a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt mStore.renamedMethods.put(attribute, renamed); 1729839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 1739839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt MethodDescription methodDescription = new MethodDescription( 1749839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt declaredOn.getQualifiedName().toString(), method); 1759839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt L.d("STORE addmethod desc %s", methodDescription); 1769839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt renamed.put(declaringClass, methodDescription); 1779839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 1789839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 1799839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt public void addBindingAdapter(ProcessingEnvironment processingEnv, String attribute, 1809839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt ExecutableElement bindingMethod, boolean takesComponent) { 1819839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt attribute = stripNamespace(attribute); 1829839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt L.d("STORE addBindingAdapter %s %s", attribute, bindingMethod); 1839839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt HashMap<AccessorKey, MethodDescription> adapters = mStore.adapterMethods.get(attribute); 1849839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 1859839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (adapters == null) { 1869839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt adapters = new HashMap<AccessorKey, MethodDescription>(); 1879839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt mStore.adapterMethods.put(attribute, adapters); 1885a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 1895a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt List<? extends VariableElement> parameters = bindingMethod.getParameters(); 1907d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt final int viewIndex = takesComponent ? 1 : 0; 1915a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt TypeMirror viewType = eraseType(processingEnv, parameters.get(viewIndex).asType()); 1927d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt String view = getQualifiedName(viewType); 1935a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt TypeMirror parameterType = eraseType(processingEnv, parameters.get(viewIndex + 1).asType()); 1945a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt String value = getQualifiedName(parameterType); 1957d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 1967d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt AccessorKey key = new AccessorKey(view, value); 1977d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt if (adapters.containsKey(key)) { 1987d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt throw new IllegalArgumentException("Already exists!"); 1995a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2007d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 2017d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt adapters.put(key, new MethodDescription(bindingMethod, 1, takesComponent)); 2027d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 2037d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 2045a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private static TypeMirror eraseType(ProcessingEnvironment processingEnv, 2055a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt TypeMirror typeMirror) { 2067d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt if (hasTypeVar(typeMirror)) { 2075a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return processingEnv.getTypeUtils().erasure(typeMirror); 2085a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else { 2095a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return typeMirror; 2104ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt } 2115a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2125a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 2135a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private static ModelClass eraseType(ModelClass modelClass) { 2145a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (hasTypeVar(modelClass)) { 2155a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return modelClass.erasure(); 2165a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else { 2179839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return modelClass; 2189839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2199839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2209839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 2219839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt private static boolean hasTypeVar(TypeMirror typeMirror) { 2229839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt TypeKind kind = typeMirror.getKind(); 2239839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (kind == TypeKind.TYPEVAR) { 2249839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return true; 2255a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else if (kind == TypeKind.ARRAY) { 2265a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return hasTypeVar(((ArrayType) typeMirror).getComponentType()); 2277d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } else if (kind == TypeKind.DECLARED) { 2285a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt DeclaredType declaredType = (DeclaredType) typeMirror; 2297d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments(); 2305a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (typeArguments == null || typeArguments.isEmpty()) { 2315a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return false; 2327d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 2337d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (TypeMirror arg : typeArguments) { 2345a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (hasTypeVar(arg)) { 2357d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt return true; 2367d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 2375a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2385a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return false; 2397d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } else { 2405a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return false; 2415a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2425a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2435a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 2445a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private static boolean hasTypeVar(ModelClass type) { 2459839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (type.isTypeVar()) { 2469839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return true; 2479839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } else if (type.isArray()) { 2489839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return hasTypeVar(type.getComponentType()); 2499839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } else { 2509839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt List<ModelClass> typeArguments = type.getTypeArguments(); 2519839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (typeArguments == null) { 2529839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return false; 2539839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2549839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt for (ModelClass arg : typeArguments) { 2559839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (hasTypeVar(arg)) { 2569839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return true; 2579839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2589839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2599839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return false; 2609839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2619839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 2629839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 2639839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt public void addBindingAdapter(ProcessingEnvironment processingEnv, String[] attributes, 2649839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt ExecutableElement bindingMethod, boolean takesComponent, boolean requireAll) { 2659839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt L.d("STORE add multi-value BindingAdapter %d %s", attributes.length, bindingMethod); 2669839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt MultiValueAdapterKey key = new MultiValueAdapterKey(processingEnv, bindingMethod, 2675a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt attributes, takesComponent, requireAll); 2685a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt MethodDescription methodDescription = new MethodDescription(bindingMethod, 2697d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt attributes.length, takesComponent); 2705a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt mStore.multiValueAdapters.put(key, methodDescription); 2715a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2727d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 2737d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt private static String[] stripAttributes(String[] attributes) { 2747d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt String[] strippedAttributes = new String[attributes.length]; 2757d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (int i = 0; i < attributes.length; i++) { 2767d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt strippedAttributes[i] = stripNamespace(attributes[i]); 2777d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 2785a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return strippedAttributes; 2797d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 2807d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 2817d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt public void addUntaggableTypes(String[] typeNames, TypeElement declaredOn) { 2827d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt L.d("STORE addUntaggableTypes %s %s", Arrays.toString(typeNames), declaredOn); 2837d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt String declaredType = declaredOn.getQualifiedName().toString(); 2847d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (String type : typeNames) { 2855a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt mStore.untaggableTypes.put(type, declaredType); 2865a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2875a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2885a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 2897d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt private static String getQualifiedName(TypeMirror type) { 2907d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt if (type.getKind() == TypeKind.ARRAY) { 2917d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt return getQualifiedName(((ArrayType) type).getComponentType()) + "[]"; 2927d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } else { 2937d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt return type.toString(); 2945a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 2957d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 2967d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt 2977d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt public void addConversionMethod(ExecutableElement conversionMethod) { 2987d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt L.d("STORE addConversionMethod %s", conversionMethod); 2997d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt List<? extends VariableElement> parameters = conversionMethod.getParameters(); 3005a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt String fromType = getQualifiedName(parameters.get(0).asType()); 3015a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt String toType = getQualifiedName(conversionMethod.getReturnType()); 3025a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt MethodDescription methodDescription = new MethodDescription(conversionMethod, 1, false); 3037d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt HashMap<String, MethodDescription> convertTo = mStore.conversionMethods.get(fromType); 3045a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (convertTo == null) { 3055a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt convertTo = new HashMap<String, MethodDescription>(); 3065a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt mStore.conversionMethods.put(fromType, convertTo); 3075a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3084ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt convertTo.put(toType, methodDescription); 3095a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3104ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt 3115a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt public void clear(Set<String> classes) { 3125a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt ArrayList<AccessorKey> removedAccessorKeys = new ArrayList<AccessorKey>(); 3135a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt for (HashMap<AccessorKey, MethodDescription> adapters : mStore.adapterMethods.values()) { 3145a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt for (AccessorKey key : adapters.keySet()) { 3154ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt MethodDescription description = adapters.get(key); 3165a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (classes.contains(description.type)) { 3174ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt removedAccessorKeys.add(key); 3185a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3195a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3209839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt removeFromMap(adapters, removedAccessorKeys); 3219839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3229839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 3239839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt ArrayList<String> removedRenamed = new ArrayList<String>(); 3249839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt for (HashMap<String, MethodDescription> renamed : mStore.renamedMethods.values()) { 3259839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt for (String key : renamed.keySet()) { 3269839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (classes.contains(renamed.get(key).type)) { 3279839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt removedRenamed.add(key); 3289839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3299839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3309839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt removeFromMap(renamed, removedRenamed); 3319839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3329839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 3339839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt ArrayList<String> removedConversions = new ArrayList<String>(); 3349839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt for (HashMap<String, MethodDescription> convertTos : mStore.conversionMethods.values()) { 3355a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt for (String toType : convertTos.keySet()) { 3365a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt MethodDescription methodDescription = convertTos.get(toType); 3377d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt if (classes.contains(methodDescription.type)) { 3385a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt removedConversions.add(toType); 3395a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3407d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 3417d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt removeFromMap(convertTos, removedConversions); 3427d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 3435a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 3447d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt ArrayList<String> removedUntaggable = new ArrayList<String>(); 3457d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (String typeName : mStore.untaggableTypes.keySet()) { 3467d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt if (classes.contains(mStore.untaggableTypes.get(typeName))) { 3475a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt removedUntaggable.add(typeName); 3485a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3495a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3507d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt removeFromMap(mStore.untaggableTypes, removedUntaggable); 3517d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 3525a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 3537d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt private static <K, V> void removeFromMap(Map<K, V> map, List<K> keys) { 3547d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (K key : keys) { 3555a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt map.remove(key); 3565a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3577d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt keys.clear(); 3585a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3594ae50e65ef0eefe6d5c356acbc1839f8eac68af5Dmitry Shmidt 3605a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt public void write(String projectPackage, ProcessingEnvironment processingEnvironment) 3615a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt throws IOException { 3625a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt GenerationalClassUtil.writeIntermediateFile(processingEnvironment, 3635a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt projectPackage, projectPackage + 3645a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt GenerationalClassUtil.ExtensionFilter.SETTER_STORE.getExtension(), mStore); 3655a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 3665a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 3679839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt private static String stripNamespace(String attribute) { 3689839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (!attribute.startsWith("android:")) { 3699839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt int colon = attribute.indexOf(':'); 3709839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (colon >= 0) { 3719839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt attribute = attribute.substring(colon + 1); 3729839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3739839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3749839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return attribute; 3759839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3769839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 3779839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt public List<MultiAttributeSetter> getMultiAttributeSetterCalls(String[] attributes, 3789839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt ModelClass viewType, ModelClass[] valueType) { 3799839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt attributes = stripAttributes(attributes); 3809839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt final ArrayList<MultiAttributeSetter> calls = new ArrayList<MultiAttributeSetter>(); 3819839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt if (viewType != null && viewType.isGeneric()) { 3829839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt List<ModelClass> viewGenerics = viewType.getTypeArguments(); 3839839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt for (int i = 0; i < valueType.length; i++) { 3849839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt valueType[i] = eraseType(valueType[i], viewGenerics); 3859839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3869839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt viewType = viewType.erasure(); 3879839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3889839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt ArrayList<MultiAttributeSetter> matching = getMatchingMultiAttributeSetters(attributes, 3899839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt viewType, valueType); 3909839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt Collections.sort(matching, COMPARE_MULTI_ATTRIBUTE_SETTERS); 3919839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt while (!matching.isEmpty()) { 3929839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt MultiAttributeSetter bestMatch = matching.get(0); 3939839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt calls.add(bestMatch); 3949839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt removeConsumedAttributes(matching, bestMatch.attributes); 3959839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3969839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt return calls; 3979839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt } 3989839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt 3999839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt // Removes all MultiAttributeSetters that require any of the values in attributes 4009839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt private static void removeConsumedAttributes(ArrayList<MultiAttributeSetter> matching, 4019839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt String[] attributes) { 4025a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt for (int i = matching.size() - 1; i >= 0; i--) { 4035a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt final MultiAttributeSetter setter = matching.get(i); 4045a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt boolean found = false; 4057d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt for (String attribute : attributes) { 4065a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (isInArray(attribute, setter.attributes)) { 4077d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt found = true; 4085a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt break; 4095a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 4107d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 4117d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt if (found) { 4125a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt matching.remove(i); 4137d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 4147d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt } 4155a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 4165a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt 4177d17530e229db79208e99741071df97ea4faeec6Dmitry Shmidt // Linear search through the String array for a specific value. 4185a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt private static boolean isInArray(String str, String[] array) { 4195a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt for (String value : array) { 4205a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (value.equals(str)) { 4215a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt return true; 4225a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 4235a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } 424 return false; 425 } 426 427 private ArrayList<MultiAttributeSetter> getMatchingMultiAttributeSetters(String[] attributes, 428 ModelClass viewType, ModelClass[] valueType) { 429 final ArrayList<MultiAttributeSetter> setters = new ArrayList<MultiAttributeSetter>(); 430 for (MultiValueAdapterKey adapter : mStore.multiValueAdapters.keySet()) { 431 if (adapter.requireAll && adapter.attributes.length > attributes.length) { 432 continue; 433 } 434 ModelClass viewClass = mClassAnalyzer.findClass(adapter.viewType, null); 435 if (viewClass.isGeneric()) { 436 viewClass = viewClass.erasure(); 437 } 438 if (!viewClass.isAssignableFrom(viewType)) { 439 continue; 440 } 441 final MethodDescription method = mStore.multiValueAdapters.get(adapter); 442 final MultiAttributeSetter setter = createMultiAttributeSetter(method, attributes, 443 valueType, adapter); 444 if (setter != null) { 445 setters.add(setter); 446 } 447 } 448 return setters; 449 } 450 451 private MultiAttributeSetter createMultiAttributeSetter(MethodDescription method, 452 String[] allAttributes, ModelClass[] attributeValues, MultiValueAdapterKey adapter) { 453 int matchingAttributes = 0; 454 String[] casts = new String[adapter.attributes.length]; 455 MethodDescription[] conversions = new MethodDescription[adapter.attributes.length]; 456 boolean[] supplied = new boolean[adapter.attributes.length]; 457 458 for (int i = 0; i < allAttributes.length; i++) { 459 Integer index = adapter.attributeIndices.get(allAttributes[i]); 460 if (index != null) { 461 supplied[index] = true; 462 matchingAttributes++; 463 final String parameterTypeStr = adapter.parameterTypes[index]; 464 final ModelClass parameterType = eraseType( 465 mClassAnalyzer.findClass(parameterTypeStr, null)); 466 final ModelClass attributeType = attributeValues[i]; 467 if (!parameterType.isAssignableFrom(attributeType)) { 468 if (ModelMethod.isBoxingConversion(parameterType, attributeType)) { 469 // automatic boxing is ok 470 continue; 471 } else if (ModelMethod.isImplicitConversion(attributeType, parameterType)) { 472 // implicit conversion is ok 473 continue; 474 } 475 // Look for a converter 476 conversions[index] = getConversionMethod(attributeType, parameterType, null); 477 if (conversions[index] == null) { 478 if (attributeType.isObject()) { 479 // Cast is allowed also 480 casts[index] = parameterTypeStr; 481 } else { 482 // Parameter type mismatch 483 return null; 484 } 485 } 486 } 487 } 488 } 489 490 if ((adapter.requireAll && matchingAttributes != adapter.attributes.length) || 491 matchingAttributes == 0) { 492 return null; 493 } else { 494 return new MultiAttributeSetter(adapter, supplied, method, conversions, casts); 495 } 496 } 497 498 public SetterCall getSetterCall(String attribute, ModelClass viewType, 499 ModelClass valueType, Map<String, String> imports) { 500 attribute = stripNamespace(attribute); 501 SetterCall setterCall = null; 502 MethodDescription conversionMethod = null; 503 if (viewType != null) { 504 viewType = viewType.erasure(); 505 HashMap<AccessorKey, MethodDescription> adapters = mStore.adapterMethods.get(attribute); 506 ModelMethod bestSetterMethod = getBestSetter(viewType, valueType, attribute, imports); 507 ModelClass bestViewType = null; 508 ModelClass bestValueType = null; 509 if (bestSetterMethod != null) { 510 bestViewType = bestSetterMethod.getDeclaringClass(); 511 bestValueType = bestSetterMethod.getParameterTypes()[0]; 512 setterCall = new ModelMethodSetter(bestSetterMethod); 513 } 514 515 if (adapters != null) { 516 for (AccessorKey key : adapters.keySet()) { 517 try { 518 ModelClass adapterViewType = mClassAnalyzer 519 .findClass(key.viewType, imports).erasure(); 520 if (adapterViewType != null && adapterViewType.isAssignableFrom(viewType)) { 521 try { 522 L.d("setter parameter type is %s", key.valueType); 523 final ModelClass adapterValueType = eraseType(mClassAnalyzer 524 .findClass(key.valueType, imports)); 525 L.d("setter %s takes type %s, compared to %s", 526 adapters.get(key).method, adapterValueType.toJavaCode(), 527 valueType.toJavaCode()); 528 boolean isBetterView = bestViewType == null || 529 bestValueType.isAssignableFrom(adapterValueType); 530 if (isBetterParameter(valueType, adapterValueType, bestValueType, 531 isBetterView, imports)) { 532 bestViewType = adapterViewType; 533 bestValueType = adapterValueType; 534 MethodDescription adapter = adapters.get(key); 535 setterCall = new AdapterSetter(adapter, adapterValueType); 536 } 537 538 } catch (Exception e) { 539 L.e(e, "Unknown class: %s", key.valueType); 540 } 541 } 542 } catch (Exception e) { 543 L.e(e, "Unknown class: %s", key.viewType); 544 } 545 } 546 } 547 548 conversionMethod = getConversionMethod(valueType, bestValueType, imports); 549 if (valueType.isObject() && setterCall != null && bestValueType.isNullable()) { 550 setterCall.setCast(bestValueType); 551 } 552 } 553 if (setterCall == null) { 554 if (viewType != null && !viewType.isViewDataBinding()) { 555 return null; // no setter found!! 556 } 557 setterCall = new DummySetter(getDefaultSetter(attribute)); 558 } 559 setterCall.setConverter(conversionMethod); 560 return setterCall; 561 } 562 563 public boolean isUntaggable(String viewType) { 564 return mStore.untaggableTypes.containsKey(viewType); 565 } 566 567 private ModelMethod getBestSetter(ModelClass viewType, ModelClass argumentType, 568 String attribute, Map<String, String> imports) { 569 if (viewType.isGeneric()) { 570 argumentType = eraseType(argumentType, viewType.getTypeArguments()); 571 viewType = viewType.erasure(); 572 } 573 List<String> setterCandidates = new ArrayList<String>(); 574 HashMap<String, MethodDescription> renamed = mStore.renamedMethods.get(attribute); 575 if (renamed != null) { 576 for (String className : renamed.keySet()) { 577 try { 578 ModelClass renamedViewType = mClassAnalyzer.findClass(className, imports); 579 if (renamedViewType.erasure().isAssignableFrom(viewType)) { 580 setterCandidates.add(renamed.get(className).method); 581 break; 582 } 583 } catch (Exception e) { 584 //printMessage(Diagnostic.Kind.NOTE, "Unknown class: " + className); 585 } 586 } 587 } 588 setterCandidates.add(getDefaultSetter(attribute)); 589 setterCandidates.add(trimAttributeNamespace(attribute)); 590 591 ModelMethod bestMethod = null; 592 ModelClass bestParameterType = null; 593 List<ModelClass> args = new ArrayList<ModelClass>(); 594 args.add(argumentType); 595 for (String name : setterCandidates) { 596 ModelMethod[] methods = viewType.getMethods(name, 1); 597 598 for (ModelMethod method : methods) { 599 ModelClass[] parameterTypes = method.getParameterTypes(); 600 ModelClass param = parameterTypes[0]; 601 if (method.isVoid() && 602 isBetterParameter(argumentType, param, bestParameterType, true, imports)) { 603 bestParameterType = param; 604 bestMethod = method; 605 } 606 } 607 } 608 return bestMethod; 609 } 610 611 private static ModelClass eraseType(ModelClass type, List<ModelClass> typeParameters) { 612 List<ModelClass> typeArguments = type.getTypeArguments(); 613 if (typeArguments == null || typeParameters == null) { 614 return type; 615 } 616 for (ModelClass arg : typeArguments) { 617 if (typeParameters.contains(arg)) { 618 return type.erasure(); 619 } 620 } 621 return type; 622 } 623 624 private static String trimAttributeNamespace(String attribute) { 625 final int colonIndex = attribute.indexOf(':'); 626 return colonIndex == -1 ? attribute : attribute.substring(colonIndex + 1); 627 } 628 629 private static String getDefaultSetter(String attribute) { 630 return "set" + StringUtils.capitalize(trimAttributeNamespace(attribute)); 631 } 632 633 private boolean isBetterParameter(ModelClass argument, ModelClass parameter, 634 ModelClass oldParameter, boolean isBetterViewTypeMatch, Map<String, String> imports) { 635 // Right view type. Check the value 636 if (!isBetterViewTypeMatch && oldParameter.equals(argument)) { 637 return false; 638 } else if (argument.equals(parameter)) { 639 // Exact match 640 return true; 641 } else if (!isBetterViewTypeMatch && 642 ModelMethod.isBoxingConversion(oldParameter, argument)) { 643 return false; 644 } else if (ModelMethod.isBoxingConversion(parameter, argument)) { 645 // Boxing/unboxing is second best 646 return true; 647 } else { 648 int oldConversionLevel = ModelMethod.getImplicitConversionLevel(oldParameter); 649 if (ModelMethod.isImplicitConversion(argument, parameter)) { 650 // Better implicit conversion 651 int conversionLevel = ModelMethod.getImplicitConversionLevel(parameter); 652 return oldConversionLevel < 0 || conversionLevel < oldConversionLevel; 653 } else if (oldConversionLevel >= 0) { 654 return false; 655 } else if (parameter.isAssignableFrom(argument)) { 656 // Right type, see if it is better than the current best match. 657 if (oldParameter == null) { 658 return true; 659 } else { 660 return oldParameter.isAssignableFrom(parameter); 661 } 662 } else { 663 MethodDescription conversionMethod = getConversionMethod(argument, parameter, 664 imports); 665 if (conversionMethod != null) { 666 return true; 667 } 668 if (getConversionMethod(argument, oldParameter, imports) != null) { 669 return false; 670 } 671 return argument.isObject() && !parameter.isPrimitive(); 672 } 673 } 674 } 675 676 private MethodDescription getConversionMethod(ModelClass from, ModelClass to, 677 Map<String, String> imports) { 678 if (from != null && to != null) { 679 if (to.isObject()) { 680 return null; 681 } 682 for (String fromClassName : mStore.conversionMethods.keySet()) { 683 try { 684 ModelClass convertFrom = mClassAnalyzer.findClass(fromClassName, imports); 685 if (canUseForConversion(from, convertFrom)) { 686 HashMap<String, MethodDescription> conversion = 687 mStore.conversionMethods.get(fromClassName); 688 for (String toClassName : conversion.keySet()) { 689 try { 690 ModelClass convertTo = mClassAnalyzer.findClass(toClassName, 691 imports); 692 if (canUseForConversion(convertTo, to)) { 693 return conversion.get(toClassName); 694 } 695 } catch (Exception e) { 696 L.d(e, "Unknown class: %s", toClassName); 697 } 698 } 699 } 700 } catch (Exception e) { 701 L.d(e, "Unknown class: %s", fromClassName); 702 } 703 } 704 } 705 return null; 706 } 707 708 private boolean canUseForConversion(ModelClass from, ModelClass to) { 709 return from.equals(to) || ModelMethod.isBoxingConversion(from, to) || 710 to.isAssignableFrom(from); 711 } 712 713 private static void merge(IntermediateV1 store, Intermediate dumpStore) { 714 IntermediateV1 intermediateV1 = (IntermediateV1) dumpStore.upgrade(); 715 merge(store.adapterMethods, intermediateV1.adapterMethods); 716 merge(store.renamedMethods, intermediateV1.renamedMethods); 717 merge(store.conversionMethods, intermediateV1.conversionMethods); 718 store.multiValueAdapters.putAll(intermediateV1.multiValueAdapters); 719 store.untaggableTypes.putAll(intermediateV1.untaggableTypes); 720 } 721 722 private static <K, V> void merge(HashMap<K, HashMap<V, MethodDescription>> first, 723 HashMap<K, HashMap<V, MethodDescription>> second) { 724 for (K key : second.keySet()) { 725 HashMap<V, MethodDescription> firstVals = first.get(key); 726 HashMap<V, MethodDescription> secondVals = second.get(key); 727 if (firstVals == null) { 728 first.put(key, secondVals); 729 } else { 730 for (V key2 : secondVals.keySet()) { 731 if (!firstVals.containsKey(key2)) { 732 firstVals.put(key2, secondVals.get(key2)); 733 } 734 } 735 } 736 } 737 } 738 739 private static String createAdapterCall(MethodDescription adapter, String bindingAdapterCall, 740 String componentExpression, String viewExpression, String... args) { 741 StringBuilder sb = new StringBuilder(); 742 743 if (adapter.isStatic) { 744 sb.append(adapter.type); 745 } else { 746 sb.append(componentExpression).append('.').append(bindingAdapterCall); 747 } 748 sb.append('.').append(adapter.method).append('('); 749 if (adapter.componentClass != null) { 750 if (!"DataBindingComponent".equals(adapter.componentClass)) { 751 sb.append('(').append(adapter.componentClass).append(") "); 752 } 753 sb.append(componentExpression).append(", "); 754 } 755 sb.append(viewExpression); 756 for (String arg: args) { 757 sb.append(", ").append(arg); 758 } 759 sb.append(')'); 760 return sb.toString(); 761 } 762 763 private static class MultiValueAdapterKey implements Serializable { 764 private static final long serialVersionUID = 1; 765 766 public final String viewType; 767 768 public final String[] attributes; 769 770 public final String[] parameterTypes; 771 772 public final boolean requireAll; 773 774 public final TreeMap<String, Integer> attributeIndices = new TreeMap<String, Integer>(); 775 776 public MultiValueAdapterKey(ProcessingEnvironment processingEnv, 777 ExecutableElement method, String[] attributes, boolean takesComponent, 778 boolean requireAll) { 779 this.attributes = stripAttributes(attributes); 780 this.requireAll = requireAll; 781 List<? extends VariableElement> parameters = method.getParameters(); 782 final int argStart = 1 + (takesComponent ? 1 : 0); 783 this.viewType = getQualifiedName(eraseType(processingEnv, 784 parameters.get(argStart - 1).asType())); 785 this.parameterTypes = new String[parameters.size() - argStart]; 786 for (int i = 0; i < attributes.length; i++) { 787 TypeMirror typeMirror = eraseType(processingEnv, 788 parameters.get(i + argStart).asType()); 789 this.parameterTypes[i] = getQualifiedName(typeMirror); 790 attributeIndices.put(this.attributes[i], i); 791 } 792 } 793 794 @Override 795 public boolean equals(Object obj) { 796 if (!(obj instanceof MultiValueAdapterKey)) { 797 return false; 798 } 799 final MultiValueAdapterKey that = (MultiValueAdapterKey) obj; 800 if (!this.viewType.equals(that.viewType) || 801 this.attributes.length != that.attributes.length || 802 !this.attributeIndices.keySet().equals(that.attributeIndices.keySet())) { 803 return false; 804 } 805 806 for (int i = 0; i < this.attributes.length; i++) { 807 final int thatIndex = that.attributeIndices.get(this.attributes[i]); 808 final String thisParameter = parameterTypes[i]; 809 final String thatParameter = that.parameterTypes[thatIndex]; 810 if (!thisParameter.equals(thatParameter)) { 811 return false; 812 } 813 } 814 return true; 815 } 816 817 @Override 818 public int hashCode() { 819 return mergedHashCode(viewType, attributeIndices.keySet()); 820 } 821 } 822 823 private static int mergedHashCode(Object... objects) { 824 return Arrays.hashCode(objects); 825 } 826 827 private static class MethodDescription implements Serializable { 828 829 private static final long serialVersionUID = 1; 830 831 public final String type; 832 833 public final String method; 834 835 public final boolean requiresOldValue; 836 837 public final boolean isStatic; 838 839 public final String componentClass; 840 841 public MethodDescription(String type, String method) { 842 this.type = type; 843 this.method = method; 844 this.requiresOldValue = false; 845 this.isStatic = true; 846 this.componentClass = null; 847 L.d("BINARY created method desc 1 %s %s", type, method ); 848 } 849 850 public MethodDescription(ExecutableElement method, int numAttributes, 851 boolean takesComponent) { 852 TypeElement enclosingClass = (TypeElement) method.getEnclosingElement(); 853 this.type = enclosingClass.getQualifiedName().toString(); 854 this.method = method.getSimpleName().toString(); 855 final int argStart = 1 + (takesComponent ? 1 : 0); 856 this.requiresOldValue = method.getParameters().size() - argStart == numAttributes * 2; 857 this.isStatic = method.getModifiers().contains(Modifier.STATIC); 858 this.componentClass = takesComponent 859 ? getQualifiedName(method.getParameters().get(0).asType()) 860 : null; 861 862 L.d("BINARY created method desc 2 %s %s, %s", type, this.method, method); 863 } 864 865 @Override 866 public boolean equals(Object obj) { 867 if (obj instanceof MethodDescription) { 868 MethodDescription that = (MethodDescription) obj; 869 return that.type.equals(this.type) && that.method.equals(this.method); 870 } else { 871 return false; 872 } 873 } 874 875 @Override 876 public int hashCode() { 877 return mergedHashCode(type, method); 878 } 879 880 @Override 881 public String toString() { 882 return type + "." + method + "()"; 883 } 884 } 885 886 private static class AccessorKey implements Serializable { 887 888 private static final long serialVersionUID = 1; 889 890 public final String viewType; 891 892 public final String valueType; 893 894 public AccessorKey(String viewType, String valueType) { 895 this.viewType = viewType; 896 this.valueType = valueType; 897 } 898 899 @Override 900 public int hashCode() { 901 return mergedHashCode(viewType, valueType); 902 } 903 904 @Override 905 public boolean equals(Object obj) { 906 if (obj instanceof AccessorKey) { 907 AccessorKey that = (AccessorKey) obj; 908 return viewType.equals(that.valueType) && valueType.equals(that.valueType); 909 } else { 910 return false; 911 } 912 } 913 914 @Override 915 public String toString() { 916 return "AK(" + viewType + ", " + valueType + ")"; 917 } 918 } 919 920 private interface Intermediate extends Serializable { 921 Intermediate upgrade(); 922 } 923 924 private static class IntermediateV1 implements Serializable, Intermediate { 925 private static final long serialVersionUID = 1; 926 public final HashMap<String, HashMap<AccessorKey, MethodDescription>> adapterMethods = 927 new HashMap<String, HashMap<AccessorKey, MethodDescription>>(); 928 public final HashMap<String, HashMap<String, MethodDescription>> renamedMethods = 929 new HashMap<String, HashMap<String, MethodDescription>>(); 930 public final HashMap<String, HashMap<String, MethodDescription>> conversionMethods = 931 new HashMap<String, HashMap<String, MethodDescription>>(); 932 public final HashMap<String, String> untaggableTypes = new HashMap<String, String>(); 933 public final HashMap<MultiValueAdapterKey, MethodDescription> multiValueAdapters = 934 new HashMap<MultiValueAdapterKey, MethodDescription>(); 935 936 public IntermediateV1() { 937 } 938 939 @Override 940 public Intermediate upgrade() { 941 return this; 942 } 943 } 944 945 public static class DummySetter extends SetterCall { 946 private String mMethodName; 947 948 public DummySetter(String methodName) { 949 mMethodName = methodName; 950 } 951 952 @Override 953 public String toJavaInternal(String componentExpression, String viewExpression, 954 String valueExpression) { 955 return viewExpression + "." + mMethodName + "(" + valueExpression + ")"; 956 } 957 958 @Override 959 public String toJavaInternal(String componentExpression, String viewExpression, 960 String oldValue, String valueExpression) { 961 return viewExpression + "." + mMethodName + "(" + valueExpression + ")"; 962 } 963 964 @Override 965 public int getMinApi() { 966 return 1; 967 } 968 969 @Override 970 public boolean requiresOldValue() { 971 return false; 972 } 973 974 @Override 975 public ModelClass[] getParameterTypes() { 976 return new ModelClass[] { 977 ModelAnalyzer.getInstance().findClass(Object.class) 978 }; 979 } 980 981 @Override 982 public String getBindingAdapterInstanceClass() { 983 return null; 984 } 985 986 @Override 987 public void setBindingAdapterCall(String method) { 988 } 989 } 990 991 public static class AdapterSetter extends SetterCall { 992 final MethodDescription mAdapter; 993 final ModelClass mParameterType; 994 String mBindingAdapterCall; 995 996 public AdapterSetter(MethodDescription adapter, ModelClass parameterType) { 997 mAdapter = adapter; 998 mParameterType = parameterType; 999 } 1000 1001 @Override 1002 public String toJavaInternal(String componentExpression, String viewExpression, 1003 String valueExpression) { 1004 return createAdapterCall(mAdapter, mBindingAdapterCall, componentExpression, 1005 viewExpression, mCastString + valueExpression); 1006 } 1007 1008 @Override 1009 protected String toJavaInternal(String componentExpression, String viewExpression, 1010 String oldValue, String valueExpression) { 1011 return createAdapterCall(mAdapter, mBindingAdapterCall, componentExpression, 1012 viewExpression, mCastString + oldValue, mCastString + valueExpression); 1013 } 1014 1015 @Override 1016 public int getMinApi() { 1017 return 1; 1018 } 1019 1020 @Override 1021 public boolean requiresOldValue() { 1022 return mAdapter.requiresOldValue; 1023 } 1024 1025 @Override 1026 public ModelClass[] getParameterTypes() { 1027 return new ModelClass[] { mParameterType }; 1028 } 1029 1030 @Override 1031 public String getBindingAdapterInstanceClass() { 1032 return mAdapter.isStatic ? null : mAdapter.type; 1033 } 1034 1035 @Override 1036 public void setBindingAdapterCall(String method) { 1037 mBindingAdapterCall = method; 1038 } 1039 } 1040 1041 public static class ModelMethodSetter extends SetterCall { 1042 final ModelMethod mModelMethod; 1043 1044 public ModelMethodSetter(ModelMethod modelMethod) { 1045 mModelMethod = modelMethod; 1046 } 1047 1048 @Override 1049 public String toJavaInternal(String componentExpression, String viewExpression, 1050 String valueExpression) { 1051 return viewExpression + "." + mModelMethod.getName() + "(" + mCastString + 1052 valueExpression + ")"; 1053 } 1054 1055 @Override 1056 protected String toJavaInternal(String componentExpression, String viewExpression, 1057 String oldValue, String valueExpression) { 1058 return viewExpression + "." + mModelMethod.getName() + "(" + 1059 mCastString + oldValue + ", " + mCastString + valueExpression + ")"; 1060 } 1061 1062 @Override 1063 public int getMinApi() { 1064 return mModelMethod.getMinApi(); 1065 } 1066 1067 @Override 1068 public boolean requiresOldValue() { 1069 return mModelMethod.getParameterTypes().length == 3; 1070 } 1071 1072 @Override 1073 public ModelClass[] getParameterTypes() { 1074 return new ModelClass[] { mModelMethod.getParameterTypes()[0] }; 1075 } 1076 1077 @Override 1078 public String getBindingAdapterInstanceClass() { 1079 return null; 1080 } 1081 1082 @Override 1083 public void setBindingAdapterCall(String method) { 1084 } 1085 } 1086 1087 public interface BindingSetterCall { 1088 String toJava(String componentExpression, String viewExpression, 1089 String... valueExpressions); 1090 1091 int getMinApi(); 1092 1093 boolean requiresOldValue(); 1094 1095 ModelClass[] getParameterTypes(); 1096 1097 String getBindingAdapterInstanceClass(); 1098 1099 void setBindingAdapterCall(String method); 1100 } 1101 1102 public static abstract class SetterCall implements BindingSetterCall { 1103 private MethodDescription mConverter; 1104 protected String mCastString = ""; 1105 1106 public SetterCall() { 1107 } 1108 1109 public void setConverter(MethodDescription converter) { 1110 mConverter = converter; 1111 } 1112 1113 protected abstract String toJavaInternal(String componentExpression, String viewExpression, 1114 String converted); 1115 1116 protected abstract String toJavaInternal(String componentExpression, String viewExpression, 1117 String oldValue, String converted); 1118 1119 @Override 1120 public final String toJava(String componentExpression, String viewExpression, 1121 String... valueExpression) { 1122 Preconditions.check(valueExpression.length == 2, "value expressions size must be 2"); 1123 if (requiresOldValue()) { 1124 return toJavaInternal(componentExpression, viewExpression, 1125 convertValue(valueExpression[0]), convertValue(valueExpression[1])); 1126 } else { 1127 return toJavaInternal(componentExpression, viewExpression, 1128 convertValue(valueExpression[1])); 1129 } 1130 } 1131 1132 protected String convertValue(String valueExpression) { 1133 return mConverter == null ? valueExpression : 1134 mConverter.type + "." + mConverter.method + "(" + valueExpression + ")"; 1135 } 1136 1137 abstract public int getMinApi(); 1138 1139 public void setCast(ModelClass castTo) { 1140 mCastString = "(" + castTo.toJavaCode() + ") "; 1141 } 1142 } 1143 1144 public static class MultiAttributeSetter implements BindingSetterCall { 1145 public final String[] attributes; 1146 private final MethodDescription mAdapter; 1147 private final MethodDescription[] mConverters; 1148 private final String[] mCasts; 1149 private final MultiValueAdapterKey mKey; 1150 private final boolean[] mSupplied; 1151 String mBindingAdapterCall; 1152 1153 public MultiAttributeSetter(MultiValueAdapterKey key, boolean[] supplied, 1154 MethodDescription adapter, MethodDescription[] converters, String[] casts) { 1155 Preconditions.check(converters != null && 1156 converters.length == key.attributes.length && 1157 casts != null && casts.length == key.attributes.length && 1158 supplied.length == key.attributes.length, 1159 "invalid arguments to create multi attr setter"); 1160 this.mAdapter = adapter; 1161 this.mConverters = converters; 1162 this.mCasts = casts; 1163 this.mKey = key; 1164 this.mSupplied = supplied; 1165 if (key.requireAll) { 1166 this.attributes = key.attributes; 1167 } else { 1168 int numSupplied = 0; 1169 for (int i = 0; i < mKey.attributes.length; i++) { 1170 if (supplied[i]) { 1171 numSupplied++; 1172 } 1173 } 1174 if (numSupplied == key.attributes.length) { 1175 this.attributes = key.attributes; 1176 } else { 1177 this.attributes = new String[numSupplied]; 1178 int attrIndex = 0; 1179 for (int i = 0; i < key.attributes.length; i++) { 1180 if (supplied[i]) { 1181 attributes[attrIndex++] = key.attributes[i]; 1182 } 1183 } 1184 } 1185 } 1186 } 1187 1188 @Override 1189 public final String toJava(String componentExpression, String viewExpression, 1190 String[] valueExpressions) { 1191 Preconditions.check(valueExpressions.length == attributes.length * 2, 1192 "MultiAttributeSetter needs %s items, received %s", 1193 Arrays.toString(attributes), Arrays.toString(valueExpressions)); 1194 final int numAttrs = mKey.attributes.length; 1195 String[] args = new String[numAttrs + (requiresOldValue() ? numAttrs : 0)]; 1196 1197 final int startIndex = mAdapter.requiresOldValue ? 0 : numAttrs; 1198 int attrIndex = mAdapter.requiresOldValue ? 0 : attributes.length; 1199 final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance(); 1200 StringBuilder argBuilder = new StringBuilder(); 1201 final int endIndex = numAttrs * 2; 1202 for (int i = startIndex; i < endIndex; i++) { 1203 argBuilder.setLength(0); 1204 if (!mSupplied[i % numAttrs]) { 1205 final String paramType = mKey.parameterTypes[i % numAttrs]; 1206 final String defaultValue = modelAnalyzer.getDefaultValue(paramType); 1207 argBuilder.append('(') 1208 .append(paramType) 1209 .append(')') 1210 .append(defaultValue); 1211 } else { 1212 if (mConverters[i % numAttrs] != null) { 1213 final MethodDescription converter = mConverters[i % numAttrs]; 1214 argBuilder.append(converter.type) 1215 .append('.') 1216 .append(converter.method) 1217 .append('(') 1218 .append(valueExpressions[attrIndex]) 1219 .append(')'); 1220 } else { 1221 if (mCasts[i % numAttrs] != null) { 1222 argBuilder.append('(') 1223 .append(mCasts[i % numAttrs]) 1224 .append(')'); 1225 } 1226 argBuilder.append(valueExpressions[attrIndex]); 1227 } 1228 attrIndex++; 1229 } 1230 args[i - startIndex] = argBuilder.toString(); 1231 } 1232 return createAdapterCall(mAdapter, mBindingAdapterCall, componentExpression, 1233 viewExpression, args); 1234 } 1235 1236 @Override 1237 public int getMinApi() { 1238 return 1; 1239 } 1240 1241 @Override 1242 public boolean requiresOldValue() { 1243 return mAdapter.requiresOldValue; 1244 } 1245 1246 @Override 1247 public ModelClass[] getParameterTypes() { 1248 ModelClass[] parameters = new ModelClass[attributes.length]; 1249 String[] paramTypeStrings = mKey.parameterTypes; 1250 ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance(); 1251 int attrIndex = 0; 1252 for (int i = 0; i < mKey.attributes.length; i++) { 1253 if (mSupplied[i]) { 1254 parameters[attrIndex++] = modelAnalyzer.findClass(paramTypeStrings[i], null); 1255 } 1256 } 1257 return parameters; 1258 } 1259 1260 @Override 1261 public String getBindingAdapterInstanceClass() { 1262 return mAdapter.isStatic ? null : mAdapter.type; 1263 } 1264 1265 @Override 1266 public void setBindingAdapterCall(String method) { 1267 mBindingAdapterCall = method; 1268 } 1269 1270 @Override 1271 public String toString() { 1272 return "MultiAttributeSetter{" + 1273 "attributes=" + Arrays.toString(attributes) + 1274 ", mAdapter=" + mAdapter + 1275 ", mConverters=" + Arrays.toString(mConverters) + 1276 ", mCasts=" + Arrays.toString(mCasts) + 1277 ", mKey=" + mKey + 1278 '}'; 1279 } 1280 } 1281} 1282