3

I need GSON mapper to throw an exception if json contains unknown fields. For example if we have POJO like

public class MyClass {
    String name;
}

and json like

{
    "name": "John",
    "age": 30
}

I want to get some sort of message that json contains unknown field (age) that can not be deserialized.

I know there is out-of-box solution in Jackson mapper, but in our project we have been using Gson as a mapper for several years and using Jackson ends up in conflicts and bugs in different parts of project, so it is easier for me to write my own solution than using Jackson.

In other words, I want to know if there is some equivalent to Jackson's DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES in Gson. Or maybe if it can be done using Gson's DeserializationStrategy other than using reflections

Grokify
  • 15,092
  • 6
  • 60
  • 81
harald
  • 31
  • 1
  • 3
  • It's not supported because no one care for about eleven years https://github.com/google/gson/issues/188 . It cannot be hacked delegating a JsonReader proxy because it requires a `Reader` instance and holds massive state. It also cannot be hacked extending `JsonElement` because some type adapters use `instanceof` instead of using public methods `JsonElement.isXXX()`. – terrorrussia-keeps-killing Dec 08 '20 at 19:47
  • However, you can probably make it work using reflection heavily over ReflectiveTypeAdapterFactory.Adapter and its related classes if you want to retain the original Gson behavior. Or, simply implement a custom type adapter but in this case you may lose the original Gson implementation details like `@SerializedName` support, empty object constructors (unsafe, not even using default ones), etc. – terrorrussia-keeps-killing Dec 08 '20 at 19:48
  • @fluffy thank you for answer! I will have to implement a workaround then I guess. – harald Dec 09 '20 at 14:09

1 Answers1

1

I believe you cannot do it automatically with Gson.

I had to do this in a project at work. I did the following:

Gson GSON = new GsonBuilder().create();
(static final) Map<String, Field> FIELDS = Arrays.stream(MyClass.class.getDeclaredFields())
    .collect(Collectors.toMap(Field::getName, Function.identity()));

JsonObject object = (JsonObject) GSON.fromJson(json, JsonObject.class);

List<String> objectProperties = object.entrySet().stream().map(Entry::getKey).collect(Collectors.toList());
List<String> classFieldNames = new ArrayList<>(FIELDS.keySet());

if (!classFieldNames.containsAll(objectProperties)) {
    List<String> invalidProperties = new ArrayList<>(objectProperties);
    invalidProperties.removeAll(classFieldNames);
    throw new RuntimeException("Invalid fields: " + invalidProperties);
}
Bonnev
  • 947
  • 2
  • 9
  • 29