• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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