Enable additional Error Prone checks & fix violations (#2561)

* Enable additional Error Prone checks & fix violations

Some of them also enforce additional Google Java Format requirements which
are not handled by google-java-format, such as disallowing wildcard imports.

Not all experimental checks have been listed because some are not applicable,
such as Dependency Injection framework checks, or checks related to Guava's
immutable collections (since Gson's main code does not have a dependency on
Guava).

Other checks have been omitted because they are probably not relevant
(this was a subjective choice), or would require larger refactoring or
would flag issues with the public API, which cannot be changed easily.

* Address review feedback

---------

Co-authored-by: Éamonn McManus <emcmanus@google.com>
This commit is contained in:
Marcono1234 2024-01-09 19:19:09 +01:00 committed by GitHub
parent 2bcaaed875
commit 5187808233
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 584 additions and 437 deletions

View File

@ -21,6 +21,7 @@ import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.Collection;
@SuppressWarnings({"PrivateConstructorForUtilityClass", "SystemOut"})
public class RawCollectionsExample {
static class Event {
private String name;

View File

@ -61,9 +61,11 @@ public class PostConstructAdapterFactory implements TypeAdapterFactory {
try {
method.invoke(result);
} catch (IllegalAccessException e) {
throw new AssertionError();
throw new AssertionError(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RuntimeException) throw (RuntimeException) e.getCause();
if (e.getCause() instanceof RuntimeException) {
throw (RuntimeException) e.getCause();
}
throw new RuntimeException(e.getCause());
}
}

View File

@ -30,7 +30,7 @@ import java.util.Locale;
import java.util.TimeZone;
public final class UtcDateTypeAdapter extends TypeAdapter<Date> {
private final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
@Override
public void write(JsonWriter out, Date date) throws IOException {

View File

@ -171,7 +171,9 @@ public final class InterceptorTest {
if (user.name == null || user.password == null) {
throw new JsonSyntaxException("name and password are required fields.");
}
if (user.email == null) user.email = User.DEFAULT_EMAIL;
if (user.email == null) {
user.email = User.DEFAULT_EMAIL;
}
}
}
@ -192,7 +194,9 @@ public final class InterceptorTest {
if (address.city == null || address.state == null || address.zip == null) {
throw new JsonSyntaxException("Address city, state and zip are required fields.");
}
if (address.firstLine == null) address.firstLine = Address.DEFAULT_FIRST_LINE;
if (address.firstLine == null) {
address.firstLine = Address.DEFAULT_FIRST_LINE;
}
}
}
}

View File

@ -656,6 +656,16 @@ public final class Gson {
return candidate;
}
/**
* Returns the type adapter for {@code type}.
*
* @throws IllegalArgumentException if this Gson instance cannot serialize and deserialize {@code
* type}.
*/
public <T> TypeAdapter<T> getAdapter(Class<T> type) {
return getAdapter(TypeToken.get(type));
}
/**
* This method is used to get an alternate type adapter for the specified type. This is used to
* access a type adapter that is overridden by a {@link TypeAdapterFactory} that you may have
@ -748,16 +758,6 @@ public final class Gson {
}
}
/**
* Returns the type adapter for {@code type}.
*
* @throws IllegalArgumentException if this Gson instance cannot serialize and deserialize {@code
* type}.
*/
public <T> TypeAdapter<T> getAdapter(Class<T> type) {
return getAdapter(TypeToken.get(type));
}
/**
* This method serializes the specified object into its equivalent representation as a tree of
* {@link JsonElement}s. This method should be used when the specified object is not a generic
@ -983,53 +983,6 @@ public final class Gson {
}
}
/**
* Returns a new JSON writer configured for the settings on this Gson instance.
*
* <p>The following settings are considered:
*
* <ul>
* <li>{@link GsonBuilder#disableHtmlEscaping()}
* <li>{@link GsonBuilder#generateNonExecutableJson()}
* <li>{@link GsonBuilder#serializeNulls()}
* <li>{@link GsonBuilder#setStrictness(Strictness)}. If no {@linkplain
* GsonBuilder#setStrictness(Strictness) explicit strictness has been set} the created
* writer will have a strictness of {@link Strictness#LEGACY_STRICT}. Otherwise, the
* strictness of the {@code Gson} instance will be used for the created writer.
* <li>{@link GsonBuilder#setPrettyPrinting()}
* <li>{@link GsonBuilder#setFormattingStyle(FormattingStyle)}
* </ul>
*/
public JsonWriter newJsonWriter(Writer writer) throws IOException {
if (generateNonExecutableJson) {
writer.write(JSON_NON_EXECUTABLE_PREFIX);
}
JsonWriter jsonWriter = new JsonWriter(writer);
jsonWriter.setFormattingStyle(formattingStyle);
jsonWriter.setHtmlSafe(htmlSafe);
jsonWriter.setStrictness(strictness == null ? Strictness.LEGACY_STRICT : strictness);
jsonWriter.setSerializeNulls(serializeNulls);
return jsonWriter;
}
/**
* Returns a new JSON reader configured for the settings on this Gson instance.
*
* <p>The following settings are considered:
*
* <ul>
* <li>{@link GsonBuilder#setStrictness(Strictness)}. If no {@linkplain
* GsonBuilder#setStrictness(Strictness) explicit strictness has been set} the created
* reader will have a strictness of {@link Strictness#LEGACY_STRICT}. Otherwise, the
* strictness of the {@code Gson} instance will be used for the created reader.
* </ul>
*/
public JsonReader newJsonReader(Reader reader) {
JsonReader jsonReader = new JsonReader(reader);
jsonReader.setStrictness(strictness == null ? Strictness.LEGACY_STRICT : strictness);
return jsonReader;
}
/**
* Writes the JSON for {@code jsonElement} to {@code writer}.
*
@ -1078,6 +1031,53 @@ public final class Gson {
}
}
/**
* Returns a new JSON writer configured for the settings on this Gson instance.
*
* <p>The following settings are considered:
*
* <ul>
* <li>{@link GsonBuilder#disableHtmlEscaping()}
* <li>{@link GsonBuilder#generateNonExecutableJson()}
* <li>{@link GsonBuilder#serializeNulls()}
* <li>{@link GsonBuilder#setStrictness(Strictness)}. If no {@linkplain
* GsonBuilder#setStrictness(Strictness) explicit strictness has been set} the created
* writer will have a strictness of {@link Strictness#LEGACY_STRICT}. Otherwise, the
* strictness of the {@code Gson} instance will be used for the created writer.
* <li>{@link GsonBuilder#setPrettyPrinting()}
* <li>{@link GsonBuilder#setFormattingStyle(FormattingStyle)}
* </ul>
*/
public JsonWriter newJsonWriter(Writer writer) throws IOException {
if (generateNonExecutableJson) {
writer.write(JSON_NON_EXECUTABLE_PREFIX);
}
JsonWriter jsonWriter = new JsonWriter(writer);
jsonWriter.setFormattingStyle(formattingStyle);
jsonWriter.setHtmlSafe(htmlSafe);
jsonWriter.setStrictness(strictness == null ? Strictness.LEGACY_STRICT : strictness);
jsonWriter.setSerializeNulls(serializeNulls);
return jsonWriter;
}
/**
* Returns a new JSON reader configured for the settings on this Gson instance.
*
* <p>The following settings are considered:
*
* <ul>
* <li>{@link GsonBuilder#setStrictness(Strictness)}. If no {@linkplain
* GsonBuilder#setStrictness(Strictness) explicit strictness has been set} the created
* reader will have a strictness of {@link Strictness#LEGACY_STRICT}. Otherwise, the
* strictness of the {@code Gson} instance will be used for the created reader.
* </ul>
*/
public JsonReader newJsonReader(Reader reader) {
JsonReader jsonReader = new JsonReader(reader);
jsonReader.setStrictness(strictness == null ? Strictness.LEGACY_STRICT : strictness);
return jsonReader;
}
/**
* This method deserializes the specified JSON into an object of the specified class. It is not
* suitable to use if the specified class is a generic type since it will not have the generic
@ -1262,18 +1262,6 @@ public final class Gson {
return object;
}
private static void assertFullConsumption(Object obj, JsonReader reader) {
try {
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonSyntaxException("JSON document was not fully consumed.");
}
} catch (MalformedJsonException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
// fromJson(JsonReader, Class) is unfortunately missing and cannot be added now without breaking
// source compatibility in certain cases, see
// https://github.com/google/gson/pull/1700#discussion_r973764414
@ -1472,6 +1460,18 @@ public final class Gson {
return fromJson(new JsonTreeReader(json), typeOfT);
}
private static void assertFullConsumption(Object obj, JsonReader reader) {
try {
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonSyntaxException("JSON document was not fully consumed.");
}
} catch (MalformedJsonException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
/**
* Proxy type adapter for cyclic type graphs.
*

View File

@ -614,14 +614,6 @@ public final class GsonBuilder {
return this;
}
private static int checkDateFormatStyle(int style) {
// Valid DateFormat styles are: 0, 1, 2, 3 (FULL, LONG, MEDIUM, SHORT)
if (style < 0 || style > 3) {
throw new IllegalArgumentException("Invalid style: " + style);
}
return style;
}
/**
* Configures Gson to serialize {@code Date} objects according to the date style value provided.
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
@ -669,6 +661,14 @@ public final class GsonBuilder {
return this;
}
private static int checkDateFormatStyle(int style) {
// Valid DateFormat styles are: 0, 1, 2, 3 (FULL, LONG, MEDIUM, SHORT)
if (style < 0 || style > 3) {
throw new IllegalArgumentException("Invalid style: " + style);
}
return style;
}
/**
* Configures Gson for custom serialization or deserialization. This method combines the
* registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a
@ -722,7 +722,7 @@ public final class GsonBuilder {
return this;
}
private boolean isTypeObjectOrJsonElement(Type type) {
private static boolean isTypeObjectOrJsonElement(Type type) {
return type instanceof Class
&& (type == Object.class || JsonElement.class.isAssignableFrom((Class<?>) type));
}
@ -901,7 +901,7 @@ public final class GsonBuilder {
new ArrayList<>(reflectionFilters));
}
private void addTypeAdaptersForDate(
private static void addTypeAdaptersForDate(
String datePattern, int dateStyle, int timeStyle, List<TypeAdapterFactory> factories) {
TypeAdapterFactory dateAdapterFactory;
boolean sqlTypesSupported = SqlTypesSupport.SUPPORTS_SQL_TYPES;

View File

@ -38,7 +38,10 @@ public final class JsonPrimitive extends JsonElement {
*
* @param bool the value to create the primitive with.
*/
@SuppressWarnings("deprecation") // superclass constructor
// "deprecation" suppression for superclass constructor
// "UnnecessaryBoxedVariable" Error Prone warning is correct since method does not accept
// null, but cannot be changed anymore since this is public API
@SuppressWarnings({"deprecation", "UnnecessaryBoxedVariable"})
public JsonPrimitive(Boolean bool) {
value = Objects.requireNonNull(bool);
}
@ -69,7 +72,10 @@ public final class JsonPrimitive extends JsonElement {
*
* @param c the value to create the primitive with.
*/
@SuppressWarnings("deprecation") // superclass constructor
// "deprecation" suppression for superclass constructor
// "UnnecessaryBoxedVariable" Error Prone warning is correct since method does not accept
// null, but cannot be changed anymore since this is public API
@SuppressWarnings({"deprecation", "UnnecessaryBoxedVariable"})
public JsonPrimitive(Character c) {
// convert characters to strings since in JSON, characters are represented as a single
// character string

View File

@ -144,69 +144,6 @@ public abstract class TypeAdapter<T> {
write(writer, value);
}
/**
* This wrapper method is used to make a type adapter null tolerant. In general, a type adapter is
* required to handle nulls in write and read methods. Here is how this is typically done:<br>
*
* <pre>{@code
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
* new TypeAdapter<Foo>() {
* public Foo read(JsonReader in) throws IOException {
* if (in.peek() == JsonToken.NULL) {
* in.nextNull();
* return null;
* }
* // read a Foo from in and return it
* }
* public void write(JsonWriter out, Foo src) throws IOException {
* if (src == null) {
* out.nullValue();
* return;
* }
* // write src as JSON to out
* }
* }).create();
* }</pre>
*
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with this
* method. Here is how we will rewrite the above example:
*
* <pre>{@code
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
* new TypeAdapter<Foo>() {
* public Foo read(JsonReader in) throws IOException {
* // read a Foo from in and return it
* }
* public void write(JsonWriter out, Foo src) throws IOException {
* // write src as JSON to out
* }
* }.nullSafe()).create();
* }</pre>
*
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
*/
public final TypeAdapter<T> nullSafe() {
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
if (value == null) {
out.nullValue();
} else {
TypeAdapter.this.write(out, value);
}
}
@Override
public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
return TypeAdapter.this.read(reader);
}
};
}
/**
* Converts {@code value} to a JSON document.
*
@ -309,4 +246,67 @@ public abstract class TypeAdapter<T> {
throw new JsonIOException(e);
}
}
/**
* This wrapper method is used to make a type adapter null tolerant. In general, a type adapter is
* required to handle nulls in write and read methods. Here is how this is typically done:<br>
*
* <pre>{@code
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
* new TypeAdapter<Foo>() {
* public Foo read(JsonReader in) throws IOException {
* if (in.peek() == JsonToken.NULL) {
* in.nextNull();
* return null;
* }
* // read a Foo from in and return it
* }
* public void write(JsonWriter out, Foo src) throws IOException {
* if (src == null) {
* out.nullValue();
* return;
* }
* // write src as JSON to out
* }
* }).create();
* }</pre>
*
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with this
* method. Here is how we will rewrite the above example:
*
* <pre>{@code
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
* new TypeAdapter<Foo>() {
* public Foo read(JsonReader in) throws IOException {
* // read a Foo from in and return it
* }
* public void write(JsonWriter out, Foo src) throws IOException {
* // write src as JSON to out
* }
* }.nullSafe()).create();
* }</pre>
*
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
*/
public final TypeAdapter<T> nullSafe() {
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
if (value == null) {
out.nullValue();
} else {
TypeAdapter.this.write(out, value);
}
}
@Override
public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
return TypeAdapter.this.read(reader);
}
};
}
}

