From 2b98d3c1e96b750dc997c29f283084aeb72fb3cf Mon Sep 17 00:00:00 2001 From: cpovirk Date: Fri, 21 Apr 2023 18:12:48 -0700 Subject: [PATCH] Reannotate `ClassToInstanceMap` and `TypeToInstanceMap` to use `Class<@NonNull ...>`. (prompted by the mention of `Class` types in cl/519736884) This lets us express that they can contain null values. See discussion in https://github.com/jspecify/jspecify/issues/86#issuecomment-1030308383 RELNOTES=n/a PiperOrigin-RevId: 526184065 --- .../common/collect/ClassToInstanceMap.java | 28 +++----- .../collect/ImmutableClassToInstanceMap.java | 5 +- .../collect/MutableClassToInstanceMap.java | 67 ++++++++++--------- .../reflect/MutableTypeToInstanceMap.java | 44 ++++++------ .../common/reflect/TypeToInstanceMap.java | 17 +++-- .../com/google/common/collect/Collect.gwt.xml | 1 + .../common/collect/ClassToInstanceMap.java | 28 +++----- .../collect/ImmutableClassToInstanceMap.java | 5 +- .../collect/MutableClassToInstanceMap.java | 67 ++++++++++--------- .../reflect/MutableTypeToInstanceMap.java | 44 ++++++------ .../common/reflect/TypeToInstanceMap.java | 17 +++-- 11 files changed, 159 insertions(+), 164 deletions(-) diff --git a/android/guava/src/com/google/common/collect/ClassToInstanceMap.java b/android/guava/src/com/google/common/collect/ClassToInstanceMap.java index 8fbdfd9ebfc7..a34c6ad5f0c4 100644 --- a/android/guava/src/com/google/common/collect/ClassToInstanceMap.java +++ b/android/guava/src/com/google/common/collect/ClassToInstanceMap.java @@ -21,6 +21,8 @@ import com.google.errorprone.annotations.DoNotMock; import java.util.Map; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A map, each entry of which maps a Java raw type to an @@ -30,17 +32,6 @@ *

Like any other {@code Map}, this map may contain entries for primitive types, * and a primitive type and its corresponding wrapper type may map to different values. * - *

This class's support for {@code null} requires some explanation: From release 31.0 onward, - * Guava specifies the nullness of its types through annotations. In the case of {@code - * ClassToInstanceMap}, it specifies that both the key and value types are restricted to - * non-nullable types. This specification is reasonable for keys, which must be non-null - * classes. This is in contrast to the specification for values: Null values are - * supported by the implementation {@link MutableClassToInstanceMap}, even though that - * implementation and this interface specify otherwise. Thus, if you use a nullness checker, you can - * safely suppress any warnings it produces when you write null values into a {@code - * MutableClassToInstanceMap}. Just be sure to be prepared for null values when reading from it, - * since nullness checkers will assume that values are non-null then, too. - * *

See the Guava User Guide article on {@code * ClassToInstanceMap}. @@ -48,25 +39,22 @@ *

