Skip to content

Commit

Permalink
Fix formatting and fix switched 'expected' and 'actual' in EnumTest
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcono1234 committed Nov 19, 2023
1 parent ad97501 commit af1a800
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 65 deletions.
42 changes: 23 additions & 19 deletions gson/src/main/java/com/google/gson/internal/Excluder.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@
import java.util.List;

/**
* This class selects which fields and types to omit. It is configurable,
* supporting version attributes {@link Since} and {@link Until}, modifiers,
* synthetic fields, anonymous and local classes, inner classes, and fields with
* the {@link Expose} annotation.
* This class selects which fields and types to omit. It is configurable, supporting version
* attributes {@link Since} and {@link Until}, modifiers, synthetic fields, anonymous and local
* classes, inner classes, and fields with the {@link Expose} annotation.
*
* <p>This class is a type adapter factory; types that are excluded will be
* adapted to null. It may delegate to another type adapter if only one
* direction is excluded.
* <p>This class is a type adapter factory; types that are excluded will be adapted to null. It may
* delegate to another type adapter if only one direction is excluded.
*
* @author Joel Leitch
* @author Jesse Wilson
Expand All @@ -59,7 +57,8 @@ public final class Excluder implements TypeAdapterFactory, Cloneable {
private List<ExclusionStrategy> serializationStrategies = Collections.emptyList();
private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList();

@Override protected Excluder clone() {
@Override
protected Excluder clone() {
try {
return (Excluder) super.clone();
} catch (CloneNotSupportedException e) {
Expand Down Expand Up @@ -94,8 +93,8 @@ public Excluder excludeFieldsWithoutExposeAnnotation() {
return result;
}

public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
boolean serialization, boolean deserialization) {
public Excluder withExclusionStrategy(
ExclusionStrategy exclusionStrategy, boolean serialization, boolean deserialization) {
Excluder result = clone();
if (serialization) {
result.serializationStrategies = new ArrayList<>(serializationStrategies);
Expand All @@ -108,7 +107,8 @@ public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
return result;
}

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

final boolean skipSerialize = excludeClass(rawType, true);
Expand All @@ -125,15 +125,17 @@ public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
*/
private volatile TypeAdapter<T> delegate;

