Skip to content

Commit

Permalink
Java 8 follow-up changes (#2747)
Browse files Browse the repository at this point in the history
* Java 8 follow-up changes

* Fix Error Prone warnings

Note that for the `final` variable warnings, it seems some of those variables
were made `final` intentionally, without the compiler requiring it.
But for consistency I removed the `final` from them as well.

* Disable `UnnecessaryAnonymousClass` Error Prone pattern

Is disabled by default as well.

It seems what this pattern does is suggest to replace anonymous classes
stored in constants with a corresponding method (with the intention that
the developer then uses a method reference to that method). But it even
does this when the anonymous class implements a custom functional type,
and not a generic type such as `Function`.

For example it suggested to replace
```
private static final FieldNamingStrategy CUSTOM_FIELD_NAMING_STRATEGY =
  new FieldNamingStrategy() {
    @OverRide
    public String translateName(Field f) {
      return "foo";
    }
  };
```

with a method
```
private static String customFieldNamingStrategy(Field f) {
  return "foo";
}
```

Which is probably not that helpful, and might not actually increase
readability.

* Revert some changes for API not available yet in target Android version
  • Loading branch information
Marcono1234 authored Sep 24, 2024
1 parent 58eaac3 commit 0eb681b
Show file tree
Hide file tree
Showing 44 changed files with 188 additions and 146 deletions.
9 changes: 2 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ jobs:
name: "Build on JDK ${{ matrix.java }}"
strategy:
matrix:
java: [ 11, 17 ]
# Custom JDK 21 configuration
include:
- java: 21
# Disable Enforcer check which (intentionally) prevents using JDK 21 for building
extra-mvn-args: -Denforcer.fail=false
java: [ 11, 17, 21 ]
runs-on: ubuntu-latest

steps:
Expand All @@ -28,7 +23,7 @@ jobs:
cache: 'maven'
- name: Build with Maven
# This also runs javadoc:jar to detect any issues with the Javadoc generated during release
run: mvn --batch-mode --no-transfer-progress verify javadoc:jar ${{ matrix.extra-mvn-args || '' }}
run: mvn --batch-mode --no-transfer-progress verify javadoc:jar

native-image-test:
name: "GraalVM Native Image test"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Gson uses Maven to build the project:
mvn clean verify
```

JDK 11 or newer is required for building, JDK 17 is recommended. Newer JDKs are currently not supported for building (but are supported when _using_ Gson).
JDK 11 or newer is required for building, JDK 17 or 21 is recommended. Newer JDKs are currently not supported for building (but are supported when _using_ Gson).

### Contributing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public GraphAdapterBuilder() {
}

public GraphAdapterBuilder addType(Type type) {
final ObjectConstructor<?> objectConstructor = constructorConstructor.get(TypeToken.get(type));
ObjectConstructor<?> objectConstructor = constructorConstructor.get(TypeToken.get(type));
InstanceCreator<Object> instanceCreator =
new InstanceCreator<Object>() {
@Override
Expand Down Expand Up @@ -95,8 +95,8 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return null;
}

final TypeAdapter<T> typeAdapter = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
TypeAdapter<T> typeAdapter = gson.getDelegateAdapter(this, type);
TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,9 @@ public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
return null;
}

final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
final Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<>();
final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate = new LinkedHashMap<>();
TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
Map<String, TypeAdapter<?>> labelToDelegate = new LinkedHashMap<>();
Map<Class<?>, TypeAdapter<?>> subtypeToDelegate = new LinkedHashMap<>();
for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) {
TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue()));
labelToDelegate.put(entry.getKey(), delegate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public boolean equals(Object o) {
if (!(o instanceof Sandwich)) {
return false;
}
final Sandwich other = (Sandwich) o;
Sandwich other = (Sandwich) o;
if (this.bread == null ? other.bread != null : !this.bread.equals(other.bread)) {
return false;
}
Expand All @@ -115,7 +115,7 @@ public boolean equals(Object o) {
if (!(o instanceof MultipleSandwiches)) {
return false;
}
final MultipleSandwiches other = (MultipleSandwiches) o;
MultipleSandwiches other = (MultipleSandwiches) o;
if (this.sandwiches == null
? other.sandwiches != null
: !this.sandwiches.equals(other.sandwiches)) {
Expand Down
6 changes: 3 additions & 3 deletions gson/src/main/java/com/google/gson/Gson.java
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ public void write(JsonWriter out, Number value) throws IOException {
};
}

private static TypeAdapter<AtomicLong> atomicLongAdapter(final TypeAdapter<Number> longAdapter) {
private static TypeAdapter<AtomicLong> atomicLongAdapter(TypeAdapter<Number> longAdapter) {
return new TypeAdapter<AtomicLong>() {
@Override
public void write(JsonWriter out, AtomicLong value) throws IOException {
Expand All @@ -554,7 +554,7 @@ public AtomicLong read(JsonReader in) throws IOException {
}

private static TypeAdapter<AtomicLongArray> atomicLongArrayAdapter(
final TypeAdapter<Number> longAdapter) {
TypeAdapter<Number> longAdapter) {
return new TypeAdapter<AtomicLongArray>() {
@Override
public void write(JsonWriter out, AtomicLongArray value) throws IOException {
Expand Down Expand Up @@ -682,7 +682,7 @@ public <T> TypeAdapter<T> getAdapter(Class<T> type) {
* public int numReads = 0;
* public int numWrites = 0;
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
* final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
* TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
* return new TypeAdapter<T>() {
* public void write(JsonWriter out, T value) throws IOException {
* ++numWrites;
Expand Down
2 changes: 1 addition & 1 deletion gson/src/main/java/com/google/gson/TypeAdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
* }
*
* private <E> TypeAdapter<Multiset<E>> newMultisetAdapter(
* final TypeAdapter<E> elementAdapter) {
* TypeAdapter<E> elementAdapter) {
* return new TypeAdapter<Multiset<E>>() {
* public void write(JsonWriter out, Multiset<E> value) throws IOException {
* if (value == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ static String checkInstantiable(Class<?> c) {
}

public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
final Type type = typeToken.getType();
final Class<? super T> rawType = typeToken.getRawType();
Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType();

// first try an instance creator

@SuppressWarnings("unchecked") // types must agree
final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
if (typeCreator != null) {
return new ObjectConstructor<T>() {
@Override
Expand All @@ -113,7 +113,7 @@ public T construct() {

// Next try raw type match for instance creators
@SuppressWarnings("unchecked") // types must agree
final InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>) instanceCreators.get(rawType);
InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>) instanceCreators.get(rawType);
if (rawTypeCreator != null) {
return new ObjectConstructor<T>() {
@Override
Expand Down Expand Up @@ -145,7 +145,7 @@ public T construct() {

// Check whether type is instantiable; otherwise ReflectionAccessFilter recommendation
// of adjusting filter suggested below is irrelevant since it would not solve the problem
final String exceptionMessage = checkInstantiable(rawType);
String exceptionMessage = checkInstantiable(rawType);
if (exceptionMessage != null) {
return new ObjectConstructor<T>() {
@Override
Expand All @@ -161,7 +161,7 @@ public T construct() {
// finally try unsafe
return newUnsafeAllocator(rawType);
} else {
final String message =
String message =
"Unable to create instance of "
+ rawType
+ "; ReflectionAccessFilter does not permit using reflection or Unsafe. Register an"
Expand All @@ -181,7 +181,7 @@ public T construct() {
* constructor.
*/
private static <T> ObjectConstructor<T> newSpecialCollectionConstructor(
final Type type, Class<? super T> rawType) {
Type type, Class<? super T> rawType) {
if (EnumSet.class.isAssignableFrom(rawType)) {
return new ObjectConstructor<T>() {
@Override
Expand Down Expand Up @@ -233,7 +233,7 @@ private static <T> ObjectConstructor<T> newDefaultConstructor(
return null;
}

final Constructor<? super T> constructor;
Constructor<? super T> constructor;
try {
constructor = rawType.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
Expand All @@ -249,7 +249,7 @@ private static <T> ObjectConstructor<T> newDefaultConstructor(
|| Modifier.isPublic(constructor.getModifiers())));

if (!canAccess) {
final String message =
String message =
"Unable to invoke no-args constructor of "
+ rawType
+ ";"
Expand All @@ -267,7 +267,7 @@ public T construct() {
// Only try to make accessible if allowed; in all other cases checks above should
// have verified that constructor is accessible
if (filterResult == FilterResult.ALLOW) {
final String exceptionMessage = ReflectionHelper.tryMakeAccessible(constructor);
String exceptionMessage = ReflectionHelper.tryMakeAccessible(constructor);
if (exceptionMessage != null) {
/*
* Create ObjectConstructor which throws exception.
Expand Down Expand Up @@ -323,7 +323,7 @@ public T construct() {
/** Constructors for common interface types like Map and List and their subtypes. */
@SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is
private static <T> ObjectConstructor<T> newDefaultImplementationConstructor(
final Type type, Class<? super T> rawType) {
Type type, Class<? super T> rawType) {

/*
* IMPORTANT: Must only create instances for classes with public no-args constructor.
Expand Down Expand Up @@ -409,7 +409,7 @@ public T construct() {
return null;
}

private <T> ObjectConstructor<T> newUnsafeAllocator(final Class<? super T> rawType) {
private <T> ObjectConstructor<T> newUnsafeAllocator(Class<? super T> rawType) {
if (useJdkUnsafe) {
return new ObjectConstructor<T>() {
@Override
Expand Down Expand Up @@ -444,8 +444,8 @@ public T construct() {
" Or adjust your R8 configuration to keep the no-args constructor of the class.";
}

// Explicit final variable to allow usage in the anonymous class below
final String exceptionMessageF = exceptionMessage;
// Separate effectively final variable to allow usage in the anonymous class below
String exceptionMessageF = exceptionMessage;

return new ObjectConstructor<T>() {
@Override
Expand Down
6 changes: 3 additions & 3 deletions gson/src/main/java/com/google/gson/internal/Excluder.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ public Excluder withExclusionStrategy(
}

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

final boolean skipSerialize = excludeClass(rawType, true);
final boolean skipDeserialize = excludeClass(rawType, false);
boolean skipSerialize = excludeClass(rawType, true);
boolean skipDeserialize = excludeClass(rawType, false);

if (!skipSerialize && !skipDeserialize) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,6 @@ public int hashCode() {
return delegate.hashCode();
}

// TODO: Once Gson targets Java 8 also override List.sort
// Maybe also delegate List#sort and List#spliterator in the future, but that
// requires Android API level 24
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private abstract static class AccessChecker {
// TODO: Ideally should use Multi-Release JAR for this version specific code
if (JavaVersion.isJava9OrLater()) {
try {
final Method canAccessMethod =
Method canAccessMethod =
AccessibleObject.class.getDeclaredMethod("canAccess", Object.class);
accessChecker =
new AccessChecker() {
Expand Down
10 changes: 5 additions & 5 deletions gson/src/main/java/com/google/gson/internal/UnsafeAllocator.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ private static UnsafeAllocator create() {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field f = unsafeClass.getDeclaredField("theUnsafe");
f.setAccessible(true);
final Object unsafe = f.get(null);
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
Object unsafe = f.get(null);
Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
return new UnsafeAllocator() {
@Override
@SuppressWarnings("unchecked")
Expand All @@ -77,8 +77,8 @@ public <T> T newInstance(Class<T> c) throws Exception {
Method getConstructorId =
ObjectStreamClass.class.getDeclaredMethod("getConstructorId", Class.class);
getConstructorId.setAccessible(true);
final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
final Method newInstance =
int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
Method newInstance =
ObjectStreamClass.class.getDeclaredMethod("newInstance", Class.class, int.class);
newInstance.setAccessible(true);
return new UnsafeAllocator() {
Expand All @@ -99,7 +99,7 @@ public <T> T newInstance(Class<T> c) throws Exception {
// Class<?> instantiationClass, Class<?> constructorClass);
// }
try {
final Method newInstance =
Method newInstance =
ObjectInputStream.class.getDeclaredMethod("newInstance", Class.class, Class.class);
newInstance.setAccessible(true);
return new UnsafeAllocator() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
private final Map<String, T> stringToConstant = new HashMap<>();
private final Map<T, String> constantToName = new HashMap<>();

private EnumTypeAdapter(final Class<T> classOfT) {
private EnumTypeAdapter(Class<T> classOfT) {
try {
// Uses reflection to find enum constants to work around name mismatches for obfuscated
// classes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,14 @@ public int nextInt() throws IOException {
}

JsonElement nextJsonElement() throws IOException {
final JsonToken peeked = peek();
JsonToken peeked = peek();
if (peeked == JsonToken.NAME
|| peeked == JsonToken.END_ARRAY
|| peeked == JsonToken.END_OBJECT
|| peeked == JsonToken.END_DOCUMENT) {
throw new IllegalStateException("Unexpected " + peeked + " when reading a JsonElement.");
}
final JsonElement element = (JsonElement) peekStack();
JsonElement element = (JsonElement) peekStack();
skipValue();
return element;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private NumberTypeAdapter(ToNumberStrategy toNumberStrategy) {
}

private static TypeAdapterFactory newFactory(ToNumberStrategy toNumberStrategy) {
final NumberTypeAdapter adapter = new NumberTypeAdapter(toNumberStrategy);
NumberTypeAdapter adapter = new NumberTypeAdapter(toNumberStrategy);
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked")
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private ObjectTypeAdapter(Gson gson, ToNumberStrategy toNumberStrategy) {
this.toNumberStrategy = toNumberStrategy;
}

private static TypeAdapterFactory newFactory(final ToNumberStrategy toNumberStrategy) {
private static TypeAdapterFactory newFactory(ToNumberStrategy toNumberStrategy) {
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked")
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private List<String> getFieldNames(Field f) {
}

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

if (!Object.class.isAssignableFrom(raw)) {
Expand Down Expand Up @@ -175,18 +175,18 @@ private static <M extends AccessibleObject & Member> void checkAccessible(
}

private BoundField createBoundField(
final Gson context,
final Field field,
final Method accessor,
final String serializedName,
final TypeToken<?> fieldType,
final boolean serialize,
final boolean blockInaccessible) {
Gson context,
Field field,
Method accessor,
String serializedName,
TypeToken<?> fieldType,
boolean serialize,
boolean blockInaccessible) {

final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());

int modifiers = field.getModifiers();
final boolean isStaticFinalField = Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers);
boolean isStaticFinalField = Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers);

JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
TypeAdapter<?> mapped = null;
Expand All @@ -196,14 +196,14 @@ private BoundField createBoundField(
jsonAdapterFactory.getTypeAdapter(
constructorConstructor, context, fieldType, annotation, false);
}
final boolean jsonAdapterPresent = mapped != null;
boolean jsonAdapterPresent = mapped != null;
if (mapped == null) {
mapped = context.getAdapter(fieldType);
}

@SuppressWarnings("unchecked")
final TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) mapped;
final TypeAdapter<Object> writeTypeAdapter;
TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) mapped;
TypeAdapter<Object> writeTypeAdapter;
if (serialize) {
writeTypeAdapter =
jsonAdapterPresent
Expand Down
Loading

0 comments on commit 0eb681b

Please sign in to comment.