To map a generic type to an instance of that type, use {@link * com.google.common.reflect.TypeToInstanceMap} instead. * - * @param the common supertype that all entries must share; often this is simply {@link Object} - * @author Kevin Bourrillion + * @param the common supertype that all values will share. When in doubt, just use {@link + * Object}, or use {@code @Nullable Object} to allow null values. * @since 2.0 */ @DoNotMock("Use ImmutableClassToInstanceMap or MutableClassToInstanceMap") @GwtCompatible @ElementTypesAreNonnullByDefault -// If we ever support non-null projections (https://github.com/jspecify/jspecify/issues/86), -// we might annotate this as... -// ClassToInstanceMap extends Map, B> -// ...and change its methods similarly ( or Class<@Nonnull T>). -public interface ClassToInstanceMap extends Map, B> { +public interface ClassToInstanceMap + extends Map, B> { /** * Returns the value the specified class is mapped to, or {@code null} if no entry for this class * is present. This will only return a value that was bound to this specific class, not a value * that may have been bound to a subtype. */ @CheckForNull - T getInstance(Class type); + T getInstance(Class type); /** * Maps the specified class to the specified value. Does not associate this value with any @@ -77,5 +65,5 @@ public interface ClassToInstanceMap extends Map, B> { */ @CanIgnoreReturnValue @CheckForNull - T putInstance(Class type, T value); + T putInstance(Class<@NonNull T> type, @ParametricNullness T value); } diff --git a/android/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java b/android/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java index dfa331c46c6d..5c907f7cd468 100644 --- a/android/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java +++ b/android/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java @@ -26,6 +26,7 @@ import java.io.Serializable; import java.util.Map; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A {@link ClassToInstanceMap} whose contents will never change, with many other important @@ -37,7 +38,9 @@ @Immutable(containerOf = "B") @GwtIncompatible @ElementTypesAreNonnullByDefault -public final class ImmutableClassToInstanceMap extends ForwardingMap, B> +// TODO(b/278589132): Remove the redundant "@NonNull" on B once it's no longer required by J2KT. +public final class ImmutableClassToInstanceMap + extends ForwardingMap, B> implements ClassToInstanceMap, Serializable { private static final ImmutableClassToInstanceMap EMPTY = diff --git a/android/guava/src/com/google/common/collect/MutableClassToInstanceMap.java b/android/guava/src/com/google/common/collect/MutableClassToInstanceMap.java index 00de9c4cbb91..0111ccade791 100644 --- a/android/guava/src/com/google/common/collect/MutableClassToInstanceMap.java +++ b/android/guava/src/com/google/common/collect/MutableClassToInstanceMap.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -41,9 +42,6 @@ * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#classtoinstancemap">{@code * ClassToInstanceMap}. * - *

