[go: nahoru, domu]

blob: 0685df81913b3e0b28973189242bf6616c7b7d50 [file] [log] [blame]
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.window.core
import android.annotation.SuppressLint
import android.util.Pair
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import kotlin.reflect.KClass
import kotlin.reflect.cast
/**
* An adapter over {@link java.util.function.Predicate} to workaround mismatch in expected extension
* API signatures after library desugaring. See b/203472665
*/
@SuppressLint("BanUncheckedReflection")
internal class PredicateAdapter(
private val loader: ClassLoader
) {
internal fun predicateClassOrNull(): Class<*>? {
return try {
predicateClassOrThrow()
} catch (e: ClassNotFoundException) {
null
}
}
private fun predicateClassOrThrow(): Class<*> {
return loader.loadClass("java.util.function.Predicate")
}
fun <T : Any> buildPredicate(clazz: KClass<T>, predicate: (T) -> Boolean): Any {
val predicateHandler = PredicateStubHandler(
clazz,
predicate
)
return Proxy.newProxyInstance(loader, arrayOf(predicateClassOrThrow()), predicateHandler)
}
fun <T : Any, U : Any> buildPairPredicate(
firstClazz: KClass<T>,
secondClazz: KClass<U>,
predicate: (T, U) -> Boolean
): Any {
val predicateHandler = PairPredicateStubHandler(
firstClazz,
secondClazz,
predicate
)
return Proxy.newProxyInstance(loader, arrayOf(predicateClassOrThrow()), predicateHandler)
}
private abstract class BaseHandler<T : Any>(private val clazz: KClass<T>) : InvocationHandler {
override fun invoke(obj: Any, method: Method, parameters: Array<out Any>?): Any {
return when {
method.isTest(parameters) -> {
val argument = clazz.cast(parameters?.get(0))
invokeTest(obj, argument)
}
method.isEquals(parameters) -> {
obj === parameters?.get(0)!!
}
method.isHashCode(parameters) -> {
hashCode()
}
method.isToString(parameters) -> {
toString()
}
else -> {
throw UnsupportedOperationException(
"Unexpected method call object:$obj, method: $method, args: $parameters"
)
}
}
}
abstract fun invokeTest(obj: Any, parameter: T): Boolean
protected fun Method.isEquals(args: Array<out Any>?): Boolean {
return name == "equals" && returnType.equals(Boolean::class.java) && args?.size == 1
}
protected fun Method.isHashCode(args: Array<out Any>?): Boolean {
return name == "hashCode" && returnType.equals(Int::class.java) && args == null
}
protected fun Method.isTest(args: Array<out Any>?): Boolean {
return name == "test" && returnType.equals(Boolean::class.java) && args?.size == 1
}
protected fun Method.isToString(args: Array<out Any>?): Boolean {
return name == "toString" && returnType.equals(String::class.java) && args == null
}
}
private class PredicateStubHandler<T : Any>(
clazzT: KClass<T>,
private val predicate: (T) -> Boolean
) : BaseHandler<T>(clazzT) {
override fun invokeTest(obj: Any, parameter: T): Boolean {
return predicate(parameter)
}
override fun hashCode(): Int {
return predicate.hashCode()
}
override fun toString(): String {
return predicate.toString()
}
}
private class PairPredicateStubHandler<T : Any, U : Any>(
private val clazzT: KClass<T>,
private val clazzU: KClass<U>,
private val predicate: (T, U) -> Boolean
) : BaseHandler<Pair<*, *>>(Pair::class) {
override fun invokeTest(obj: Any, parameter: Pair<*, *>): Boolean {
val t = clazzT.cast(parameter.first)
val u = clazzU.cast(parameter.second)
return predicate(t, u)
}
override fun hashCode(): Int {
return predicate.hashCode()
}
override fun toString(): String {
return predicate.toString()
}
}
}