Skip to content

Commit

Permalink
Verify that JsonTreeReader and JsonTreeWriter override all methods (#…
Browse files Browse the repository at this point in the history
…2181)

* Verify that JsonTreeReader and JsonTreeWriter override all methods

If those classes do not override one of the JsonReader or JsonWriter methods
the user might encounter an AssertionError.

* Address review feedback
  • Loading branch information
Marcono1234 committed Aug 23, 2022
1 parent 7f77ad4 commit 325f37c
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 2 deletions.
57 changes: 55 additions & 2 deletions gson/src/test/java/com/google/gson/common/MoreAsserts.java
Expand Up @@ -16,9 +16,13 @@

package com.google.gson.common;

import org.junit.Assert;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.junit.Assert;

/**
* Handy asserts that we wish were present in {@link Assert}
Expand Down Expand Up @@ -49,4 +53,53 @@ public static void assertEqualsAndHashCode(Object a, Object b) {
Assert.assertFalse(a.equals(null));
Assert.assertFalse(a.equals(new Object()));
}

private static boolean isProtectedOrPublic(Method method) {
int modifiers = method.getModifiers();
return Modifier.isProtected(modifiers) || Modifier.isPublic(modifiers);
}

private static String getMethodSignature(Method method) {
StringBuilder builder = new StringBuilder(method.getName());
builder.append('(');

String sep = "";
for (Class<?> paramType : method.getParameterTypes()) {
builder.append(sep).append(paramType.getName());
sep = ",";
}

builder.append(')');
return builder.toString();
}

/**
* Asserts that {@code subClass} overrides all protected and public methods declared by
* {@code baseClass} except for the ones whose signatures are in {@code ignoredMethods}.
*/
public static void assertOverridesMethods(Class<?> baseClass, Class<?> subClass, List<String> ignoredMethods) {
Set<String> requiredOverriddenMethods = new LinkedHashSet<>();
for (Method method : baseClass.getDeclaredMethods()) {
// Note: Do not filter out `final` methods; maybe they should not be `final` and subclass needs
// to override them
if (isProtectedOrPublic(method)) {
requiredOverriddenMethods.add(getMethodSignature(method));
}
}

for (Method method : subClass.getDeclaredMethods()) {
requiredOverriddenMethods.remove(getMethodSignature(method));
}

for (String ignoredMethod : ignoredMethods) {
boolean foundIgnored = requiredOverriddenMethods.remove(ignoredMethod);
if (!foundIgnored) {
throw new IllegalArgumentException("Method '" + ignoredMethod + "' does not exist or is already overridden");
}
}

if (!requiredOverriddenMethods.isEmpty()) {
Assert.fail(subClass.getSimpleName() + " must override these methods: " + requiredOverriddenMethods);
}
}
}
Expand Up @@ -19,9 +19,14 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.common.MoreAsserts;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.MalformedJsonException;
import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;

@SuppressWarnings("resource")
Expand Down Expand Up @@ -80,4 +85,14 @@ public JsonElement deepCopy() {
expected.getMessage());
}
}

/**
* {@link JsonTreeReader} effectively replaces the complete reading logic of {@link JsonReader} to
* read from a {@link JsonElement} instead of a {@link Reader}. Therefore all relevant methods of
* {@code JsonReader} must be overridden.
*/
public void testOverrides() {
List<String> ignoredMethods = Arrays.asList("setLenient(boolean)", "isLenient()");
MoreAsserts.assertOverridesMethods(JsonReader.class, JsonTreeReader.class, ignoredMethods);
}
}
Expand Up @@ -16,8 +16,14 @@

package com.google.gson.internal.bind;

import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.common.MoreAsserts;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;

@SuppressWarnings("resource")
Expand Down Expand Up @@ -243,4 +249,15 @@ public void testJsonValue() throws IOException {
} catch (UnsupportedOperationException expected) {
}
}

/**
* {@link JsonTreeWriter} effectively replaces the complete writing logic of {@link JsonWriter} to
* create a {@link JsonElement} tree instead of writing to a {@link Writer}. Therefore all relevant
* methods of {@code JsonWriter} must be overridden.
*/
public void testOverrides() {
List<String> ignoredMethods = Arrays.asList("setLenient(boolean)", "isLenient()", "setIndent(java.lang.String)",
"setHtmlSafe(boolean)", "isHtmlSafe()", "setSerializeNulls(boolean)", "getSerializeNulls()");
MoreAsserts.assertOverridesMethods(JsonWriter.class, JsonTreeWriter.class, ignoredMethods);
}
}

0 comments on commit 325f37c

Please sign in to comment.