This implementation does support null values, despite how it is annotated; see - * discussion at {@link ClassToInstanceMap}. - * * @author Kevin Bourrillion * @since 2.0 */ @@ -51,15 +49,16 @@ @GwtIncompatible @SuppressWarnings("serial") // using writeReplace instead of standard serialization @ElementTypesAreNonnullByDefault -public final class MutableClassToInstanceMap extends ForwardingMap, B> +public final class MutableClassToInstanceMap + extends ForwardingMap, B> implements ClassToInstanceMap, Serializable { /** * Returns a new {@code MutableClassToInstanceMap} instance backed by a {@link HashMap} using the * default initial capacity and load factor. */ - public static MutableClassToInstanceMap create() { - return new MutableClassToInstanceMap(new HashMap, B>()); + public static MutableClassToInstanceMap create() { + return new MutableClassToInstanceMap(new HashMap, B>()); } /** @@ -67,50 +66,58 @@ public static MutableClassToInstanceMap create() { * backingMap}. The caller surrenders control of the backing map, and thus should not allow any * direct references to it to remain accessible. */ - public static MutableClassToInstanceMap create(Map, B> backingMap) { + public static MutableClassToInstanceMap create( + Map, B> backingMap) { return new MutableClassToInstanceMap(backingMap); } - private final Map, B> delegate; + private final Map, B> delegate; - private MutableClassToInstanceMap(Map, B> delegate) { + private MutableClassToInstanceMap(Map, B> delegate) { this.delegate = checkNotNull(delegate); } @Override - protected Map, B> delegate() { + protected Map, B> delegate() { return delegate; } - static Entry, B> checkedEntry(final Entry, B> entry) { - return new ForwardingMapEntry, B>() { + /** + * Wraps the {@code setValue} implementation of an {@code Entry} to enforce the class constraint. + */ + private static Entry, B> checkedEntry( + final Entry, B> entry) { + return new ForwardingMapEntry, B>() { @Override - protected Entry, B> delegate() { + protected Entry, B> delegate() { return entry; } @Override - public B setValue(B value) { + @ParametricNullness + public B setValue(@ParametricNullness B value) { return super.setValue(cast(getKey(), value)); } }; } @Override - public Set, B>> entrySet() { - return new ForwardingSet, B>>() { + public Set, B>> entrySet() { + return new ForwardingSet, B>>() { @Override - protected Set, B>> delegate() { + protected Set, B>> delegate() { return MutableClassToInstanceMap.this.delegate().entrySet(); } @Override - public Iterator, B>> iterator() { - return new TransformedIterator, B>, Entry, B>>( + public Iterator, B>> iterator() { + return new TransformedIterator< + Entry, B>, Entry, B>>( delegate().iterator()) { @Override - Entry, B> transform(Entry, B> from) { + Entry, B> transform( + Entry, B> from) { return checkedEntry(from); } }; @@ -140,14 +147,14 @@ public Object[] toArray() { @Override @CanIgnoreReturnValue @CheckForNull - public B put(Class key, B value) { + public B put(Class key, @ParametricNullness B value) { return super.put(key, cast(key, value)); } @Override - public void putAll(Map, ? extends B> map) { - Map, B> copy = new LinkedHashMap<>(map); - for (Entry, B> entry : copy.entrySet()) { + public void putAll(Map, ? extends B> map) { + Map, B> copy = new LinkedHashMap<>(map); + for (Entry, B> entry : copy.entrySet()) { cast(entry.getKey(), entry.getValue()); } super.putAll(copy); @@ -156,19 +163,19 @@ public void putAll(Map, ? extends B> map) { @CanIgnoreReturnValue @Override @CheckForNull - public T putInstance(Class type, T value) { + public T putInstance(Class<@NonNull T> type, @ParametricNullness T value) { return cast(type, put(type, value)); } @Override @CheckForNull - public T getInstance(Class type) { + public T getInstance(Class type) { return cast(type, get(type)); } @CanIgnoreReturnValue @CheckForNull - private static T cast(Class type, @CheckForNull B value) { + private static T cast(Class<@NonNull T> type, @CheckForNull B value) { return Primitives.wrap(type).cast(value); } @@ -181,10 +188,10 @@ private void readObject(ObjectInputStream stream) throws InvalidObjectException } /** Serialized form of the map, to avoid serializing the constraint. */ - private static final class SerializedForm implements Serializable { - private final Map, B> backingMap; + private static final class SerializedForm implements Serializable { + private final Map, B> backingMap; - SerializedForm(Map, B> backingMap) { + SerializedForm(Map, B> backingMap) { this.backingMap = backingMap; } diff --git a/android/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java b/android/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java index 9542e0a7ed51..7690d2eef928 100644 --- a/android/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java +++ b/android/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java @@ -27,47 +27,45 @@ import java.util.Map; import java.util.Set; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** * A mutable type-to-instance map. See also {@link ImmutableTypeToInstanceMap}. * - *

