Make our Android builds work with an Android bootclasspath.

Notably:

- Remove all usages of `AnnotatedType` from the Android flavor.
- Make `NullPointerTester` a no-op in the Android flavor (instead of only in the Android flavor _when running under an Android VM_).
  - (This requires removing its tests from the Android flavor entirely, rather than merely skipping them during our internal Android-VM test runs.)

In both cases, these changes apply only to (a) guava-android and (b) our actual internal _Android_ builds. In contrast, in the internal copy of the backport _that we test under a JRE_, the `AnnotatedType` APIs are still in place, and `NullPointerTester` still runs.

RELNOTES=`reflect`: In `guava-android` only, removed `Invokable.getAnnotatedReturnType()` and `Parameter.getAnnotatedType()`. These methods never worked in an Android VM, and to reflect that, they were born `@Deprecated`, `@Beta`, and `@DoNotCall`. They're now preventing us from rolling out some new Android compatibility testing.
PiperOrigin-RevId: 583032835
This commit is contained in:
cpovirk 2023-11-16 07:09:11 -08:00 committed by Google Java Core Libraries
parent 7feac90308
commit 045cd8428f
11 changed files with 27 additions and 2927 deletions

View File

@ -35,7 +35,6 @@ import com.google.common.reflect.Reflection;
import com.google.common.reflect.TypeToken;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
@ -43,7 +42,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
@ -353,9 +351,9 @@ public final class NullPointerTester {
@Nullable Object instance, Invokable<?, ?> invokable, int paramIndex, Class<?> testedClass) {
/*
* com.google.common is starting to rely on type-use annotations, which aren't visible under
* Android VMs. So we skip testing there.
* Android VMs and in open-source guava-android. So we skip testing there.
*/
if (isAndroid() && Reflection.getPackageName(testedClass).startsWith("com.google.common")) {
if (Reflection.getPackageName(testedClass).startsWith("com.google.common")) {
return;
}
if (isPrimitiveOrNullable(invokable.getParameters().get(paramIndex))) {
@ -612,39 +610,19 @@ public final class NullPointerTester {
* don't know that anyone uses it there, anyway.
*/
private enum NullnessAnnotationReader {
// Usages (which are unsafe only for Android) are guarded by the annotatedTypeExists() check.
@SuppressWarnings({"Java7ApiChecker", "AndroidApiChecker", "DoNotCall", "deprecation"})
@SuppressWarnings("Java7ApiChecker")
FROM_DECLARATION_AND_TYPE_USE_ANNOTATIONS {
@Override
@IgnoreJRERequirement
boolean isNullable(Invokable<?, ?> invokable) {
return FROM_DECLARATION_ANNOTATIONS_ONLY.isNullable(invokable)
|| containsNullable(invokable.getAnnotatedReturnType().getAnnotations());
;
// TODO(cpovirk): Should we also check isNullableTypeVariable?
}
@Override
@IgnoreJRERequirement
boolean isNullable(Parameter param) {
return FROM_DECLARATION_ANNOTATIONS_ONLY.isNullable(param)
|| containsNullable(param.getAnnotatedType().getAnnotations())
|| isNullableTypeVariable(param.getAnnotatedType().getType());
}
@IgnoreJRERequirement
boolean isNullableTypeVariable(Type type) {
if (!(type instanceof TypeVariable)) {
return false;
}
TypeVariable<?> typeVar = (TypeVariable<?>) type;
for (AnnotatedType bound : typeVar.getAnnotatedBounds()) {
// Until Java 15, the isNullableTypeVariable case here won't help:
// https://bugs.openjdk.java.net/browse/JDK-8202469
if (containsNullable(bound.getAnnotations()) || isNullableTypeVariable(bound.getType())) {
return true;
}
}
return false;
;
}
},
FROM_DECLARATION_ANNOTATIONS_ONLY {
@ -663,9 +641,4 @@ public final class NullPointerTester {
abstract boolean isNullable(Parameter param);
}
private static boolean isAndroid() {
// Arguably it would make more sense to test "can we see type-use annotations" directly....
return checkNotNull(System.getProperty("java.runtime.name", "")).contains("Android");
}
}

View File

@ -16,14 +16,11 @@ package com.google.common.reflect;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotCall;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
@ -278,7 +275,7 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
Type[] parameterTypes = getGenericParameterTypes();
Annotation[][] annotations = getParameterAnnotations();
@Nullable Object[] annotatedTypes =
ANNOTATED_TYPE_EXISTS ? getAnnotatedParameterTypes() : new Object[parameterTypes.length];
new Object[parameterTypes.length];
ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
for (int i = 0; i < parameterTypes.length; i++) {
builder.add(
@ -343,10 +340,6 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
abstract Type[] getGenericParameterTypes();
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
abstract AnnotatedType[] getAnnotatedParameterTypes();
/** This should never return a type that's not a subtype of Throwable. */
abstract Type[] getGenericExceptionTypes();
@ -354,22 +347,6 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
abstract Type getGenericReturnType();
/**
* Returns the {@link AnnotatedType} for the return type.
*
* <p>This method will fail if run under an Android VM.
*
* @since NEXT for guava-android (available since 14.0 in guava-jre)
* @deprecated This method does not work under Android VMs. It is safe to use from guava-jre, but
* this copy in guava-android is not safe to use.
*/
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@DoNotCall("fails under Android VMs; do not use from guava-android")
@Deprecated
@IgnoreJRERequirement
@Beta
public abstract AnnotatedType getAnnotatedReturnType();
static class MethodInvokable<T> extends Invokable<T, Object> {
final Method method;
@ -396,21 +373,6 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
return method.getGenericParameterTypes();
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
AnnotatedType[] getAnnotatedParameterTypes() {
return method.getAnnotatedParameterTypes();
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker", "DoNotCall"})
@DoNotCall
@IgnoreJRERequirement
public AnnotatedType getAnnotatedReturnType() {
return method.getAnnotatedReturnType();
}
@Override
Type[] getGenericExceptionTypes() {
return method.getGenericExceptionTypes();
@ -488,21 +450,6 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
return types;
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
AnnotatedType[] getAnnotatedParameterTypes() {
return constructor.getAnnotatedParameterTypes();
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker", "DoNotCall"})
@DoNotCall
@IgnoreJRERequirement
public AnnotatedType getAnnotatedReturnType() {
return constructor.getAnnotatedReturnType();
}
@Override
Type[] getGenericExceptionTypes() {
return constructor.getGenericExceptionTypes();

View File

@ -15,15 +15,11 @@
package com.google.common.reflect;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.DoNotCall;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.AnnotatedType;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -42,7 +38,7 @@ public final class Parameter implements AnnotatedElement {
private final ImmutableList<Annotation> annotations;
/**
* An {@link AnnotatedType} instance, or {@code null} under Android VMs (possible only when using
* An {@code AnnotatedType} instance, or {@code null} under Android VMs (possible only when using
* the Android flavor of Guava). The field is declared with a type of {@code Object} to avoid
* compatibility problems on Android VMs. The corresponding accessor method, however, can have the
* more specific return type as long as users are careful to guard calls to it with version checks
@ -131,24 +127,6 @@ public final class Parameter implements AnnotatedElement {
return cast;
}
/**
* Returns the {@link AnnotatedType} of the parameter.
*
* <p>This method will fail if run under an Android VM.
*
* @since NEXT for guava-android (available since 25.1 in guava-jre)
* @deprecated This method does not work under Android VMs. It is safe to use from guava-jre, but
* this copy in guava-android is not safe to use.
*/
@Beta
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@Deprecated
@DoNotCall("fails under Android VMs; do not use from guava-android")
@IgnoreJRERequirement
public AnnotatedType getAnnotatedType() {
return requireNonNull((AnnotatedType) annotatedType);
}
@Override
public boolean equals(@CheckForNull Object obj) {
if (obj instanceof Parameter) {

View File

@ -352,13 +352,6 @@ public final class NullPointerTester {
*/
private void testParameter(
@Nullable Object instance, Invokable<?, ?> invokable, int paramIndex, Class<?> testedClass) {
/*
* com.google.common is starting to rely on type-use annotations, which aren't visible under
* Android VMs. So we skip testing there.
*/
if (isAndroid() && Reflection.getPackageName(testedClass).startsWith("com.google.common")) {
return;
}
if (isPrimitiveOrNullable(invokable.getParameters().get(paramIndex))) {
return; // there's nothing to test
}
@ -613,11 +606,9 @@ public final class NullPointerTester {
* don't know that anyone uses it there, anyway.
*/
private enum NullnessAnnotationReader {
// Usages (which are unsafe only for Android) are guarded by the annotatedTypeExists() check.
@SuppressWarnings({"Java7ApiChecker", "AndroidApiChecker", "DoNotCall", "deprecation"})
@SuppressWarnings("Java7ApiChecker")
FROM_DECLARATION_AND_TYPE_USE_ANNOTATIONS {
@Override
@IgnoreJRERequirement
boolean isNullable(Invokable<?, ?> invokable) {
return FROM_DECLARATION_ANNOTATIONS_ONLY.isNullable(invokable)
|| containsNullable(invokable.getAnnotatedReturnType().getAnnotations());
@ -625,14 +616,12 @@ public final class NullPointerTester {
}
@Override
@IgnoreJRERequirement
boolean isNullable(Parameter param) {
return FROM_DECLARATION_ANNOTATIONS_ONLY.isNullable(param)
|| containsNullable(param.getAnnotatedType().getAnnotations())
|| isNullableTypeVariable(param.getAnnotatedType().getType());
}
@IgnoreJRERequirement
boolean isNullableTypeVariable(Type type) {
if (!(type instanceof TypeVariable)) {
return false;
@ -664,9 +653,4 @@ public final class NullPointerTester {
abstract boolean isNullable(Parameter param);
}
private static boolean isAndroid() {
// Arguably it would make more sense to test "can we see type-use annotations" directly....
return checkNotNull(System.getProperty("java.runtime.name", "")).contains("Android");
}
}

View File

@ -46,7 +46,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* @author Ben Yu
*/
@AndroidIncompatible // NullPointerTester refuses to run for c.g.c under Android
public class ClassSanityTesterTest extends TestCase {
private final ClassSanityTester tester = new ClassSanityTester();

View File

@ -57,7 +57,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* @author Mick Killianey
*/
@SuppressWarnings("CheckReturnValue")
@AndroidIncompatible // NullPointerTester refuses to run for c.g.c under Android
public class NullPointerTesterTest extends TestCase {
/** Non-NPE RuntimeException. */

View File

@ -341,8 +341,7 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
abstract Type[] getGenericParameterTypes();
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
abstract AnnotatedType[] getAnnotatedParameterTypes();
/** This should never return a type that's not a subtype of Throwable. */
@ -355,12 +354,9 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
/**
* Returns the {@link AnnotatedType} for the return type.
*
* <p>This method will fail if run under an Android VM.
*
* @since 14.0 for guava-jre (available since 32.0.0 in guava-android)
* @since 14.0
*/
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
public abstract AnnotatedType getAnnotatedReturnType();
static class MethodInvokable<T> extends Invokable<T, Object> {
@ -390,15 +386,13 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
AnnotatedType[] getAnnotatedParameterTypes() {
return method.getAnnotatedParameterTypes();
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker", "DoNotCall"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
public AnnotatedType getAnnotatedReturnType() {
return method.getAnnotatedReturnType();
}
@ -481,15 +475,13 @@ public abstract class Invokable<T, R> implements AnnotatedElement, Member {
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
AnnotatedType[] getAnnotatedParameterTypes() {
return constructor.getAnnotatedParameterTypes();
}
@Override
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker", "DoNotCall"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
public AnnotatedType getAnnotatedReturnType() {
return constructor.getAnnotatedReturnType();
}

View File

@ -40,7 +40,7 @@ public final class Parameter implements AnnotatedElement {
private final ImmutableList<Annotation> annotations;
/**
* An {@link AnnotatedType} instance, or {@code null} under Android VMs (possible only when using
* An {@code AnnotatedType} instance, or {@code null} under Android VMs (possible only when using
* the Android flavor of Guava). The field is declared with a type of {@code Object} to avoid
* compatibility problems on Android VMs. The corresponding accessor method, however, can have the
* more specific return type as long as users are careful to guard calls to it with version checks
@ -93,7 +93,9 @@ public final class Parameter implements AnnotatedElement {
return getDeclaredAnnotations();
}
/** @since 18.0 */
/**
* @since 18.0
*/
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
return getDeclaredAnnotationsByType(annotationType);
@ -105,7 +107,9 @@ public final class Parameter implements AnnotatedElement {
return annotations.toArray(new Annotation[0]);
}
/** @since 18.0 */
/**
* @since 18.0
*/
@Override
@CheckForNull
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationType) {
@ -113,7 +117,9 @@ public final class Parameter implements AnnotatedElement {
return FluentIterable.from(annotations).filter(annotationType).first().orNull();
}
/** @since 18.0 */
/**
* @since 18.0
*/
@Override
public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationType) {
@Nullable
@ -126,12 +132,9 @@ public final class Parameter implements AnnotatedElement {
/**
* Returns the {@link AnnotatedType} of the parameter.
*
* <p>This method will fail if run under an Android VM.
*
* @since 25.1 for guava-jre (available since 32.0.0 in guava-android)
* @since 25.1 for guava-jre
*/
@SuppressWarnings({"Java7ApiChecker", "AndroidJdkLibsChecker"})
@IgnoreJRERequirement
@SuppressWarnings("Java7ApiChecker")
public AnnotatedType getAnnotatedType() {
return requireNonNull((AnnotatedType) annotatedType);
}

View File

@ -1,9 +0,0 @@
# Warning: common.reflect (like reflection in general) is typically slow and
# unreliable under Android. We do not recommend using it. This Proguard config
# exists only to avoid breaking the builds of users who already have
# common.reflect in their transitive dependencies.
#
-dontwarn com.google.common.reflect.Invokable
-dontwarn com.google.common.reflect.Invokable$ConstructorInvokable
-dontwarn com.google.common.reflect.Invokable$MethodInvokable
-dontwarn com.google.common.reflect.Parameter