View File

@ -216,17 +216,17 @@ public final class Excluder implements TypeAdapterFactory, Cloneable {
return false;
}
private boolean isAnonymousOrNonStaticLocal(Class<?> clazz) {
private static boolean isAnonymousOrNonStaticLocal(Class<?> clazz) {
return !Enum.class.isAssignableFrom(clazz)
&& !isStatic(clazz)
&& (clazz.isAnonymousClass() || clazz.isLocalClass());
}
private boolean isInnerClass(Class<?> clazz) {
private static boolean isInnerClass(Class<?> clazz) {
return clazz.isMemberClass() && !isStatic(clazz);
}
private boolean isStatic(Class<?> clazz) {
private static boolean isStatic(Class<?> clazz) {
return (clazz.getModifiers() & Modifier.STATIC) != 0;
}

View File

@ -27,11 +27,11 @@ public final class JavaVersion {
private static int determineMajorJavaVersion() {
String javaVersion = System.getProperty("java.version");
return getMajorJavaVersion(javaVersion);
return parseMajorJavaVersion(javaVersion);
}
// Visible for testing only
static int getMajorJavaVersion(String javaVersion) {
static int parseMajorJavaVersion(String javaVersion) {
int version = parseDotted(javaVersion);
if (version == -1) {
version = extractBeginningInt(javaVersion);

View File

@ -21,7 +21,10 @@ import java.io.IOException;
/** Internal-only APIs of JsonReader available only to other classes in Gson. */
public abstract class JsonReaderInternalAccess {
public static JsonReaderInternalAccess INSTANCE;
// Suppress warnings because field is initialized by `JsonReader` class during class loading
// (and therefore should be thread-safe), and any usage appears after `JsonReader` was loaded
@SuppressWarnings({"ConstantField", "NonFinalStaticField"})
public static volatile JsonReaderInternalAccess INSTANCE;
/** Changes the type of the current property name token to a string value. */
public abstract void promoteNameToValue(JsonReader reader) throws IOException;

View File

@ -233,7 +233,7 @@ public final class LinkedTreeMap<K, V> extends AbstractMap<K, V> implements Seri
return valuesEqual ? mine : null;
}
private boolean equal(Object a, Object b) {
private static boolean equal(Object a, Object b) {
return Objects.equals(a, b);
}

View File

@ -76,6 +76,7 @@ public class NonNullElementWrapperList<E> extends AbstractList<E> implements Ran
delegate.clear();
}
@SuppressWarnings("UngroupedOverloads") // this is intentionally ungrouped, see comment above
@Override
public boolean remove(Object o) {
return delegate.remove(o);

View File

@ -21,12 +21,13 @@ import java.util.Locale;
/** Provides DateFormats for US locale with patterns which were the default ones before Java 9. */
public class PreJava9DateFormatProvider {
private PreJava9DateFormatProvider() {}
/**
* Returns the same DateFormat as {@code DateFormat.getDateInstance(style, Locale.US)} in Java 8
* or below.
*/
public static DateFormat getUSDateFormat(int style) {
public static DateFormat getUsDateFormat(int style) {
return new SimpleDateFormat(getDateFormatPattern(style), Locale.US);
}
@ -34,7 +35,7 @@ public class PreJava9DateFormatProvider {
* Returns the same DateFormat as {@code DateFormat.getDateTimeInstance(dateStyle, timeStyle,
* Locale.US)} in Java 8 or below.
*/
public static DateFormat getUSDateTimeFormat(int dateStyle, int timeStyle) {
public static DateFormat getUsDateTimeFormat(int dateStyle, int timeStyle) {
String pattern =
getDatePartOfDateTimePattern(dateStyle) + " " + getTimePartOfDateTimePattern(timeStyle);
return new SimpleDateFormat(pattern, Locale.US);

View File

@ -60,7 +60,7 @@ public final class Primitives {
* wrap(String.class) == String.class
* </pre>
*/
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "MissingBraces"})
public static <T> Class<T> wrap(Class<T> type) {
if (type == int.class) return (Class<T>) Integer.class;
if (type == float.class) return (Class<T>) Float.class;
@ -84,7 +84,7 @@ public final class Primitives {
* unwrap(String.class) == String.class
* </pre>
*/
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "MissingBraces"})
public static <T> Class<T> unwrap(Class<T> type) {
if (type == Integer.class) return (Class<T>) int.class;
if (type == Float.class) return (Class<T>) float.class;

View File

@ -81,6 +81,7 @@ public final class Streams {
this.appendable = appendable;
}
@SuppressWarnings("UngroupedOverloads") // this is intentionally ungrouped, see comment below
@Override
public void write(char[] chars, int offset, int length) throws IOException {
currentWrite.setChars(chars);

View File

@ -141,7 +141,7 @@ public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T>
dateFormats.add(DateFormat.getDateInstance(style));
}
if (JavaVersion.isJava9OrLater()) {
dateFormats.add(PreJava9DateFormatProvider.getUSDateFormat(style));
dateFormats.add(PreJava9DateFormatProvider.getUsDateFormat(style));
}
}
@ -152,7 +152,7 @@ public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T>
dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle));
}
if (JavaVersion.isJava9OrLater()) {
dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(dateStyle, timeStyle));
dateFormats.add(PreJava9DateFormatProvider.getUsDateTimeFormat(dateStyle, timeStyle));
}
}

View File

@ -67,7 +67,7 @@ public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapte
}
// Separate helper method to make sure callers retrieve annotation in a consistent way
private JsonAdapter getAnnotation(Class<?> rawType) {
private static JsonAdapter getAnnotation(Class<?> rawType) {
return rawType.getAnnotation(JsonAdapter.class);
}

View File

@ -371,13 +371,13 @@ public final class JsonTreeReader extends JsonReader {
}
@Override
public String getPreviousPath() {
return getPath(true);
public String getPath() {
return getPath(false);
}
@Override
public String getPath() {
return getPath(false);
public String getPreviousPath() {
return getPath(true);
}
private String locationString() {

View File

@ -167,18 +167,6 @@ public final class JsonTreeWriter extends JsonWriter {
return this;
}
@Override
public JsonWriter jsonValue(String value) throws IOException {
throw new UnsupportedOperationException();
}
@CanIgnoreReturnValue
@Override
public JsonWriter nullValue() throws IOException {
put(JsonNull.INSTANCE);
return this;
}
@CanIgnoreReturnValue
@Override
public JsonWriter value(boolean value) throws IOException {
@ -241,6 +229,18 @@ public final class JsonTreeWriter extends JsonWriter {
return this;
}
@CanIgnoreReturnValue
@Override
public JsonWriter nullValue() throws IOException {
put(JsonNull.INSTANCE);
return this;
}
@Override
public JsonWriter jsonValue(String value) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void flush() throws IOException {}

View File

@ -172,7 +172,9 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
constructorConstructor, context, fieldType, annotation, false);
}
final boolean jsonAdapterPresent = mapped != null;
if (mapped == null) mapped = context.getAdapter(fieldType);
if (mapped == null) {
mapped = context.getAdapter(fieldType);
}
@SuppressWarnings("unchecked")
final TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) mapped;

View File

@ -594,7 +594,7 @@ public final class TypeAdapters {
return null;
}
String nextString = in.nextString();
return "null".equals(nextString) ? null : new URL(nextString);
return nextString.equals("null") ? null : new URL(nextString);
}
@Override
@ -615,7 +615,7 @@ public final class TypeAdapters {
}
try {
String nextString = in.nextString();
return "null".equals(nextString) ? null : new URI(nextString);
return nextString.equals("null") ? null : new URI(nextString);
} catch (URISyntaxException e) {
throw new JsonIOException(e);
}
@ -724,18 +724,27 @@ public final class TypeAdapters {
while (in.peek() != JsonToken.END_OBJECT) {
String name = in.nextName();
int value = in.nextInt();
if (YEAR.equals(name)) {
year = value;
} else if (MONTH.equals(name)) {
month = value;
} else if (DAY_OF_MONTH.equals(name)) {
dayOfMonth = value;
} else if (HOUR_OF_DAY.equals(name)) {
hourOfDay = value;
} else if (MINUTE.equals(name)) {
minute = value;
} else if (SECOND.equals(name)) {
second = value;
switch (name) {
case YEAR:
year = value;
break;
case MONTH:
month = value;
break;
case DAY_OF_MONTH:
dayOfMonth = value;
break;
case HOUR_OF_DAY:
hourOfDay = value;
break;
case MINUTE:
minute = value;
break;
case SECOND:
second = value;
break;
default:
// Ignore unknown JSON property
}
}
in.endObject();
@ -1030,6 +1039,7 @@ public final class TypeAdapters {
}
};
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactory(
final TypeToken<TT> type, final TypeAdapter<TT> typeAdapter) {
return new TypeAdapterFactory() {
@ -1041,6 +1051,7 @@ public final class TypeAdapters {
};
}
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactory(
final Class<TT> type, final TypeAdapter<TT> typeAdapter) {
return new TypeAdapterFactory() {
@ -1057,6 +1068,7 @@ public final class TypeAdapters {
};
}
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactory(
final Class<TT> unboxed, final Class<TT> boxed, final TypeAdapter<? super TT> typeAdapter) {
return new TypeAdapterFactory() {
@ -1080,6 +1092,7 @@ public final class TypeAdapters {
};
}
@SuppressWarnings("TypeParameterNaming")
public static <TT> TypeAdapterFactory newFactoryForMultipleTypes(
final Class<TT> base,
final Class<? extends TT> sub,

View File

@ -36,6 +36,8 @@ import java.util.TimeZone;
// Date parsing code from Jackson databind ISO8601Utils.java
// https://github.com/FasterXML/jackson-databind/blob/2.8/src/main/java/com/fasterxml/jackson/databind/util/ISO8601Utils.java
public class ISO8601Utils {
private ISO8601Utils() {}
/**
* ID to represent the 'UTC' string, default timezone since Jackson 2.7
*
@ -197,7 +199,9 @@ public class ISO8601Utils {
char c = date.charAt(offset);
if (c != 'Z' && c != '+' && c != '-') {
seconds = parseInt(date, offset, offset += 2);
if (seconds > 59 && seconds < 63) seconds = 59; // truncate up to 3 leap seconds
if (seconds > 59 && seconds < 63) {
seconds = 59; // truncate up to 3 leap seconds
}
// milliseconds can be optional in the format
if (checkOffset(date, offset, '.')) {
offset += 1;
@ -241,7 +245,7 @@ public class ISO8601Utils {
offset += timezoneOffset.length();
// 18-Jun-2015, tatu: Minor simplification, skip offset of "+0000"/"+00:00"
if ("+0000".equals(timezoneOffset) || "+00:00".equals(timezoneOffset)) {
if (timezoneOffset.equals("+0000") || timezoneOffset.equals("+00:00")) {
timezone = TIMEZONE_UTC;
} else {
// 18-Jun-2015, tatu: Looks like offsets only work from GMT, not UTC...
@ -372,7 +376,9 @@ public class ISO8601Utils {
private static int indexOfNonDigit(String string, int offset) {
for (int i = offset; i < string.length(); i++) {
char c = string.charAt(i);
if (c < '0' || c > '9') return i;
if (c < '0' || c > '9') {
return i;
}
}
return string.length();
}

View File

@ -1141,6 +1141,8 @@ public class JsonReader implements Closeable {
case '\r':
case '\n':
break findNonLiteralCharacter;
default:
// skip character to be included in string value
}
}
@ -1223,6 +1225,8 @@ public class JsonReader implements Closeable {
case '\n':
pos += i;
return;
default:
// skip the character
}
}
pos += i;
@ -1380,6 +1384,7 @@ public class JsonReader implements Closeable {
case PEEKED_EOF:
// Do nothing
return;
default:
// For all other tokens there is nothing to do; token has already been consumed from
// underlying reader
}
@ -1586,7 +1591,8 @@ public class JsonReader implements Closeable {
private String getPath(boolean usePreviousPath) {
StringBuilder result = new StringBuilder().append('$');
for (int i = 0; i < stackSize; i++) {
switch (stack[i]) {
int scope = stack[i];
switch (scope) {
case JsonScope.EMPTY_ARRAY:
case JsonScope.NONEMPTY_ARRAY:
int pathIndex = pathIndices[i];
@ -1608,29 +1614,13 @@ public class JsonReader implements Closeable {
case JsonScope.EMPTY_DOCUMENT:
case JsonScope.CLOSED:
break;
default:
throw new AssertionError("Unknown scope value: " + scope);
}
}
return result.toString();
}
/**
* Returns a <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> in <i>dot-notation</i>
* to the previous (or current) location in the JSON document. That means:
*
* <ul>
* <li>For JSON arrays the path points to the index of the previous element.<br>
* If no element has been consumed yet it uses the index 0 (even if there are no elements).
* <li>For JSON objects the path points to the last property, or to the current property if its
* name has already been consumed.
* </ul>
*
* <p>This method can be useful to add additional context to exception messages <i>after</i> a
* value has been consumed.
*/
public String getPreviousPath() {
return getPath(true);
}
/**
* Returns a <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> in <i>dot-notation</i>
* to the next (or current) location in the JSON document. That means:
@ -1649,6 +1639,24 @@ public class JsonReader implements Closeable {
return getPath(false);
}
/**
* Returns a <a href="https://goessner.net/articles/JsonPath/">JSONPath</a> in <i>dot-notation</i>
* to the previous (or current) location in the JSON document. That means:
*
* <ul>
* <li>For JSON arrays the path points to the index of the previous element.<br>
* If no element has been consumed yet it uses the index 0 (even if there are no elements).
* <li>For JSON objects the path points to the last property, or to the current property if its
* name has already been consumed.
* </ul>
*
* <p>This method can be useful to add additional context to exception messages <i>after</i> a
* value has been consumed.
*/
public String getPreviousPath() {
return getPath(true);
}
/**
* Unescapes the character identified by the character or characters that immediately follow a
* backslash. The backslash '\' should have already been read. This supports both Unicode escapes

View File

@ -23,6 +23,7 @@ package com.google.gson.stream;
* @since 1.6
*/
final class JsonScope {
private JsonScope() {}
/** An array with no elements requires no separator before the next element. */
static final int EMPTY_ARRAY = 1;

View File

@ -396,7 +396,7 @@ public class JsonWriter implements Closeable, Flushable {
@CanIgnoreReturnValue
public JsonWriter beginArray() throws IOException {
writeDeferredName();
return open(EMPTY_ARRAY, '[');
return openScope(EMPTY_ARRAY, '[');
}
/**
@ -406,7 +406,7 @@ public class JsonWriter implements Closeable, Flushable {
*/
@CanIgnoreReturnValue
public JsonWriter endArray() throws IOException {
return close(EMPTY_ARRAY, NONEMPTY_ARRAY, ']');
return closeScope(EMPTY_ARRAY, NONEMPTY_ARRAY, ']');
}
/**
@ -418,7 +418,7 @@ public class JsonWriter implements Closeable, Flushable {
@CanIgnoreReturnValue
public JsonWriter beginObject() throws IOException {
writeDeferredName();
return open(EMPTY_OBJECT, '{');
return openScope(EMPTY_OBJECT, '{');
}
/**
@ -428,12 +428,12 @@ public class JsonWriter implements Closeable, Flushable {
*/
@CanIgnoreReturnValue
public JsonWriter endObject() throws IOException {
return close(EMPTY_OBJECT, NONEMPTY_OBJECT, '}');
return closeScope(EMPTY_OBJECT, NONEMPTY_OBJECT, '}');
}
/** Enters a new scope by appending any necessary whitespace and the given bracket. */
@CanIgnoreReturnValue
private JsonWriter open(int empty, char openBracket) throws IOException {
private JsonWriter openScope(int empty, char openBracket) throws IOException {
beforeValue();
push(empty);
out.write(openBracket);
@ -442,7 +442,7 @@ public class JsonWriter implements Closeable, Flushable {
/** Closes the current scope by appending any necessary whitespace and the given bracket. */
@CanIgnoreReturnValue
private JsonWriter close(int empty, int nonempty, char closeBracket) throws IOException {
private JsonWriter closeScope(int empty, int nonempty, char closeBracket) throws IOException {
int context = peek();
if (context != nonempty && context != empty) {
throw new IllegalStateException("Nesting problem.");
@ -524,47 +524,6 @@ public class JsonWriter implements Closeable, Flushable {
return this;
}
/**
* Writes {@code value} directly to the writer without quoting or escaping. This might not be
* supported by all implementations, if not supported an {@code UnsupportedOperationException} is
* thrown.
*
* @param value the literal string value, or null to encode a null literal.
* @return this writer.
* @throws UnsupportedOperationException if this writer does not support writing raw JSON values.
* @since 2.4
*/
@CanIgnoreReturnValue
public JsonWriter jsonValue(String value) throws IOException {
if (value == null) {
return nullValue();
}
writeDeferredName();
beforeValue();
out.append(value);
return this;
}
/**
* Encodes {@code null}.
*
* @return this writer.
*/
@CanIgnoreReturnValue
public JsonWriter nullValue() throws IOException {
if (deferredName != null) {
if (serializeNulls) {
writeDeferredName();
} else {
deferredName = null;
return this; // skip the name and the value
}
}
beforeValue();
out.write("null");
return this;
}
/**
* Encodes {@code value}.
*
@ -649,25 +608,6 @@ public class JsonWriter implements Closeable, Flushable {
return this;
}
/**
* Returns whether the {@code toString()} of {@code c} can be trusted to return a valid JSON
* number.
*/
private static boolean isTrustedNumberType(Class<? extends Number> c) {
// Note: Don't consider LazilyParsedNumber trusted because it could contain
// an arbitrary malformed string
return c == Integer.class
|| c == Long.class
|| c == Double.class
|| c == Float.class
|| c == Byte.class
|| c == Short.class
|| c == BigDecimal.class
|| c == BigInteger.class
|| c == AtomicInteger.class
|| c == AtomicLong.class;
}
/**
* Encodes {@code value}. The value is written by directly writing the {@link Number#toString()}
* result to JSON. Implementations must make sure that the result represents a valid JSON number.
@ -706,6 +646,47 @@ public class JsonWriter implements Closeable, Flushable {
return this;
}
/**
* Encodes {@code null}.
*
* @return this writer.
*/
@CanIgnoreReturnValue
public JsonWriter nullValue() throws IOException {
if (deferredName != null) {
if (serializeNulls) {
writeDeferredName();
} else {
deferredName = null;
return this; // skip the name and the value
}
}
beforeValue();
out.write("null");
return this;
}
/**
* Writes {@code value} directly to the writer without quoting or escaping. This might not be
* supported by all implementations, if not supported an {@code UnsupportedOperationException} is
* thrown.
*
* @param value the literal string value, or null to encode a null literal.
* @return this writer.
* @throws UnsupportedOperationException if this writer does not support writing raw JSON values.
* @since 2.4
*/
@CanIgnoreReturnValue
public JsonWriter jsonValue(String value) throws IOException {
if (value == null) {
return nullValue();
}
writeDeferredName();
beforeValue();
out.append(value);
return this;
}
/**
* Ensures all buffered data is written to the underlying {@link Writer} and flushes that writer.
*/
@ -733,6 +714,25 @@ public class JsonWriter implements Closeable, Flushable {
stackSize = 0;
}
/**
* Returns whether the {@code toString()} of {@code c} can be trusted to return a valid JSON
* number.
*/
private static boolean isTrustedNumberType(Class<? extends Number> c) {
// Note: Don't consider LazilyParsedNumber trusted because it could contain
// an arbitrary malformed string
return c == Integer.class
|| c == Long.class
|| c == Double.class
|| c == Float.class
|| c == Byte.class
|| c == Short.class
|| c == BigDecimal.class
|| c == BigInteger.class
|| c == AtomicInteger.class
|| c == AtomicLong.class;
}
private void string(String value) throws IOException {
String[] replacements = htmlSafe ? HTML_SAFE_REPLACEMENT_CHARS : REPLACEMENT_CHARS;
out.write('\"');

View File

@ -115,7 +115,7 @@ public class FieldNamingPolicyTest {
@Test
public void testLowerCasingLocaleIndependent() throws Exception {
class Dummy {
@SuppressWarnings("unused")
@SuppressWarnings({"unused", "ConstantField"})
int I;
}

View File

@ -151,7 +151,7 @@ public class GsonTypeAdapterTest {
assertSerialized("{\"b\":\"beep\",\"a\":\"android\"}", Concrete.class, false, false, instance);
}
private void assertSerialized(
private static void assertSerialized(
String expected,
Class<?> instanceType,
boolean registerAbstractDeserializer,

View File

@ -66,7 +66,7 @@ public final class JavaSerializationTest {
}
@SuppressWarnings("unchecked") // Serialization promises to return the same type.
private <T> T serializedCopy(T object) throws IOException, ClassNotFoundException {
private static <T> T serializedCopy(T object) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bytesOut);
out.writeObject(object);

View File

@ -19,7 +19,6 @@ package com.google.gson;
import com.google.common.base.Objects;
import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.Primitives;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@ -33,6 +32,7 @@ import java.lang.reflect.Type;
* @author Joel Leitch
*/
public class ParameterizedTypeFixtures {
private ParameterizedTypeFixtures() {}
public static final class MyParameterizedType<T> {
public final T value;
@ -50,7 +50,7 @@ public class ParameterizedTypeFixtures {
return String.format("{\"value\":%s}", valueAsJson);
}
private String getExpectedJson(Object obj) {
private static String getExpectedJson(Object obj) {
Class<?> clazz = obj.getClass();
if (Primitives.isWrapperType(Primitives.wrap(clazz))) {
return obj.toString();
@ -62,15 +62,7 @@ public class ParameterizedTypeFixtures {
Method method = clazz.getMethod("getExpectedJson");
Object results = method.invoke(obj);
return (String) results;
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}

View File

@ -18,7 +18,6 @@ package com.google.gson;
import com.google.gson.internal.Primitives;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
@ -45,13 +44,7 @@ final class PrimitiveTypeAdapter {
try {
Constructor<?> constructor = aClass.getConstructor(String.class);
return (T) constructor.newInstance(from.toString());
} catch (NoSuchMethodException e) {
throw new JsonParseException(e);
} catch (IllegalAccessException e) {
throw new JsonParseException(e);
} catch (InvocationTargetException e) {
throw new JsonParseException(e);
} catch (InstantiationException e) {
} catch (ReflectiveOperationException e) {
throw new JsonParseException(e);
}
} else if (Enum.class.isAssignableFrom(to)) {
@ -60,11 +53,7 @@ final class PrimitiveTypeAdapter {
try {
Method valuesMethod = to.getMethod("valueOf", String.class);
return (T) valuesMethod.invoke(null, from.toString());
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
} else {

View File

@ -30,6 +30,7 @@ import org.junit.Assert;
* @author Inderjeet Singh
*/
public class MoreAsserts {
private MoreAsserts() {}
/**
* Asserts that the specified {@code value} is not present in {@code collection}

View File

@ -36,6 +36,7 @@ import java.util.Collection;
* @author Joel Leitch
*/
public class TestTypes {
private TestTypes() {}
public static class Base {
public static final String BASE_NAME = Base.class.getSimpleName();

View File

@ -70,8 +70,8 @@ public class EscapingTest {
assertThat(jsonRepresentation).doesNotContain(">");
assertThat(jsonRepresentation).contains("\\\"");
BagOfPrimitives expectedObject = gson.fromJson(jsonRepresentation, BagOfPrimitives.class);
assertThat(objWithPrimitives.getExpectedJson()).isEqualTo(expectedObject.getExpectedJson());
BagOfPrimitives deserialized = gson.fromJson(jsonRepresentation, BagOfPrimitives.class);
assertThat(deserialized.getExpectedJson()).isEqualTo(objWithPrimitives.getExpectedJson());
}
@Test

View File

@ -91,11 +91,12 @@ public final class FieldNamingTest {
+ "'annotatedName':7,'lower-id':8,'_9':9}");
}
private Gson getGsonWithNamingPolicy(FieldNamingPolicy fieldNamingPolicy) {
private static Gson getGsonWithNamingPolicy(FieldNamingPolicy fieldNamingPolicy) {
return new GsonBuilder().setFieldNamingPolicy(fieldNamingPolicy).create();
}
@SuppressWarnings("unused") // fields are used reflectively
// Suppress because fields are used reflectively, and the names are intentionally unconventional
@SuppressWarnings({"unused", "MemberName", "ConstantField"})
private static class TestNames {
int lowerCamel = 1;
int UpperCamel = 2;

View File

@ -79,7 +79,7 @@ public class GsonVersionDiagnosticsTest {
ensureAssertionErrorPrintsGsonVersion(e);
}
private void ensureAssertionErrorPrintsGsonVersion(AssertionError expected) {
private static void ensureAssertionErrorPrintsGsonVersion(AssertionError expected) {
String msg = expected.getMessage();
// System.err.println(msg);
int start = msg.indexOf("(GSON");

View File

@ -275,7 +275,7 @@ public class InheritanceTest {
}
@CanIgnoreReturnValue
private StringBuilder append(StringBuilder sb, Collection<?> c) {
private static StringBuilder append(StringBuilder sb, Collection<?> c) {
sb.append("[");
boolean first = true;
for (Object o : c) {

View File

@ -354,6 +354,7 @@ public final class Java17RecordTest {
}
private record RecordWithStaticField() {
@SuppressWarnings("NonFinalStaticField")
static String s = "initial";
}

View File

@ -44,6 +44,7 @@ import java.util.Locale;
import org.junit.Test;
/** Functional tests for the {@link JsonAdapter} annotation on classes. */
@SuppressWarnings("ClassNamedLikeTypeParameter") // for dummy classes A, B, ...
public final class JsonAdapterAnnotationOnClassesTest {
@Test
@ -305,7 +306,8 @@ public final class JsonAdapterAnnotationOnClassesTest {
// This class is used in JsonAdapter Javadoc as an example
@JsonAdapter(UserJsonAdapter.class)
private static class User {
final String firstName, lastName;
final String firstName;
final String lastName;
User(String firstName, String lastName) {
this.firstName = firstName;

View File

@ -240,6 +240,7 @@ public final class JsonAdapterSerializerDeserializerTest {
assertThat(deserialized.userDN).isNull();
}
@SuppressWarnings("MemberName")
private static final class WithNullSafe {
// "userS..." uses JsonSerializer
@JsonAdapter(value = UserSerializer.class, nullSafe = false)

View File

@ -89,7 +89,7 @@ public class JsonTreeTest {
assertThat(jsonElement.has("stringValue")).isFalse();
}
private void assertContains(JsonObject json, JsonPrimitive child) {
private static void assertContains(JsonObject json, JsonPrimitive child) {
for (Map.Entry<String, JsonElement> entry : json.entrySet()) {
JsonElement node = entry.getValue();
if (node.isJsonPrimitive()) {

View File

@ -641,7 +641,7 @@ public class MapTest {
assertThat(gson.fromJson(json, type)).isEqualTo(map);
}
private <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
Map<K, V> result = new LinkedHashMap<>();
result.put(key1, value1);
result.put(key2, value2);

View File

@ -23,6 +23,7 @@ import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
@ -51,7 +52,7 @@ public class MoreSpecificTypeSerializationTest {
@Test
public void testListOfSubclassFields() {
Collection<Base> list = new ArrayList<>();
List<Base> list = new ArrayList<>();
list.add(new Base(1));
list.add(new Sub(2, 3));
ClassWithContainersOfBaseFields target = new ClassWithContainersOfBaseFields(list, null);
@ -89,7 +90,7 @@ public class MoreSpecificTypeSerializationTest {
*/
@Test
public void testListOfParameterizedSubclassFields() {
Collection<ParameterizedBase<String>> list = new ArrayList<>();
List<ParameterizedBase<String>> list = new ArrayList<>();
list.add(new ParameterizedBase<>("one"));
list.add(new ParameterizedSub<>("two", "three"));
ClassWithContainersOfParameterizedBaseFields target =

View File

@ -177,12 +177,13 @@ public class NullObjectAndFieldTest {
public static class ClassWithInitializedMembers {
// Using a mix of no-args constructor and field initializers
// Also, some fields are intialized and some are not (so initialized per JVM spec)
// Also, some fields are initialized and some are not (so initialized per JVM spec)
public static final String MY_STRING_DEFAULT = "string";
private static final int MY_INT_DEFAULT = 2;
private static final boolean MY_BOOLEAN_DEFAULT = true;
int[] array;
String str1, str2;
String str1;
String str2;
int int1 = MY_INT_DEFAULT;
int int2;
boolean bool1 = MY_BOOLEAN_DEFAULT;

View File

@ -678,10 +678,12 @@ public class ObjectTest {
}
}
@SuppressWarnings({"PrivateConstructorForUtilityClass", "NonFinalStaticField"})
static class ClassWithStaticField {
static String s = "initial";
}
@SuppressWarnings("PrivateConstructorForUtilityClass")
static class ClassWithStaticFinalField {
static final String s = "initial";
}

View File

@ -39,8 +39,6 @@ import org.junit.Test;
*/
public class PrettyPrintingTest {
private static final boolean DEBUG = false;
private Gson gson;
@Before
@ -52,31 +50,75 @@ public class PrettyPrintingTest {
public void testPrettyPrintList() {
BagOfPrimitives b = new BagOfPrimitives();
List<BagOfPrimitives> listOfB = new ArrayList<>();
for (int i = 0; i < 15; ++i) {
for (int i = 0; i < 3; ++i) {
listOfB.add(b);
}
Type typeOfSrc = new TypeToken<List<BagOfPrimitives>>() {}.getType();
String json = gson.toJson(listOfB, typeOfSrc);
print(json);
assertThat(json)
.isEqualTo(
"[\n"
+ " {\n"
+ " \"longValue\": 0,\n"
+ " \"intValue\": 0,\n"
+ " \"booleanValue\": false,\n"
+ " \"stringValue\": \"\"\n"
+ " },\n"
+ " {\n"
+ " \"longValue\": 0,\n"
+ " \"intValue\": 0,\n"
+ " \"booleanValue\": false,\n"
+ " \"stringValue\": \"\"\n"
+ " },\n"
+ " {\n"
+ " \"longValue\": 0,\n"
+ " \"intValue\": 0,\n"
+ " \"booleanValue\": false,\n"
+ " \"stringValue\": \"\"\n"
+ " }\n"
+ "]");
}
@Test
public void testPrettyPrintArrayOfObjects() {
ArrayOfObjects target = new ArrayOfObjects();
String json = gson.toJson(target);
print(json);
assertThat(json)
.isEqualTo(
"{\n"
+ " \"elements\": [\n"
+ " {\n"
+ " \"longValue\": 0,\n"
+ " \"intValue\": 2,\n"
+ " \"booleanValue\": false,\n"
+ " \"stringValue\": \"i0\"\n"
+ " },\n"
+ " {\n"
+ " \"longValue\": 1,\n"
+ " \"intValue\": 3,\n"
+ " \"booleanValue\": false,\n"
+ " \"stringValue\": \"i1\"\n"
+ " },\n"
+ " {\n"
+ " \"longValue\": 2,\n"
+ " \"intValue\": 4,\n"
+ " \"booleanValue\": false,\n"
+ " \"stringValue\": \"i2\"\n"
+ " }\n"
+ " ]\n"
+ "}");
}
@Test
public void testPrettyPrintArrayOfPrimitives() {
int[] ints = new int[] {1, 2, 3, 4, 5};
int[] ints = {1, 2, 3, 4, 5};
String json = gson.toJson(ints);
assertThat(json).isEqualTo("[\n 1,\n 2,\n 3,\n 4,\n 5\n]");
}
@Test
public void testPrettyPrintArrayOfPrimitiveArrays() {
int[][] ints = new int[][] {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}, {10}};
int[][] ints = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}, {10}};
String json = gson.toJson(ints);
assertThat(json)
.isEqualTo(
@ -121,14 +163,8 @@ public class PrettyPrintingTest {
@Test
public void testMultipleArrays() {
int[][][] ints = new int[][][] {{{1}, {2}}};
int[][][] ints = {{{1}, {2}}};
String json = gson.toJson(ints);
assertThat(json).isEqualTo("[\n [\n [\n 1\n ],\n [\n 2\n ]\n ]\n]");
}
private void print(String msg) {
if (DEBUG) {
System.out.println(msg);
}
}
}

View File

@ -526,7 +526,7 @@ public class PrimitiveTest {
assertThat(actualJson).isNotEqualTo(expectedJson);
}
private String extractElementFromArray(String json) {
private static String extractElementFromArray(String json) {
return json.substring(json.indexOf('[') + 1, json.indexOf(']'));
}

View File

@ -152,7 +152,7 @@ public class ReflectionAccessFilterTest {
}
private static class ClassWithStaticField {
@SuppressWarnings("unused")
@SuppressWarnings({"unused", "NonFinalStaticField"})
private static int i = 1;
}

View File

@ -139,7 +139,7 @@ public final class TypeAdapterPrecedenceTest {
}
}
private JsonSerializer<Foo> newSerializer(final String name) {
private static JsonSerializer<Foo> newSerializer(final String name) {
return new JsonSerializer<Foo>() {
@Override
public JsonElement serialize(Foo src, Type typeOfSrc, JsonSerializationContext context) {
@ -148,7 +148,7 @@ public final class TypeAdapterPrecedenceTest {
};
}
private JsonDeserializer<Foo> newDeserializer(final String name) {
private static JsonDeserializer<Foo> newDeserializer(final String name) {
return new JsonDeserializer<Foo>() {
@Override
public Foo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
@ -157,7 +157,7 @@ public final class TypeAdapterPrecedenceTest {
};
}
private TypeAdapter<Foo> newTypeAdapter(final String name) {
private static TypeAdapter<Foo> newTypeAdapter(final String name) {
return new TypeAdapter<Foo>() {
@Override
public Foo read(JsonReader in) throws IOException {

View File

@ -85,9 +85,12 @@ public class VersioningTest {
public void testVersionedClassesDeserialization() {
Gson gson = gsonWithVersion(1.0);
String json = "{\"a\":3,\"b\":4,\"c\":5}";
Version1 version1 = gson.fromJson(json, Version1.class);
assertThat(version1.a).isEqualTo(3);
assertThat(version1.b).isEqualTo(4);
@SuppressWarnings("MemberName")
Version1_1 version1_1 = gson.fromJson(json, Version1_1.class);
assertThat(version1_1.a).isEqualTo(3);
assertThat(version1_1.b).isEqualTo(4);
@ -104,6 +107,8 @@ public class VersioningTest {
public void testIgnoreLaterVersionClassDeserialization() {
Gson gson = gsonWithVersion(1.0);
String json = "{\"a\":3,\"b\":4,\"c\":5,\"d\":6}";
@SuppressWarnings("MemberName")
Version1_2 version1_2 = gson.fromJson(json, Version1_2.class);
// Since the class is versioned to be after 1.0, we expect null
// This is the new behavior in Gson 2.0

View File

@ -24,6 +24,7 @@ import java.lang.reflect.Type;
import java.util.List;
import org.junit.Test;
@SuppressWarnings("ClassNamedLikeTypeParameter") // for dummy classes A, B, ...
public final class GsonTypesTest {
@Test
@ -87,10 +88,14 @@ public final class GsonTypesTest {
* type, returns null.
*/
public static Type getFirstTypeArgument(Type type) throws Exception {
if (!(type instanceof ParameterizedType)) return null;
if (!(type instanceof ParameterizedType)) {
return null;
}
ParameterizedType ptype = (ParameterizedType) type;
Type[] actualTypeArguments = ptype.getActualTypeArguments();
if (actualTypeArguments.length == 0) return null;
if (actualTypeArguments.length == 0) {
return null;
}
return $Gson$Types.canonicalize(actualTypeArguments[0]);
}
}

View File

@ -37,49 +37,49 @@ public class JavaVersionTest {
@Test
public void testJava6() {
// http://www.oracle.com/technetwork/java/javase/version-6-141920.html
assertThat(JavaVersion.getMajorJavaVersion("1.6.0")).isEqualTo(6);
assertThat(JavaVersion.parseMajorJavaVersion("1.6.0")).isEqualTo(6);
}
@Test
public void testJava7() {
// http://www.oracle.com/technetwork/java/javase/jdk7-naming-418744.html
assertThat(JavaVersion.getMajorJavaVersion("1.7.0")).isEqualTo(7);
assertThat(JavaVersion.parseMajorJavaVersion("1.7.0")).isEqualTo(7);
}
@Test
public void testJava8() {
assertThat(JavaVersion.getMajorJavaVersion("1.8")).isEqualTo(8);
assertThat(JavaVersion.getMajorJavaVersion("1.8.0")).isEqualTo(8);
assertThat(JavaVersion.getMajorJavaVersion("1.8.0_131")).isEqualTo(8);
assertThat(JavaVersion.getMajorJavaVersion("1.8.0_60-ea")).isEqualTo(8);
assertThat(JavaVersion.getMajorJavaVersion("1.8.0_111-internal")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8.0")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8.0_131")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8.0_60-ea")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8.0_111-internal")).isEqualTo(8);
// openjdk8 per https://github.com/AdoptOpenJDK/openjdk-build/issues/93
assertThat(JavaVersion.getMajorJavaVersion("1.8.0-internal")).isEqualTo(8);
assertThat(JavaVersion.getMajorJavaVersion("1.8.0_131-adoptopenjdk")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8.0-internal")).isEqualTo(8);
assertThat(JavaVersion.parseMajorJavaVersion("1.8.0_131-adoptopenjdk")).isEqualTo(8);
}
@Test
public void testJava9() {
// Legacy style
assertThat(JavaVersion.getMajorJavaVersion("9.0.4")).isEqualTo(9); // Oracle JDK 9
assertThat(JavaVersion.parseMajorJavaVersion("9.0.4")).isEqualTo(9); // Oracle JDK 9
// Debian as reported in https://github.com/google/gson/issues/1310
assertThat(JavaVersion.getMajorJavaVersion("9-Debian")).isEqualTo(9);
assertThat(JavaVersion.parseMajorJavaVersion("9-Debian")).isEqualTo(9);
// New style
assertThat(JavaVersion.getMajorJavaVersion("9-ea+19")).isEqualTo(9);
assertThat(JavaVersion.getMajorJavaVersion("9+100")).isEqualTo(9);
assertThat(JavaVersion.getMajorJavaVersion("9.0.1+20")).isEqualTo(9);
assertThat(JavaVersion.getMajorJavaVersion("9.1.1+20")).isEqualTo(9);
assertThat(JavaVersion.parseMajorJavaVersion("9-ea+19")).isEqualTo(9);
assertThat(JavaVersion.parseMajorJavaVersion("9+100")).isEqualTo(9);
assertThat(JavaVersion.parseMajorJavaVersion("9.0.1+20")).isEqualTo(9);
assertThat(JavaVersion.parseMajorJavaVersion("9.1.1+20")).isEqualTo(9);
}
@Test
public void testJava10() {
assertThat(JavaVersion.getMajorJavaVersion("10.0.1")).isEqualTo(10); // Oracle JDK 10.0.1
assertThat(JavaVersion.parseMajorJavaVersion("10.0.1")).isEqualTo(10); // Oracle JDK 10.0.1
}
@Test
public void testUnknownVersionFormat() {
assertThat(JavaVersion.getMajorJavaVersion("Java9")).isEqualTo(6); // unknown format
assertThat(JavaVersion.parseMajorJavaVersion("Java9")).isEqualTo(6); // unknown format
}
}

View File

@ -237,7 +237,7 @@ public final class LinkedTreeMapTest {
@SuppressWarnings("varargs")
@SafeVarargs
private final <T> void assertIterationOrder(Iterable<T> actual, T... expected) {
private static final <T> void assertIterationOrder(Iterable<T> actual, T... expected) {
ArrayList<T> actualList = new ArrayList<>();
for (T t : actual) {
actualList.add(t);

View File

@ -52,7 +52,7 @@ public class DefaultDateTypeAdapterTest {
assertFormattingAlwaysEmitsUsLocale(Locale.FRANCE);
}
private void assertFormattingAlwaysEmitsUsLocale(Locale locale) {
private static void assertFormattingAlwaysEmitsUsLocale(Locale locale) {
TimeZone defaultTimeZone = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Locale defaultLocale = Locale.getDefault();

View File

@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.functional.DefaultTypeAdaptersTest;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Locale;
@ -30,6 +29,8 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
// Suppression for `java.sql.Date` to make it explicit that this is not `java.util.Date`
@SuppressWarnings("UnnecessarilyFullyQualified")
public class SqlTypesGsonTest {
private Gson gson;
private TimeZone oldTimeZone;
@ -52,7 +53,7 @@ public class SqlTypesGsonTest {
@Test
public void testNullSerializationAndDeserialization() {
testNullSerializationAndDeserialization(Date.class);
testNullSerializationAndDeserialization(java.sql.Date.class);
testNullSerializationAndDeserialization(Time.class);
testNullSerializationAndDeserialization(Timestamp.class);
}

View File

@ -39,6 +39,7 @@ import org.junit.Test;
* @author Inderjeet Singh
* @author Joel Leitch
*/
@SuppressWarnings("SystemOut") // allow System.out because test is for manual execution anyway
public class PerformanceTest {
private static final int COLLECTION_SIZE = 5000;
@ -292,7 +293,7 @@ public class PerformanceTest {
Map<Long, Long> unused = gson.fromJson(json, longToLong);
}
private String buildJsonForClassWithList() {
private static String buildJsonForClassWithList() {
StringBuilder sb = new StringBuilder("{");
sb.append("field:").append("'str',");
sb.append("list:[");
@ -301,12 +302,12 @@ public class PerformanceTest {
if (first) {
first = false;
} else {
sb.append(",");
sb.append(',');
}
sb.append("{field:'element-" + i + "'}");
}
sb.append("]");
sb.append("}");
sb.append(']');
sb.append('}');
String json = sb.toString();
return json;
}

View File

@ -37,6 +37,9 @@ import org.junit.Test;
*
* @author Jesse Wilson
*/
// Suppress because these classes are only needed for this test, but must be top-level classes
// to not have an enclosing type
@SuppressWarnings("MultipleTopLevelClasses")
public final class TypeTokenTest {
// These fields are accessed using reflection by the tests below
List<Integer> listOfInteger = null;

View File

@ -884,7 +884,7 @@ public final class JsonReaderTest {
assertNotANumber("-.0e1");
}
private void assertNotANumber(String s) throws IOException {
private static void assertNotANumber(String s) throws IOException {
JsonReader reader = new JsonReader(reader(s));
reader.setStrictness(Strictness.LENIENT);
assertThat(reader.peek()).isEqualTo(JsonToken.STRING);
@ -1858,6 +1858,7 @@ public final class JsonReaderTest {
}
}
@SuppressWarnings("UngroupedOverloads")
@Test
public void testFailWithPosition() throws IOException {
testFailWithPosition("Expected value at line 6 column 5 path $[1]", "[\n\n\n\n\n\"a\",}]");
@ -1909,7 +1910,7 @@ public final class JsonReaderTest {
testFailWithPosition("Expected value at line 1 column 6 path $[1]", "\ufeff[\"a\",}]");
}
private void testFailWithPosition(String message, String json) throws IOException {
private static void testFailWithPosition(String message, String json) throws IOException {
// Validate that it works reading the string normally.
JsonReader reader1 = new JsonReader(reader(json));
reader1.setStrictness(Strictness.LENIENT);
@ -2264,7 +2265,7 @@ public final class JsonReaderTest {
}
}
private String repeat(char c, int count) {
private static String repeat(char c, int count) {
char[] array = new char[count];
Arrays.fill(array, c);
return new String(array);
@ -2382,7 +2383,7 @@ public final class JsonReaderTest {
+ troubleshootingId);
}
private void assertDocument(String document, Object... expectations) throws IOException {
private static void assertDocument(String document, Object... expectations) throws IOException {
JsonReader reader = new JsonReader(reader(document));
reader.setStrictness(Strictness.LENIENT);
for (Object expectation : expectations) {
@ -2419,7 +2420,7 @@ public final class JsonReaderTest {
}
/** Returns a reader that returns one character at a time. */
private Reader reader(final String s) {
private static Reader reader(final String s) {
/* if (true) */ return new StringReader(s);
/* return new Reader() {
int position = 0;

View File

@ -19,6 +19,8 @@ package com.google.gson.metrics;
import com.google.caliper.runner.CaliperMain;
class NonUploadingCaliperRunner {
private NonUploadingCaliperRunner() {}
private static String[] concat(String first, String... others) {
if (others.length == 0) {
return new String[] {first};

View File

@ -32,6 +32,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import java.io.CharArrayReader;
import java.io.File;
import java.io.IOException;
@ -173,13 +174,12 @@ public final class ParseBenchmark {
private static class GsonStreamParser implements Parser {
@Override
public void parse(char[] data, Document document) throws Exception {
com.google.gson.stream.JsonReader jsonReader =
new com.google.gson.stream.JsonReader(new CharArrayReader(data));
JsonReader jsonReader = new JsonReader(new CharArrayReader(data));
readToken(jsonReader);
jsonReader.close();
}
private void readToken(com.google.gson.stream.JsonReader reader) throws IOException {
private static void readToken(JsonReader reader) throws IOException {
while (true) {
switch (reader.peek()) {
case BEGIN_ARRAY:
@ -211,8 +211,6 @@ public final class ParseBenchmark {
break;
case END_DOCUMENT:
return;
default:
throw new IllegalArgumentException("Unexpected token" + reader.peek());
}
}
}
@ -221,8 +219,7 @@ public final class ParseBenchmark {
private static class GsonSkipParser implements Parser {
@Override
public void parse(char[] data, Document document) throws Exception {
com.google.gson.stream.JsonReader jsonReader =
new com.google.gson.stream.JsonReader(new CharArrayReader(data));
JsonReader jsonReader = new JsonReader(new CharArrayReader(data));
jsonReader.skipValue();
jsonReader.close();
}
@ -309,6 +306,7 @@ public final class ParseBenchmark {
}
}
@SuppressWarnings("MemberName")
static class Tweet {
@JsonProperty String coordinates;
@JsonProperty boolean favorited;
@ -332,6 +330,7 @@ public final class ParseBenchmark {
@JsonProperty String in_reply_to_user_id_str;
}
@SuppressWarnings("MemberName")
static class User {
@JsonProperty String name;
@JsonProperty String profile_sidebar_border_color;

60
pom.xml
View File

@ -224,6 +224,66 @@
<arg>-Xplugin:ErrorProne
-XepExcludedPaths:.*/generated-test-sources/protobuf/.*
-Xep:NotJavadoc:OFF <!-- Triggered by local class. -->
<!-- Increase severity from 'suggestion' to 'warning' so that the user has to fix
found issues, and they are not overlooked
TODO: Does not work properly yet, see https://github.com/google/error-prone/issues/4206,
so for now have to manually set them to `:WARN` -->
-XepAllSuggestionsAsWarnings
<!-- Enable some experimental checks which are disabled by default
In case they cause issues or are unreliable turn them off by adding `:OFF`,
and add a comment mentioning why they were disabled -->
-Xep:AnnotationPosition <!-- required by style guide -->
-Xep:AssertFalse
-Xep:ClassName <!-- required by style guide -->
-Xep:ClassNamedLikeTypeParameter:WARN
-Xep:ComparisonContractViolated
-Xep:ConstantField:WARN <!-- required by style guide -->
-Xep:DepAnn
-Xep:DifferentNameButSame
-Xep:EmptyIf
-Xep:EqualsBrokenForNull
-Xep:ForEachIterable:WARN
-Xep:FunctionalInterfaceClash
-Xep:InitializeInline
-Xep:InterfaceWithOnlyStatics
-Xep:LambdaFunctionalInterface:WARN <!-- only relevant for test code at the moment, which uses Java 11 -->
-Xep:LongLiteralLowerCaseSuffix <!-- required by style guide -->
-Xep:MemberName <!-- required by style guide -->
-Xep:MissingBraces:WARN
-Xep:MissingDefault <!-- required by style guide -->
-Xep:MixedArrayDimensions:WARN <!-- required by style guide -->
-Xep:MultiVariableDeclaration:WARN <!-- required by style guide -->
-Xep:MultipleTopLevelClasses:WARN <!-- required by style guide -->
-Xep:NonCanonicalStaticMemberImport
-Xep:NonFinalStaticField
-Xep:PackageLocation:WARN
-Xep:PrimitiveArrayPassedToVarargsMethod
-Xep:PrivateConstructorForUtilityClass:WARN
-Xep:RemoveUnusedImports:WARN
-Xep:StatementSwitchToExpressionSwitch:OFF <!-- disabled: requires Java 14 -->
-Xep:StaticQualifiedUsingExpression <!-- required by style guide -->
-Xep:SwitchDefault:WARN
-Xep:SystemExitOutsideMain
-Xep:SystemOut
-Xep:TestExceptionChecker
-Xep:ThrowSpecificExceptions:OFF <!-- disabled: Gson has no proper exception hierarchy yet, see https://github.com/google/gson/issues/2359 -->
-Xep:TryFailRefactoring:OFF <!-- disabled: there are too many tests which violate this -->
-Xep:TypeParameterNaming:WARN <!-- required by style guide -->
-Xep:UnescapedEntity
-Xep:UngroupedOverloads:WARN <!-- required by style guide -->
-Xep:UnnecessarilyFullyQualified
-Xep:UnnecessarilyUsedValue
-Xep:UnnecessaryAnonymousClass:OFF <!-- disabled: requires Java 8 -->
-Xep:UnnecessaryBoxedVariable:WARN
-Xep:UnnecessaryDefaultInEnumSwitch
-Xep:UnnecessaryFinal:OFF <!-- disabled: requires Java 8 -->
-Xep:UnnecessaryStaticImport:WARN <!-- required by style guide -->
-Xep:UnusedException
-Xep:UrlInSee
-Xep:UseCorrectAssertInTests
-Xep:UseEnumSwitch:WARN
-Xep:WildcardImport:WARN <!-- required by style guide -->
-Xep:YodaCondition
</arg>
<!-- Enable all warnings, except for ones which cause issues when building with newer JDKs, see also
https://docs.oracle.com/en/java/javase/11/tools/javac.html -->

View File

@ -39,7 +39,6 @@ import com.google.protobuf.DynamicMessage;
import com.google.protobuf.Extension;
import com.google.protobuf.Message;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
@ -194,8 +193,7 @@ public class ProtoTypeAdapter implements JsonSerializer<Message>, JsonDeserializ
return new Builder(EnumSerialization.NAME, CaseFormat.LOWER_UNDERSCORE, CaseFormat.LOWER_CAMEL);
}
private static final com.google.protobuf.Descriptors.FieldDescriptor.Type ENUM_TYPE =
com.google.protobuf.Descriptors.FieldDescriptor.Type.ENUM;
private static final FieldDescriptor.Type ENUM_TYPE = FieldDescriptor.Type.ENUM;
private static final ConcurrentMap<String, ConcurrentMap<Class<?>, Method>> mapOfMapOfMethods =
new MapMaker().makeMap();
@ -263,69 +261,56 @@ public class ProtoTypeAdapter implements JsonSerializer<Message>, JsonDeserializ
throw new IllegalStateException("only generated messages are supported");
}
try {
// Invoke the ProtoClass.newBuilder() method
Message.Builder protoBuilder =
(Message.Builder) getCachedMethod(protoClass, "newBuilder").invoke(null);
// Invoke the ProtoClass.newBuilder() method
Message.Builder protoBuilder =
(Message.Builder) getCachedMethod(protoClass, "newBuilder").invoke(null);
Message defaultInstance =
(Message) getCachedMethod(protoClass, "getDefaultInstance").invoke(null);
Message defaultInstance =
(Message) getCachedMethod(protoClass, "getDefaultInstance").invoke(null);
Descriptor protoDescriptor =
(Descriptor) getCachedMethod(protoClass, "getDescriptor").invoke(null);
// Call setters on all of the available fields
for (FieldDescriptor fieldDescriptor : protoDescriptor.getFields()) {
String jsonFieldName =
getCustSerializedName(fieldDescriptor.getOptions(), fieldDescriptor.getName());
Descriptor protoDescriptor =
(Descriptor) getCachedMethod(protoClass, "getDescriptor").invoke(null);
// Call setters on all of the available fields
for (FieldDescriptor fieldDescriptor : protoDescriptor.getFields()) {
String jsonFieldName =
getCustSerializedName(fieldDescriptor.getOptions(), fieldDescriptor.getName());
JsonElement jsonElement = jsonObject.get(jsonFieldName);
if (jsonElement != null && !jsonElement.isJsonNull()) {
// Do not reuse jsonFieldName here, it might have a custom value
Object fieldValue;
if (fieldDescriptor.getType() == ENUM_TYPE) {
if (jsonElement.isJsonArray()) {
// Handling array
Collection<EnumValueDescriptor> enumCollection =
new ArrayList<>(jsonElement.getAsJsonArray().size());
for (JsonElement element : jsonElement.getAsJsonArray()) {
enumCollection.add(
findValueByNameAndExtension(fieldDescriptor.getEnumType(), element));
}
fieldValue = enumCollection;
} else {
// No array, just a plain value
fieldValue =
findValueByNameAndExtension(fieldDescriptor.getEnumType(), jsonElement);
JsonElement jsonElement = jsonObject.get(jsonFieldName);
if (jsonElement != null && !jsonElement.isJsonNull()) {
// Do not reuse jsonFieldName here, it might have a custom value
Object fieldValue;
if (fieldDescriptor.getType() == ENUM_TYPE) {
if (jsonElement.isJsonArray()) {
// Handling array
Collection<EnumValueDescriptor> enumCollection =
new ArrayList<>(jsonElement.getAsJsonArray().size());
for (JsonElement element : jsonElement.getAsJsonArray()) {
enumCollection.add(
findValueByNameAndExtension(fieldDescriptor.getEnumType(), element));
}
protoBuilder.setField(fieldDescriptor, fieldValue);
} else if (fieldDescriptor.isRepeated()) {
// If the type is an array, then we have to grab the type from the class.
// protobuf java field names are always lower camel case
String protoArrayFieldName =
protoFormat.to(CaseFormat.LOWER_CAMEL, fieldDescriptor.getName()) + "_";
Field protoArrayField = protoClass.getDeclaredField(protoArrayFieldName);
Type protoArrayFieldType = protoArrayField.getGenericType();
fieldValue = context.deserialize(jsonElement, protoArrayFieldType);
protoBuilder.setField(fieldDescriptor, fieldValue);
fieldValue = enumCollection;
} else {
Object field = defaultInstance.getField(fieldDescriptor);
fieldValue = context.deserialize(jsonElement, field.getClass());
protoBuilder.setField(fieldDescriptor, fieldValue);
// No array, just a plain value
fieldValue = findValueByNameAndExtension(fieldDescriptor.getEnumType(), jsonElement);
}
protoBuilder.setField(fieldDescriptor, fieldValue);
} else if (fieldDescriptor.isRepeated()) {
// If the type is an array, then we have to grab the type from the class.
// protobuf java field names are always lower camel case
String protoArrayFieldName =
protoFormat.to(CaseFormat.LOWER_CAMEL, fieldDescriptor.getName()) + "_";
Field protoArrayField = protoClass.getDeclaredField(protoArrayFieldName);
Type protoArrayFieldType = protoArrayField.getGenericType();
fieldValue = context.deserialize(jsonElement, protoArrayFieldType);
protoBuilder.setField(fieldDescriptor, fieldValue);
} else {
Object field = defaultInstance.getField(fieldDescriptor);
fieldValue = context.deserialize(jsonElement, field.getClass());
protoBuilder.setField(fieldDescriptor, fieldValue);
}
}
return protoBuilder.build();
} catch (SecurityException e) {
throw new JsonParseException(e);
} catch (NoSuchMethodException e) {
throw new JsonParseException(e);
} catch (IllegalArgumentException e) {
throw new JsonParseException(e);
} catch (IllegalAccessException e) {
throw new JsonParseException(e);
} catch (InvocationTargetException e) {
throw new JsonParseException(e);
}
return protoBuilder.build();
} catch (Exception e) {
throw new JsonParseException("Error while parsing proto", e);
}

View File

@ -8,6 +8,8 @@ import com.google.gson.stream.JsonWriter;
import java.io.IOException;
public class GenericClasses {
private GenericClasses() {}
static class GenericClass<T> {
@SerializedName("t")
T t;

View File

@ -15,6 +15,8 @@ import java.util.function.BiConsumer;
import java.util.function.Supplier;
public class Main {
private Main() {}
/**
* Main entrypoint, called by {@code ShrinkingIT.test()}.
*

View File

@ -10,6 +10,8 @@ import com.google.gson.GsonBuilder;
* therefore not matched by the default {@code gson.pro} rules.
*/
public class NoSerializedNameMain {
private NoSerializedNameMain() {}
static class TestClassNoArgsConstructor {
// Has a no-args default constructor.
public String s;

View File

@ -5,6 +5,8 @@ import java.util.function.BiConsumer;
import java.util.function.Supplier;
public class TestExecutor {
private TestExecutor() {}
/**
* Helper method for running individual tests. In case of an exception wraps it and includes the
* {@code name} of the test to make debugging issues with the obfuscated JARs a bit easier.