This implementation does support null values, despite how it is annotated; see - * discussion at {@link TypeToInstanceMap}. - * * @author Ben Yu * @since 13.0 */ @ElementTypesAreNonnullByDefault -public final class MutableTypeToInstanceMap extends ForwardingMap, B> - implements TypeToInstanceMap { +public final class MutableTypeToInstanceMap + extends ForwardingMap, B> implements TypeToInstanceMap { - private final Map, B> backingMap = Maps.newHashMap(); + private final Map, B> backingMap = Maps.newHashMap(); @Override @CheckForNull - public T getInstance(Class type) { + public T getInstance(Class type) { return trustedGet(TypeToken.of(type)); } @Override @CheckForNull - public T getInstance(TypeToken type) { + public T getInstance(TypeToken type) { return trustedGet(type.rejectTypeVariables()); } @Override @CanIgnoreReturnValue @CheckForNull - public T putInstance(Class type, T value) { + public T putInstance(Class<@NonNull T> type, @ParametricNullness T value) { return trustedPut(TypeToken.of(type), value); } @Override @CanIgnoreReturnValue @CheckForNull - public T putInstance(TypeToken type, T value) { - return trustedPut(type.rejectTypeVariables(), value); + public T putInstance(TypeToken<@NonNull T> type, @ParametricNullness T value) { + return this.trustedPut(type.rejectTypeVariables(), value); } /** @@ -81,7 +79,7 @@ public T putInstance(TypeToken type, T value) { @Override @DoNotCall("Always throws UnsupportedOperationException") @CheckForNull - public B put(TypeToken key, B value) { + public B put(TypeToken key, @ParametricNullness B value) { throw new UnsupportedOperationException("Please use putInstance() instead."); } @@ -94,37 +92,39 @@ public B put(TypeToken key, B value) { @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") - public void putAll(Map, ? extends B> map) { + public void putAll(Map, ? extends B> map) { throw new UnsupportedOperationException("Please use putInstance() instead."); } @Override - public Set, B>> entrySet() { + public Set, B>> entrySet() { return UnmodifiableEntry.transformEntries(super.entrySet()); } @Override - protected Map, B> delegate() { + protected Map, B> delegate() { return backingMap; } @SuppressWarnings("unchecked") // value could not get in if not a T @CheckForNull - private T trustedPut(TypeToken type, T value) { + private T trustedPut(TypeToken<@NonNull T> type, @ParametricNullness T value) { return (T) backingMap.put(type, value); } @SuppressWarnings("unchecked") // value could not get in if not a T @CheckForNull - private T trustedGet(TypeToken type) { + private T trustedGet(TypeToken type) { return (T) backingMap.get(type); } - private static final class UnmodifiableEntry extends ForwardingMapEntry { + private static final class UnmodifiableEntry + extends ForwardingMapEntry { private final Entry delegate; - static Set> transformEntries(Set> entries) { + static Set> transformEntries( + Set> entries) { return new ForwardingSet>() { @Override protected Set> delegate() { @@ -157,7 +157,8 @@ public Object[] toArray() { }; } - private static Iterator> transformEntries(Iterator> entries) { + private static Iterator> transformEntries( + Iterator> entries) { return Iterators.transform(entries, UnmodifiableEntry::new); } @@ -171,7 +172,8 @@ protected Entry delegate() { } @Override - public V setValue(V value) { + @ParametricNullness + public V setValue(@ParametricNullness V value) { throw new UnsupportedOperationException(); } } diff --git a/android/guava/src/com/google/common/reflect/TypeToInstanceMap.java b/android/guava/src/com/google/common/reflect/TypeToInstanceMap.java index 0134dffcb036..fe61a2cc510b 100644 --- a/android/guava/src/com/google/common/reflect/TypeToInstanceMap.java +++ b/android/guava/src/com/google/common/reflect/TypeToInstanceMap.java @@ -18,6 +18,8 @@ import com.google.errorprone.annotations.DoNotMock; import java.util.Map; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A map, each entry of which maps a {@link TypeToken} to an instance of that type. In addition to @@ -34,17 +36,14 @@ *

Like any other {@code Map}, this map may contain entries for primitive types, * and a primitive type and its corresponding wrapper type may map to different values. * - *

This class's support for {@code null} requires some explanation. For details, see {@link - * com.google.common.collect.ClassToInstanceMap}. Its explanation applies equally well to {@code - * TypeToInstanceMap}. - * * @param the common supertype that all entries must share; often this is simply {@link Object} * @author Ben Yu * @since 13.0 */ @DoNotMock("Use ImmutableTypeToInstanceMap or MutableTypeToInstanceMap") @ElementTypesAreNonnullByDefault -public interface TypeToInstanceMap extends Map, B> { +public interface TypeToInstanceMap + extends Map, B> { /** * Returns the value the specified class is mapped to, or {@code null} if no entry for this class @@ -55,7 +54,7 @@ public interface TypeToInstanceMap extends Map, B> { * getInstance(TypeToken.of(Foo.class))}. */ @CheckForNull - T getInstance(Class type); + T getInstance(Class type); /** * Returns the value the specified type is mapped to, or {@code null} if no entry for this type is @@ -63,7 +62,7 @@ public interface TypeToInstanceMap extends Map, B> { * may have been bound to a subtype. */ @CheckForNull - T getInstance(TypeToken type); + T getInstance(TypeToken type); /** * Maps the specified class to the specified value. Does not associate this value with any @@ -77,7 +76,7 @@ public interface TypeToInstanceMap extends Map, B> { */ @CanIgnoreReturnValue @CheckForNull - T putInstance(Class type, T value); + T putInstance(Class<@NonNull T> type, @ParametricNullness T value); /** * Maps the specified type to the specified value. Does not associate this value with any @@ -88,5 +87,5 @@ public interface TypeToInstanceMap extends Map, B> { */ @CanIgnoreReturnValue @CheckForNull - T putInstance(TypeToken type, T value); + T putInstance(TypeToken<@NonNull T> type, @ParametricNullness T value); } diff --git a/guava-gwt/src/com/google/common/collect/Collect.gwt.xml b/guava-gwt/src/com/google/common/collect/Collect.gwt.xml index 91756f9e8b52..dd3c5e8fc6ea 100644 --- a/guava-gwt/src/com/google/common/collect/Collect.gwt.xml +++ b/guava-gwt/src/com/google/common/collect/Collect.gwt.xml @@ -28,6 +28,7 @@ --> + diff --git a/guava/src/com/google/common/collect/ClassToInstanceMap.java b/guava/src/com/google/common/collect/ClassToInstanceMap.java index 8fbdfd9ebfc7..a34c6ad5f0c4 100644 --- a/guava/src/com/google/common/collect/ClassToInstanceMap.java +++ b/guava/src/com/google/common/collect/ClassToInstanceMap.java @@ -21,6 +21,8 @@ import com.google.errorprone.annotations.DoNotMock; import java.util.Map; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A map, each entry of which maps a Java raw type to an @@ -30,17 +32,6 @@ *

Like any other {@code Map}, this map may contain entries for primitive types, * and a primitive type and its corresponding wrapper type may map to different values. * - *

This class's support for {@code null} requires some explanation: From release 31.0 onward, - * Guava specifies the nullness of its types through annotations. In the case of {@code - * ClassToInstanceMap}, it specifies that both the key and value types are restricted to - * non-nullable types. This specification is reasonable for keys, which must be non-null - * classes. This is in contrast to the specification for values: Null values are - * supported by the implementation {@link MutableClassToInstanceMap}, even though that - * implementation and this interface specify otherwise. Thus, if you use a nullness checker, you can - * safely suppress any warnings it produces when you write null values into a {@code - * MutableClassToInstanceMap}. Just be sure to be prepared for null values when reading from it, - * since nullness checkers will assume that values are non-null then, too. - * *

See the Guava User Guide article on {@code * ClassToInstanceMap}. @@ -48,25 +39,22 @@ *

To map a generic type to an instance of that type, use {@link * com.google.common.reflect.TypeToInstanceMap} instead. * - * @param the common supertype that all entries must share; often this is simply {@link Object} - * @author Kevin Bourrillion + * @param the common supertype that all values will share. When in doubt, just use {@link + * Object}, or use {@code @Nullable Object} to allow null values. * @since 2.0 */ @DoNotMock("Use ImmutableClassToInstanceMap or MutableClassToInstanceMap") @GwtCompatible @ElementTypesAreNonnullByDefault -// If we ever support non-null projections (https://github.com/jspecify/jspecify/issues/86), -// we might annotate this as... -// ClassToInstanceMap extends Map, B> -// ...and change its methods similarly ( or Class<@Nonnull T>). -public interface ClassToInstanceMap extends Map, B> { +public interface ClassToInstanceMap + extends Map, B> { /** * Returns the value the specified class is mapped to, or {@code null} if no entry for this class * is present. This will only return a value that was bound to this specific class, not a value * that may have been bound to a subtype. */ @CheckForNull - T getInstance(Class type); + T getInstance(Class type); /** * Maps the specified class to the specified value. Does not associate this value with any @@ -77,5 +65,5 @@ public interface ClassToInstanceMap extends Map, B> { */ @CanIgnoreReturnValue @CheckForNull - T putInstance(Class type, T value); + T putInstance(Class<@NonNull T> type, @ParametricNullness T value); } diff --git a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java index dfa331c46c6d..5c907f7cd468 100644 --- a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java +++ b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java @@ -26,6 +26,7 @@ import java.io.Serializable; import java.util.Map; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A {@link ClassToInstanceMap} whose contents will never change, with many other important @@ -37,7 +38,9 @@ @Immutable(containerOf = "B") @GwtIncompatible @ElementTypesAreNonnullByDefault -public final class ImmutableClassToInstanceMap extends ForwardingMap, B> +// TODO(b/278589132): Remove the redundant "@NonNull" on B once it's no longer required by J2KT. +public final class ImmutableClassToInstanceMap + extends ForwardingMap, B> implements ClassToInstanceMap, Serializable { private static final ImmutableClassToInstanceMap EMPTY = diff --git a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java index e8dd42509304..740d66715bcc 100644 --- a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java +++ b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java @@ -32,6 +32,7 @@ import java.util.Set; import java.util.Spliterator; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -42,9 +43,6 @@ * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#classtoinstancemap">{@code * ClassToInstanceMap}. * - *

This implementation does support null values, despite how it is annotated; see - * discussion at {@link ClassToInstanceMap}. - * * @author Kevin Bourrillion * @since 2.0 */ @@ -52,15 +50,16 @@ @GwtIncompatible @SuppressWarnings("serial") // using writeReplace instead of standard serialization @ElementTypesAreNonnullByDefault -public final class MutableClassToInstanceMap extends ForwardingMap, B> +public final class MutableClassToInstanceMap + extends ForwardingMap, B> implements ClassToInstanceMap, Serializable { /** * Returns a new {@code MutableClassToInstanceMap} instance backed by a {@link HashMap} using the * default initial capacity and load factor. */ - public static MutableClassToInstanceMap create() { - return new MutableClassToInstanceMap(new HashMap, B>()); + public static MutableClassToInstanceMap create() { + return new MutableClassToInstanceMap(new HashMap, B>()); } /** @@ -68,60 +67,64 @@ public static MutableClassToInstanceMap create() { * backingMap}. The caller surrenders control of the backing map, and thus should not allow any * direct references to it to remain accessible. */ - public static MutableClassToInstanceMap create(Map, B> backingMap) { + public static MutableClassToInstanceMap create( + Map, B> backingMap) { return new MutableClassToInstanceMap(backingMap); } - private final Map, B> delegate; + private final Map, B> delegate; - private MutableClassToInstanceMap(Map, B> delegate) { + private MutableClassToInstanceMap(Map, B> delegate) { this.delegate = checkNotNull(delegate); } @Override - protected Map, B> delegate() { + protected Map, B> delegate() { return delegate; } /** * Wraps the {@code setValue} implementation of an {@code Entry} to enforce the class constraint. */ - private static Entry, B> checkedEntry( - final Entry, B> entry) { - return new ForwardingMapEntry, B>() { + private static Entry, B> checkedEntry( + final Entry, B> entry) { + return new ForwardingMapEntry, B>() { @Override - protected Entry, B> delegate() { + protected Entry, B> delegate() { return entry; } @Override - public B setValue(B value) { + @ParametricNullness + public B setValue(@ParametricNullness B value) { return super.setValue(cast(getKey(), value)); } }; } @Override - public Set, B>> entrySet() { - return new ForwardingSet, B>>() { + public Set, B>> entrySet() { + return new ForwardingSet, B>>() { @Override - protected Set, B>> delegate() { + protected Set, B>> delegate() { return MutableClassToInstanceMap.this.delegate().entrySet(); } @Override - public Spliterator, B>> spliterator() { + public Spliterator, B>> spliterator() { return CollectSpliterators.map( delegate().spliterator(), MutableClassToInstanceMap::checkedEntry); } @Override - public Iterator, B>> iterator() { - return new TransformedIterator, B>, Entry, B>>( + public Iterator, B>> iterator() { + return new TransformedIterator< + Entry, B>, Entry, B>>( delegate().iterator()) { @Override - Entry, B> transform(Entry, B> from) { + Entry, B> transform( + Entry, B> from) { return checkedEntry(from); } }; @@ -151,14 +154,14 @@ public Object[] toArray() { @Override @CanIgnoreReturnValue @CheckForNull - public B put(Class key, B value) { + public B put(Class key, @ParametricNullness B value) { return super.put(key, cast(key, value)); } @Override - public void putAll(Map, ? extends B> map) { - Map, B> copy = new LinkedHashMap<>(map); - for (Entry, B> entry : copy.entrySet()) { + public void putAll(Map, ? extends B> map) { + Map, B> copy = new LinkedHashMap<>(map); + for (Entry, B> entry : copy.entrySet()) { cast(entry.getKey(), entry.getValue()); } super.putAll(copy); @@ -167,19 +170,19 @@ public void putAll(Map, ? extends B> map) { @CanIgnoreReturnValue @Override @CheckForNull - public T putInstance(Class type, T value) { + public T putInstance(Class<@NonNull T> type, @ParametricNullness T value) { return cast(type, put(type, value)); } @Override @CheckForNull - public T getInstance(Class type) { + public T getInstance(Class type) { return cast(type, get(type)); } @CanIgnoreReturnValue @CheckForNull - private static T cast(Class type, @CheckForNull B value) { + private static T cast(Class<@NonNull T> type, @CheckForNull B value) { return Primitives.wrap(type).cast(value); } @@ -192,10 +195,10 @@ private void readObject(ObjectInputStream stream) throws InvalidObjectException } /** Serialized form of the map, to avoid serializing the constraint. */ - private static final class SerializedForm implements Serializable { - private final Map, B> backingMap; + private static final class SerializedForm implements Serializable { + private final Map, B> backingMap; - SerializedForm(Map, B> backingMap) { + SerializedForm(Map, B> backingMap) { this.backingMap = backingMap; } diff --git a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java index 9542e0a7ed51..7690d2eef928 100644 --- a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java +++ b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java @@ -27,47 +27,45 @@ import java.util.Map; import java.util.Set; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** * A mutable type-to-instance map. See also {@link ImmutableTypeToInstanceMap}. * - *

This implementation does support null values, despite how it is annotated; see - * discussion at {@link TypeToInstanceMap}. - * * @author Ben Yu * @since 13.0 */ @ElementTypesAreNonnullByDefault -public final class MutableTypeToInstanceMap extends ForwardingMap, B> - implements TypeToInstanceMap { +public final class MutableTypeToInstanceMap + extends ForwardingMap, B> implements TypeToInstanceMap { - private final Map, B> backingMap = Maps.newHashMap(); + private final Map, B> backingMap = Maps.newHashMap(); @Override @CheckForNull - public T getInstance(Class type) { + public T getInstance(Class type) { return trustedGet(TypeToken.of(type)); } @Override @CheckForNull - public T getInstance(TypeToken type) { + public T getInstance(TypeToken type) { return trustedGet(type.rejectTypeVariables()); } @Override @CanIgnoreReturnValue @CheckForNull - public T putInstance(Class type, T value) { + public T putInstance(Class<@NonNull T> type, @ParametricNullness T value) { return trustedPut(TypeToken.of(type), value); } @Override @CanIgnoreReturnValue @CheckForNull - public T putInstance(TypeToken type, T value) { - return trustedPut(type.rejectTypeVariables(), value); + public T putInstance(TypeToken<@NonNull T> type, @ParametricNullness T value) { + return this.trustedPut(type.rejectTypeVariables(), value); } /** @@ -81,7 +79,7 @@ public T putInstance(TypeToken type, T value) { @Override @DoNotCall("Always throws UnsupportedOperationException") @CheckForNull - public B put(TypeToken key, B value) { + public B put(TypeToken key, @ParametricNullness B value) { throw new UnsupportedOperationException("Please use putInstance() instead."); } @@ -94,37 +92,39 @@ public B put(TypeToken key, B value) { @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") - public void putAll(Map, ? extends B> map) { + public void putAll(Map, ? extends B> map) { throw new UnsupportedOperationException("Please use putInstance() instead."); } @Override - public Set, B>> entrySet() { + public Set, B>> entrySet() { return UnmodifiableEntry.transformEntries(super.entrySet()); } @Override - protected Map, B> delegate() { + protected Map, B> delegate() { return backingMap; } @SuppressWarnings("unchecked") // value could not get in if not a T @CheckForNull - private T trustedPut(TypeToken type, T value) { + private T trustedPut(TypeToken<@NonNull T> type, @ParametricNullness T value) { return (T) backingMap.put(type, value); } @SuppressWarnings("unchecked") // value could not get in if not a T @CheckForNull - private T trustedGet(TypeToken type) { + private T trustedGet(TypeToken type) { return (T) backingMap.get(type); } - private static final class UnmodifiableEntry extends ForwardingMapEntry { + private static final class UnmodifiableEntry + extends ForwardingMapEntry { private final Entry delegate; - static Set> transformEntries(Set> entries) { + static Set> transformEntries( + Set> entries) { return new ForwardingSet>() { @Override protected Set> delegate() { @@ -157,7 +157,8 @@ public Object[] toArray() { }; } - private static Iterator> transformEntries(Iterator> entries) { + private static Iterator> transformEntries( + Iterator> entries) { return Iterators.transform(entries, UnmodifiableEntry::new); } @@ -171,7 +172,8 @@ protected Entry delegate() { } @Override - public V setValue(V value) { + @ParametricNullness + public V setValue(@ParametricNullness V value) { throw new UnsupportedOperationException(); } } diff --git a/guava/src/com/google/common/reflect/TypeToInstanceMap.java b/guava/src/com/google/common/reflect/TypeToInstanceMap.java index 0134dffcb036..fe61a2cc510b 100644 --- a/guava/src/com/google/common/reflect/TypeToInstanceMap.java +++ b/guava/src/com/google/common/reflect/TypeToInstanceMap.java @@ -18,6 +18,8 @@ import com.google.errorprone.annotations.DoNotMock; import java.util.Map; import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A map, each entry of which maps a {@link TypeToken} to an instance of that type. In addition to @@ -34,17 +36,14 @@ *

Like any other {@code Map}, this map may contain entries for primitive types, * and a primitive type and its corresponding wrapper type may map to different values. * - *

This class's support for {@code null} requires some explanation. For details, see {@link - * com.google.common.collect.ClassToInstanceMap}. Its explanation applies equally well to {@code - * TypeToInstanceMap}. - * * @param the common supertype that all entries must share; often this is simply {@link Object} * @author Ben Yu * @since 13.0 */ @DoNotMock("Use ImmutableTypeToInstanceMap or MutableTypeToInstanceMap") @ElementTypesAreNonnullByDefault -public interface TypeToInstanceMap extends Map, B> { +public interface TypeToInstanceMap + extends Map, B> { /** * Returns the value the specified class is mapped to, or {@code null} if no entry for this class @@ -55,7 +54,7 @@ public interface TypeToInstanceMap extends Map, B> { * getInstance(TypeToken.of(Foo.class))}. */ @CheckForNull - T getInstance(Class type); + T getInstance(Class type); /** * Returns the value the specified type is mapped to, or {@code null} if no entry for this type is @@ -63,7 +62,7 @@ public interface TypeToInstanceMap extends Map, B> { * may have been bound to a subtype. */ @CheckForNull - T getInstance(TypeToken type); + T getInstance(TypeToken type); /** * Maps the specified class to the specified value. Does not associate this value with any @@ -77,7 +76,7 @@ public interface TypeToInstanceMap extends Map, B> { */ @CanIgnoreReturnValue @CheckForNull - T putInstance(Class type, T value); + T putInstance(Class<@NonNull T> type, @ParametricNullness T value); /** * Maps the specified type to the specified value. Does not associate this value with any @@ -88,5 +87,5 @@ public interface TypeToInstanceMap extends Map, B> { */ @CanIgnoreReturnValue @CheckForNull - T putInstance(TypeToken type, T value); + T putInstance(TypeToken<@NonNull T> type, @ParametricNullness T value); }