@Override public T read(JsonReader in) throws IOException {
@Override
public T read(JsonReader in) throws IOException {
if (skipDeserialize) {
in.skipValue();
return null;
}
return delegate().read(in);
}

@Override public void write(JsonWriter out, T value) throws IOException {
@Override
public void write(JsonWriter out, T value) throws IOException {
if (skipSerialize) {
out.nullValue();
return;
Expand All @@ -142,11 +144,10 @@ public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
}

private TypeAdapter<T> delegate() {
// A race might lead to `delegate` being assigned by multiple threads but the last assignment will stick
// A race might lead to `delegate` being assigned by multiple threads but the last
// assignment will stick
TypeAdapter<T> d = delegate;
return d != null
? d
: (delegate = gson.getDelegateAdapter(Excluder.this, type));
return d != null ? d : (delegate = gson.getDelegateAdapter(Excluder.this, type));
}
};
}
Expand Down Expand Up @@ -191,7 +192,8 @@ public boolean excludeField(Field field, boolean serialize) {

// public for unit tests; can otherwise be private
public boolean excludeClass(Class<?> clazz, boolean serialize) {
if (version != Excluder.IGNORE_VERSIONS && !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
if (version != Excluder.IGNORE_VERSIONS
&& !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
return true;
}

Expand All @@ -211,7 +213,9 @@ public boolean excludeClass(Class<?> clazz, boolean serialize) {
* fall back to creating instances using Unsafe, which would likely lead to runtime exceptions
* for anonymous and local classes if they capture values.
*/
if (!serialize && !Enum.class.isAssignableFrom(clazz) && ReflectionHelper.isAnonymousOrNonStaticLocal(clazz)) {
if (!serialize
&& !Enum.class.isAssignableFrom(clazz)
&& ReflectionHelper.isAnonymousOrNonStaticLocal(clazz)) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
// captured enclosing values make this unreliable
if (ReflectionHelper.isAnonymousOrNonStaticLocal(raw)) {
// This adapter just serializes and deserializes null, ignoring the actual values
// This is done for backward compatibility; troubleshooting-wise it might be better to throw exceptions
// This is done for backward compatibility; troubleshooting-wise it might be better to throw
// exceptions
return new TypeAdapter<T>() {
@Override
public T read(JsonReader in) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,7 @@ public static boolean isStatic(Class<?> clazz) {
return (clazz.getModifiers() & Modifier.STATIC) != 0;
}

/**
* Returns whether the class is anonymous or a non-static local class.
*/
/** Returns whether the class is anonymous or a non-static local class. */
public static boolean isAnonymousOrNonStaticLocal(Class<?> clazz) {
return !isStatic(clazz) && (clazz.isAnonymousClass() || clazz.isLocalClass());
}
Expand Down
13 changes: 7 additions & 6 deletions gson/src/test/java/com/google/gson/functional/EnumTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,12 @@ public void testEnumSubclass() {
assertThat(gson.toJson(EnumSet.allOf(Roshambo.class)))
.isEqualTo("[\"ROCK\",\"PAPER\",\"SCISSORS\"]");
assertThat(gson.fromJson("\"ROCK\"", Roshambo.class)).isEqualTo(Roshambo.ROCK);
assertThat(EnumSet.allOf(Roshambo.class))
.isEqualTo(
gson.fromJson(
"[\"ROCK\",\"PAPER\",\"SCISSORS\"]", new TypeToken<Set<Roshambo>>() {}.getType()));
Set<Roshambo> deserialized =
gson.fromJson("[\"ROCK\",\"PAPER\",\"SCISSORS\"]", new TypeToken<>() {});
assertThat(deserialized).isEqualTo(EnumSet.allOf(Roshambo.class));

// A bit contrived, but should also work if explicitly deserializing using anonymous enum subclass
// A bit contrived, but should also work if explicitly deserializing using anonymous enum
// subclass
assertThat(gson.fromJson("\"ROCK\"", Roshambo.ROCK.getClass())).isEqualTo(Roshambo.ROCK);
}

Expand All @@ -148,7 +148,8 @@ public void testEnumSubclassWithRegisteredTypeAdapter() {
assertThat(gson.toJson(EnumSet.allOf(Roshambo.class)))
.isEqualTo("[\"123ROCK\",\"123PAPER\",\"123SCISSORS\"]");
assertThat(gson.fromJson("\"123ROCK\"", Roshambo.class)).isEqualTo(Roshambo.ROCK);
Set<Roshambo> deserialized = gson.fromJson("[\"123ROCK\",\"123PAPER\",\"123SCISSORS\"]", new TypeToken<Set<Roshambo>>() {}.getType());
Set<Roshambo> deserialized =
gson.fromJson("[\"123ROCK\",\"123PAPER\",\"123SCISSORS\"]", new TypeToken<>() {});
assertThat(deserialized).isEqualTo(EnumSet.allOf(Roshambo.class));
}

Expand Down
91 changes: 55 additions & 36 deletions gson/src/test/java/com/google/gson/functional/ObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -391,56 +391,75 @@ class Local {}

@Test
public void testAnonymousLocalClassesCustomSerialization() {
Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(ClassWithNoFields.class,
new JsonSerializer<ClassWithNoFields>() {
@Override
public JsonElement serialize(ClassWithNoFields src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive("custom-value");
}
}).create();

assertThat(gson.toJson(new ClassWithNoFields() {
// empty anonymous class
})).isEqualTo("\"custom-value\"");
Gson gson =
new GsonBuilder()
.registerTypeHierarchyAdapter(
ClassWithNoFields.class,
new JsonSerializer<ClassWithNoFields>() {
@Override
public JsonElement serialize(
ClassWithNoFields src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive("custom-value");
}
})
.create();

assertThat(
gson.toJson(
new ClassWithNoFields() {
// empty anonymous class
}))
.isEqualTo("\"custom-value\"");

class Local {}
gson = new GsonBuilder()
.registerTypeAdapter(Local.class,
new JsonSerializer<Local>() {
@Override
public JsonElement serialize(Local src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive("custom-value");
}
}).create();
gson =
new GsonBuilder()
.registerTypeAdapter(
Local.class,
new JsonSerializer<Local>() {
@Override
public JsonElement serialize(
Local src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive("custom-value");
}
})
.create();
assertThat(gson.toJson(new Local())).isEqualTo("\"custom-value\"");
}

@Test
public void testAnonymousLocalClassesCustomDeserialization() {
Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(ClassWithNoFields.class,
new JsonDeserializer<ClassWithNoFields>() {
@Override
public ClassWithNoFields deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
return new ClassWithNoFields();
}
}).create();
Gson gson =
new GsonBuilder()
.registerTypeHierarchyAdapter(
ClassWithNoFields.class,
new JsonDeserializer<ClassWithNoFields>() {
@Override
public ClassWithNoFields deserialize(
JsonElement json, Type typeOfT, JsonDeserializationContext context) {
return new ClassWithNoFields();
}
})
.create();

assertThat(gson.fromJson("{}", ClassWithNoFields.class)).isNotNull();
Class<?> anonymousClass = new ClassWithNoFields() {}.getClass();
// Custom deserializer is ignored
assertThat(gson.fromJson("{}", anonymousClass)).isNull();

class Local {}
gson = new GsonBuilder()
.registerTypeAdapter(Local.class,
new JsonDeserializer<Local>() {
@Override
public Local deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
throw new AssertionError("should not be called");
}
}).create();
gson =
new GsonBuilder()
.registerTypeAdapter(
Local.class,
new JsonDeserializer<Local>() {
@Override
public Local deserialize(
JsonElement json, Type typeOfT, JsonDeserializationContext context) {
throw new AssertionError("should not be called");
}
})
.create();
// Custom deserializer is ignored
assertThat(gson.fromJson("{}", Local.class)).isNull();
}
Expand Down

0 comments on commit af1a800

Please sign in to comment.