1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.metalava.model.text 18 19 import com.android.tools.metalava.model.ClassResolver 20 import com.android.tools.metalava.model.JAVA_LANG_PACKAGE 21 import com.android.tools.metalava.model.JAVA_LANG_PREFIX 22 23 /** 24 * Encapsulates information about the contents of the `java.lang` package obtained from a number of 25 * different sources, e.g. a [ClassResolver] or Metalava's own classpath, depending on what is 26 * available. 27 */ 28 abstract class JavaLangPackage { 29 /** Cache for the result of [check]. */ 30 private val nameToBoolean = mutableMapOf<String, Boolean>() 31 32 /** 33 * Check to see if [name] exists. 34 * 35 * @param name the qualified name of a class in `java.lang` package and not its sub-packages. 36 */ containsQualifiednull37 fun containsQualified(name: String): Boolean { 38 require(name.startsWith(JAVA_LANG_PREFIX)) { "'$name' must start with '$JAVA_LANG_PREFIX'" } 39 require(name.lastIndexOf('.') == JAVA_LANG_PACKAGE.length) { 40 "'$name' must not be in a sub-package of '$JAVA_LANG_PACKAGE'" 41 } 42 return nameToBoolean.computeIfAbsent(name, ::check) 43 } 44 checknull45 protected abstract fun check(name: String): Boolean 46 47 companion object { 48 /** 49 * A [JavaLangPackage] implementation that uses reflection to check the running process's 50 * `java.lang` package. 51 * 52 * This may not be exactly the same as the `java.lang` package that is usable from the API 53 * being read, but it is better than just assuming every unqualified type is part of 54 * `java.lang`. 55 */ 56 val DEFAULT: JavaLangPackage = JavaLangPackageViaReflection() 57 } 58 59 private class JavaLangPackageViaReflection : JavaLangPackage() { 60 private val platformClassLoader = ClassLoader.getPlatformClassLoader() 61 checknull62 override fun check(name: String) = 63 try { 64 // Try and load the class. 65 platformClassLoader.loadClass(name) 66 // The class was loaded so it 67 true 68 } catch (_: ClassNotFoundException) { 69 // The class could not be found so it does not exist. 70 false 71 } 72 } 73 } 74