Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gson intrepret specific field as capitalized

I have a class with some fields, e.g.

public class Message {

    public Enum Type {
        TEXT,
        PICTURE;
    }

    private Type type;
    private String text;
    private int id;
}

Let's say I have a json like the following

[ { "id" : "1",
    "data" : "hello",
    "type" : "text",
  },
  { "id" : "2",
    "data" : "<someImageUrl>",
    "type" : "picture",
  },
]

I can easily deserialize it by calling

Gson gson = new Gson();
ArrayList<Message> messages = gson.fromJson(jsonResult, new TypeToken<List<Message>>() {}.getType());

Cool. Unfortunately, the Type field remains null, because of the casing difference between the json object and the defined instances in the enum. How can I alter gson's behaviour so that it will interpret json Type objects as capitalized.

Potential workaround I have thought of:

  • assign ordinal values to the enum type that will match what's given in the json (i.e. TEXT("text")
  • split the json result by the delimiting character "},"
  • replace all occurences of -someEnumType- with -SOMEENUMTYPE-

something like

public enum Type {
    TEXT("text"),
    PICTURE("picture");

    private final String value

    private MessageType(String value) {
        this.value = value;
    }

    public String getValue() {
        return value
    }
}
...

   String[] jsonResultSplit = StringUtils.split(jsonResult, "},") 
   for (String jsonMessage : jsonResultSplit) {
        for (MessageType messageType : MessageType.values()) {
            if (jsonMessage.contains("\"type:\" : \"" + messageType.getValue() + "\"")) {
                jsonMessage.replace(
                        "\"type:\" : \"" + messageType.getValue() + "\"",
                        "\"type:\" : \""
                                + StringUtils.capitalize(messageType.getValue() + "\""));
            }
        }
    }
    jsonResult = StringUtils.join(jsonResultSplit);
    Gson gson = new Gson();
    ArrayList<Message> messages = gson.fromJson(jsonResult, new TypeToken<List<Message>>() {}.getType());

However this seems kind of hacky, and the string will be split incorrectly if a message contains "}," or something.

like image 853
rperryng Avatar asked Mar 20 '14 18:03

rperryng


People also ask

Does GSON ignore transient fields?

By default, GSON excludes transient and static fields from the serialization/deserialization process.

Does GSON ignore extra fields?

As you can see, Gson will ignore the unknown fields and simply match the fields that it's able to.

Why does GSON parse an integer as a double?

It sees all kind of numbers as a single type. That the numbers are parsed as a Double is an implementation detail of the Gson library. When it encounters a JSON number, it defaults to parsing it as a Double .

What does GSON toJson do?

Gson is the main actor class of Google Gson library. It provides functionalities to convert Java objects to matching JSON constructs and vice versa. Gson is first constructed using GsonBuilder and then toJson(Object) or fromJson(String, Class) methods are used to read/write JSON constructs.


2 Answers

Simplest way is to use @SerializedName annotation for your Enum.

public Enum Type {
    @SerializedName("text")
    TEXT,

    @SerializedName("picture")
    PICTURE
}

@SerializedName can be used not only for capitalization but also to change name of your enums or variables, for example

public enum Gender {
    @SerializedName("boy")
    MALE,

    @SerializedName("girl")
    FEMALE
}

Reference

Also as @Sotirios suggested, you need to annotate text to map json key with your variable.

 @SerializedName("data")
 private String text;

You can now deserialize your json using Gson as earlier

Gson gson = new Gson();
ArrayList<Message> messages = gson.fromJson(jsonResult, new TypeToken<List<Message>>() {}.getType());

Hope this helps...

like image 61
Purushotham Avatar answered Sep 18 '22 22:09

Purushotham


You'll have to register your own TypeAdapter to do the conversion

Gson gson = new GsonBuilder().registerTypeAdapter(Type.class,
            new TypeAdapter<Type>() {

                @Override
                public void write(JsonWriter out, Type value)
                        throws IOException {
                    out.value(value.name().toLowerCase());
                }

                @Override
                public Type read(JsonReader in) throws IOException {
                    return Type.valueOf(in.nextString().toUpperCase());
                }
            }).create();

Note that you should also annotate

private String text;

with @SerializedName("data") as it doesn't match the JSON name.

"data" : "hello",
like image 27
Sotirios Delimanolis Avatar answered Sep 21 '22 22:09

Sotirios Delimanolis