rharter / auto-value-gson

AutoValue Extension to add Gson De/Serializer support
Apache License 2.0
603 stars 103 forks source link

Handling unrecognized json properties #266

Closed VysotskiVadim closed 2 years ago

VysotskiVadim commented 2 years ago

The problem

I want to process a json file, for example:

{
    "a": "a",
    "b": "b"
}

having a model which isn't aware of all the properties from the json file, for example:

@AutoValue
public class Model {

  public abstract String a();

  public abstract Builder toBuilder();

  public static Builder builder() {
    return new AutoValue_Model.Builder();
  }

  public static TypeAdapter<Model> typeAdapter(Gson gson) {
    return new AutoValue_Model.GsonTypeAdapter(gson);
  }

  @AutoValue.Builder
  public class Builder {
     public abstract Builder a(String value);
     public abstract Model build();
  }

}

but when I serialize the model back to json after processing I want the unrecognized property b to be present in json.

For example, when I deserialize, update property a to a value "c", and serialize json back I want the following output:

{
    "a": "c",
    "b": "b"
}

Desired behaviour in code

String json = "{\"a\": \"a\", \"b\": \"b\"}"; // the same source JSON as in the example ☝️ 
// serializing json to Model
GsonBuilder gson = new GsonBuilder();
JsonObject jsonObject = gson.create().fromJson(json, JsonObject.class);
gson.registerTypeAdapterFactory(GeneratedAdaptersFactory.create());
Model model = gson.create().fromJson(jsonObject, Model.class);
// updating the model
Model updatedModel = model.toBuilder().a("c").build();
// deserializing back to json
String outputJson =  gson.create().toJson(updatedModel);

assertEquals( "{\"a\": \"c\", \"b\": \"b\"}", outputJson);

Idea of it can work

I can manually add an unrecognized property to the model:

@AutoValue
public class Model {

  public abstract String a();

  abstract Map<String, Object> unrecognized();

  public abstract Builder toBuilder();

  public static Builder builder() {
    return new AutoValue_Model.Builder();
  }

  public static TypeAdapter<Model> typeAdapter(Gson gson) {
    return new AutoValue_Model.GsonTypeAdapter(gson);
  }

  @AutoValue.Builder
  public class Builder {
     public abstract Builder a(String value);
     abstract Builder unrecognized(Map<String, Object> value);
     public abstract Model build();
  }

}

If the generated type adapters were aware of the unrecognized property and put all the unrecognized fields from a parsed json there during reading, and wrote unrecognized properties from back to json file during writing I would get desired behavior.

Help is needed

What do you think about such a feature? Maybe the library already has something similar but I didn't find this feature? Would you like to have this feature in your library? Are you ready to accept a PR to the library with this feature? Can you give any recommendations about implementation(even if you don't want this feature in the lib I will appreciate your advice)?

ZacSweers commented 2 years ago

I don't think this library is the right place for that. It would be a significant performance impact and extremely special cases. You should write your own system for this