Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.jspecify.annotations.Nullable;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
Expand Down Expand Up @@ -151,7 +153,7 @@ static class Factory implements TypeAdapterFactory, InstanceCreator<Object> {
}

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
public @Nullable <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!instanceCreators.containsKey(type.getType())) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import org.jspecify.annotations.Nullable;

import java.io.IOException;

/** A type adapter factory that implements {@code @Intercept}. */
public final class InterceptorFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
public @Nullable <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Intercept intercept = type.getRawType().getAnnotation(Intercept.class);
if (intercept == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import org.jspecify.annotations.Nullable;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand All @@ -30,7 +32,7 @@
public class PostConstructAdapterFactory implements TypeAdapterFactory {
// copied from https://gist.github.com/swankjesse/20df26adaf639ed7fd160f145a0b661a
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
public @Nullable <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
for (Class<?> t = type.getRawType();
(t != Object.class) && (t.getSuperclass() != null);
t = t.getSuperclass()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import org.jspecify.annotations.Nullable;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
Expand Down Expand Up @@ -241,7 +243,7 @@ public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {
}

@Override
public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
public @Nullable <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
if (type == null) {
return null;
}
Expand Down
5 changes: 5 additions & 0 deletions gson/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<artifactId>error_prone_annotations</artifactId>
<version>2.43.0</version>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
Expand Down
15 changes: 8 additions & 7 deletions gson/src/main/java/com/google/gson/TypeAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import org.jspecify.annotations.Nullable;

/**
* Converts Java objects to and from JSON.
Expand Down Expand Up @@ -127,7 +128,7 @@ public TypeAdapter() {}
*
* @param value the Java object to write. May be null.
*/
public abstract void write(JsonWriter out, T value) throws IOException;
public abstract void write(JsonWriter out, @Nullable T value) throws IOException;

/**
* Converts {@code value} to a JSON document and writes it to {@code out}.
Expand Down Expand Up @@ -191,7 +192,7 @@ public final JsonElement toJsonTree(T value) {
*
* @return the converted Java object. May be {@code null}.
*/
public abstract T read(JsonReader in) throws IOException;
public abstract @Nullable T read(JsonReader in) throws IOException;

/**
* Converts the JSON document in {@code in} to a Java object.
Expand All @@ -207,7 +208,7 @@ public final JsonElement toJsonTree(T value) {
* @return the converted Java object. May be {@code null}.
* @since 2.2
*/
public final T fromJson(Reader in) throws IOException {
public final @Nullable T fromJson(Reader in) throws IOException {
JsonReader reader = new JsonReader(in);
return read(reader);
}
Expand All @@ -226,7 +227,7 @@ public final T fromJson(Reader in) throws IOException {
* @return the converted Java object. May be {@code null}.
* @since 2.2
*/
public final T fromJson(String json) throws IOException {
public final @Nullable T fromJson(String json) throws IOException {
return fromJson(new StringReader(json));
}

Expand All @@ -238,7 +239,7 @@ public final T fromJson(String json) throws IOException {
* @throws JsonIOException wrapping {@code IOException}s thrown by {@link #read(JsonReader)}
* @since 2.2
*/
public final T fromJsonTree(JsonElement jsonTree) {
public final @Nullable T fromJsonTree(JsonElement jsonTree) {
try {
JsonReader jsonReader = new JsonTreeReader(jsonTree);
return read(jsonReader);
Expand Down Expand Up @@ -297,7 +298,7 @@ public final TypeAdapter<T> nullSafe() {

private final class NullSafeTypeAdapter extends TypeAdapter<T> {
@Override
public void write(JsonWriter out, T value) throws IOException {
public void write(JsonWriter out, @Nullable T value) throws IOException {
if (value == null) {
out.nullValue();
} else {
Expand All @@ -306,7 +307,7 @@ public void write(JsonWriter out, T value) throws IOException {
}

@Override
public T read(JsonReader reader) throws IOException {
public @Nullable T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
Expand Down
3 changes: 2 additions & 1 deletion gson/src/main/java/com/google/gson/TypeAdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.gson;

import com.google.gson.reflect.TypeToken;
import org.jspecify.annotations.Nullable;

/**
* Creates type adapters for set of related types. Type adapter factories are most useful when
Expand Down Expand Up @@ -166,5 +167,5 @@ public interface TypeAdapterFactory {
/**
* Returns a type adapter for {@code type}, or null if this factory doesn't support {@code type}.
*/
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
<T> @Nullable TypeAdapter<T> create(Gson gson, TypeToken<T> type);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@
* @author Inderjeet Singh, Joel Leitch
*/
@com.google.errorprone.annotations.CheckReturnValue
@org.jspecify.annotations.NullMarked
package com.google.gson.annotations;
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import org.jspecify.annotations.Nullable;

/** Returns a function that can construct an instance of a requested type. */
public final class ConstructorConstructor {
Expand All @@ -63,7 +64,7 @@ public ConstructorConstructor(
* @param c instance of the class to be checked
* @return if instantiable {@code null}, else a non-{@code null} exception message
*/
static String checkInstantiable(Class<?> c) {
static @Nullable String checkInstantiable(Class<?> c) {
int modifiers = c.getModifiers();
if (Modifier.isInterface(modifiers)) {
return "Interfaces can't be instantiated! Register an InstanceCreator"
Expand Down Expand Up @@ -174,7 +175,7 @@ public <T> ObjectConstructor<T> get(TypeToken<T> typeToken, boolean allowUnsafe)
* Creates constructors for special JDK collection types which do not have a public no-args
* constructor.
*/
private static <T> ObjectConstructor<T> newSpecialCollectionConstructor(
private static <T> @Nullable ObjectConstructor<T> newSpecialCollectionConstructor(
Type type, Class<? super T> rawType) {
if (EnumSet.class.isAssignableFrom(rawType)) {
return () -> {
Expand Down Expand Up @@ -214,7 +215,7 @@ else if (rawType == EnumMap.class) {
return null;
}

private static <T> ObjectConstructor<T> newDefaultConstructor(
private static <T> @Nullable ObjectConstructor<T> newDefaultConstructor(
Class<? super T> rawType, FilterResult filterResult) {
// Cannot invoke constructor of abstract class
if (Modifier.isAbstract(rawType.getModifiers())) {
Expand Down Expand Up @@ -285,7 +286,7 @@ private static <T> ObjectConstructor<T> newDefaultConstructor(
}

/** Constructors for common interface types like Map and List and their subtypes. */
private static <T> ObjectConstructor<T> newDefaultImplementationConstructor(
private static <T> @Nullable ObjectConstructor<T> newDefaultImplementationConstructor(
Type type, Class<? super T> rawType) {

/*
Expand Down Expand Up @@ -349,7 +350,7 @@ private static boolean hasStringKeyType(Type mapType) {
return GsonTypes.getRawType(typeArguments[0]) == String.class;
}

private static ObjectConstructor<? extends Map<?, Object>> newMapConstructor(
private static @Nullable ObjectConstructor<? extends Map<?, Object>> newMapConstructor(
Type type, Class<?> rawType) {
// First try Map implementation
/*
Expand Down
3 changes: 2 additions & 1 deletion gson/src/main/java/com/google/gson/internal/Excluder.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jspecify.annotations.Nullable;

/**
* This class selects which fields and types to omit. It is configurable, supporting version
Expand Down Expand Up @@ -108,7 +109,7 @@ public Excluder withExclusionStrategy(
}

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
public @Nullable <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<?> rawType = type.getRawType();

boolean skipSerialize = excludeClass(rawType, true);
Expand Down
15 changes: 8 additions & 7 deletions gson/src/main/java/com/google/gson/internal/GsonTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Properties;
import org.jspecify.annotations.Nullable;

/**
* Static methods for working with types.
Expand All @@ -55,7 +56,7 @@ private GsonTypes() {
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
public static ParameterizedType newParameterizedTypeWithOwner(
Type ownerType, Class<?> rawType, Type... typeArguments) {
@Nullable Type ownerType, Class<?> rawType, Type... typeArguments) {
return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
}

Expand Down Expand Up @@ -512,15 +513,15 @@ public static boolean requiresOwnerType(Type rawType) {
// the nested Type implementations here (which are also serializable).
private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable {
@SuppressWarnings("serial")
private final Type ownerType;
private final @Nullable Type ownerType;

@SuppressWarnings("serial")
private final Type rawType;

@SuppressWarnings("serial")
private final Type[] typeArguments;

ParameterizedTypeImpl(Type ownerType, Class<?> rawType, Type... typeArguments) {
ParameterizedTypeImpl(@Nullable Type ownerType, Class<?> rawType, Type... typeArguments) {
requireNonNull(rawType);

if (ownerType == null && requiresOwnerType(rawType)) {
Expand Down Expand Up @@ -548,17 +549,17 @@ public Type getRawType() {
}

@Override
public Type getOwnerType() {
public @Nullable Type getOwnerType() {
return ownerType;
}

@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
return other instanceof ParameterizedType
&& GsonTypes.equals(this, (ParameterizedType) other);
}

private static int hashCodeOrZero(Object o) {
private static int hashCodeOrZero(@Nullable Object o) {
return o != null ? o.hashCode() : 0;
}

Expand Down Expand Up @@ -631,7 +632,7 @@ private static final class WildcardTypeImpl implements WildcardType, Serializabl
private final Type upperBound;

@SuppressWarnings("serial")
private final Type lowerBound;
private final @Nullable Type lowerBound;

WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
if (lowerBounds.length > 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.List;
import org.jspecify.annotations.Nullable;

/** Internal helper class for {@link ReflectionAccessFilter}. */
public class ReflectionAccessFilterHelper {
Expand Down Expand Up @@ -73,7 +74,7 @@ public static FilterResult getFilterResult(
}

/** See {@link AccessibleObject#canAccess(Object)} (Java >= 9) */
public static boolean canAccess(AccessibleObject accessibleObject, Object object) {
public static boolean canAccess(AccessibleObject accessibleObject, @Nullable Object object) {
return AccessChecker.INSTANCE.canAccess(accessibleObject, object);
}

Expand All @@ -90,7 +91,8 @@ private abstract static class AccessChecker {
accessChecker =
new AccessChecker() {
@Override
public boolean canAccess(AccessibleObject accessibleObject, Object object) {
public boolean canAccess(
AccessibleObject accessibleObject, @Nullable Object object) {
try {
return (Boolean) canAccessMethod.invoke(accessibleObject, object);
} catch (Exception e) {
Expand All @@ -107,7 +109,7 @@ public boolean canAccess(AccessibleObject accessibleObject, Object object) {
accessChecker =
new AccessChecker() {
@Override
public boolean canAccess(AccessibleObject accessibleObject, Object object) {
public boolean canAccess(AccessibleObject accessibleObject, @Nullable Object object) {
// Cannot determine whether object can be accessed, so assume it can be accessed
return true;
}
Expand All @@ -116,6 +118,6 @@ public boolean canAccess(AccessibleObject accessibleObject, Object object) {
INSTANCE = accessChecker;
}

abstract boolean canAccess(AccessibleObject accessibleObject, Object object);
abstract boolean canAccess(AccessibleObject accessibleObject, @Nullable Object object);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import org.jspecify.annotations.Nullable;

/** Adapter for arrays. */
public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
public static final TypeAdapterFactory FACTORY =
new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
public @Nullable <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
if (!(type instanceof GenericArrayType
|| (type instanceof Class && ((Class<?>) type).isArray()))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import org.jspecify.annotations.Nullable;

/** Adapt a homogeneous collection of objects. */
public final class CollectionTypeAdapterFactory implements TypeAdapterFactory {
Expand All @@ -39,7 +40,7 @@ public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructo
}

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
public @Nullable <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();

Class<? super T> rawType = typeToken.getRawType();
Expand Down
Loading
Loading