197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar/* 297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Copyright (C) 2015 The Android Open Source Project 397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * you may not use this file except in compliance with the License. 597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * You may obtain a copy of the License at 697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Unless required by applicable law or agreed to in writing, software 897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * See the License for the specific language governing permissions and 1197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * limitations under the License. 1297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */ 1397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 14fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.reflection.java; 1597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 16fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer; 17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass; 18fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.SdkUtil; 19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.TypeUtil; 20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L; 2197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 2297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.io.File; 2397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.net.MalformedURLException; 2497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.net.URL; 2597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.net.URLClassLoader; 2697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.util.HashMap; 2797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.util.Map; 2897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 2997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarpublic class JavaAnalyzer extends ModelAnalyzer { 302611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar public static final Map<String, Class> PRIMITIVE_TYPES; 312611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar static { 322611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES = new HashMap<String, Class>(); 332611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("boolean", boolean.class); 342611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("byte", byte.class); 352611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("short", short.class); 362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("char", char.class); 372611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("int", int.class); 382611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("long", long.class); 392611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("float", float.class); 402611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar PRIMITIVE_TYPES.put("double", double.class); 412611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar } 4297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 43895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar private HashMap<String, JavaClass> mClassCache = new HashMap<String, JavaClass>(); 4497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 4597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private final ClassLoader mClassLoader; 4697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 47fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount public JavaAnalyzer(ClassLoader classLoader) { 4897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar setInstance(this); 4997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mClassLoader = classLoader; 5097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 5197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 5297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar @Override 5397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public JavaClass loadPrimitive(String className) { 5497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar Class clazz = PRIMITIVE_TYPES.get(className); 5597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (clazz == null) { 5697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return null; 5797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } else { 5897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return new JavaClass(clazz); 5997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 6097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 6197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 6297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar @Override 63924fa7c597694ebc433fc0379d0015785351d1b7Yigit Boyar protected ModelClass[] getObservableFieldTypes() { 64924fa7c597694ebc433fc0379d0015785351d1b7Yigit Boyar return new ModelClass[0]; 65924fa7c597694ebc433fc0379d0015785351d1b7Yigit Boyar } 66924fa7c597694ebc433fc0379d0015785351d1b7Yigit Boyar 67924fa7c597694ebc433fc0379d0015785351d1b7Yigit Boyar @Override 6897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public ModelClass findClass(String className, Map<String, String> imports) { 6997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar // TODO handle imports 7097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar JavaClass loaded = mClassCache.get(className); 7197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (loaded != null) { 7297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return loaded; 7397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 7497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.d("trying to load class %s from %s", className, mClassLoader.toString()); 7597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar loaded = loadPrimitive(className); 7697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (loaded == null) { 7797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar try { 7897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (className.startsWith("[") && className.contains("L")) { 7997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar int indexOfL = className.indexOf('L'); 8097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar JavaClass baseClass = (JavaClass) findClass( 8197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar className.substring(indexOfL + 1, className.length() - 1), null); 8297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String realClassName = className.substring(0, indexOfL + 1) + 8397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar baseClass.mClass.getCanonicalName() + ';'; 8497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar loaded = new JavaClass(Class.forName(realClassName, false, mClassLoader)); 8597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mClassCache.put(className, loaded); 8697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } else { 8797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar loaded = loadRecursively(className); 8897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mClassCache.put(className, loaded); 8997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 9097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 9197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } catch (Throwable t) { 9297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar// L.e(t, "cannot load class " + className); 9397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 9497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 9597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar // expr visitor may call this to resolve statics. Sometimes, it is OK not to find a class. 9697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (loaded == null) { 9797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return null; 9897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 9997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.d("loaded class %s", loaded.mClass.getCanonicalName()); 10097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return loaded; 10197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 10297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 10397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar @Override 10497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public ModelClass findClass(Class classType) { 10597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return new JavaClass(classType); 10697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 10797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 10897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar @Override 10997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public TypeUtil createTypeUtil() { 11097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return new JavaTypeUtil(); 11197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 11297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 11397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private JavaClass loadRecursively(String className) throws ClassNotFoundException { 11497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar try { 11597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.d("recursively checking %s", className); 11697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return new JavaClass(mClassLoader.loadClass(className)); 11797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } catch (ClassNotFoundException ex) { 11897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar int lastIndexOfDot = className.lastIndexOf("."); 11997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (lastIndexOfDot == -1) { 12097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar throw ex; 12197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return loadRecursively(className.substring(0, lastIndexOfDot) + "$" + className 12397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar .substring(lastIndexOfDot + 1)); 12497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 12797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public static void initForTests() { 12897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar Map<String, String> env = System.getenv(); 12997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar for (Map.Entry<String, String> entry : env.entrySet()) { 13097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.d("%s %s", entry.getKey(), entry.getValue()); 13197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 13297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String androidHome = env.get("ANDROID_HOME"); 13397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (androidHome == null) { 134fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount throw new IllegalStateException( 135fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount "you need to have ANDROID_HOME set in your environment" 136fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount + " to run compiler tests"); 13797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 13897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar File androidJar = new File(androidHome + "/platforms/android-21/android.jar"); 13997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (!androidJar.exists() || !androidJar.canRead()) { 14097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar throw new IllegalStateException( 14197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar "cannot find android jar at " + androidJar.getAbsolutePath()); 14297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 14397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar // now load android data binding library as well 14497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 14597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar try { 14697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar ClassLoader classLoader = new URLClassLoader(new URL[]{androidJar.toURI().toURL()}, 14797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar ModelAnalyzer.class.getClassLoader()); 148fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount new JavaAnalyzer(classLoader); 14997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } catch (MalformedURLException e) { 15097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar throw new RuntimeException("cannot create class loader", e); 15197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 15397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar SdkUtil.initialize(8, new File(androidHome)); 15497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar} 156