Search code examples
androidgsonretrofit2

Class with two fields with same SerializedName


I have a problem with my services because the same field is different form in request and response, whereby I use @Expose annotation to serialize one and deserialize another:

@SerializedName("photo")
@Expose(deserialize = false)
private String imageB64;

@SerializedName("photo")
@Expose(serialize = false)
private ImageURL imageURL;

But in the response, my service is launching an exception:

Caused by: java.lang.IllegalArgumentException: class User declares multiple JSON fields named photo

I'm using Retrofit with GSON converter.

Thanks for your help!


Solution

  • I don't think it's possible to add multiple @SerializedName annotations, because otherwise you'll get the error you provided.

    However, you can create a custom TypeAdapter to manually hand serialization/deserialization of your object, like that:

    MyObject

    public class MyObject {
    
      private String url;
    
      private int number;
    
      // constructor + getters + setters + custom "toString()"
      ...
    
    }
    

    MyObjectTypeAdapter

    class MyObjectTypeAdapter extends TypeAdapter<MyObject> {
    
      @Override
      public void write(JsonWriter out, MyObject value) throws IOException {
        out.beginObject().name("photo").value(value.getUrl()).endObject();
      }
    
      @Override
      public MyObject read(JsonReader in) throws IOException {
        MyObject result = new MyObject();
        in.beginObject();
        while (in.hasNext()) {
          switch (in.nextName()) {
          case "photo":
            result.setNumber(in.nextInt());
          }
          // other fields
          ...
        }
    
        in.endObject();
        return result;
      }
    }
    

    You can use it in this way:

    public static void main(String[] args) {
      Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyObjectTypeAdapter()).create();
    
      System.out.println(gson.toJson(new MyObject("myUrl", 1)));
    
      MyObject deserialized = gson.fromJson("{ \"photo\": 12 }", MyObject.class);
    
      System.out.println(deserialized);
    }
    

    and it prints (note I used a custom toString() for MyObject):

    {"photo":"myUrl"}
    MyObject{url='null', number=12}