问题
I want to create the following json from my model
either i have
{"name" : "Arsénio", "value" : 12}
or
{"name" : "Arsénio", "value" : {"min" : 12, "max" : 100, "value" : 200}}
I've defined the following POJO's
class Data {
String name;
Value value;
}
abstract class Value {}
class IntegerValue : Value {
int value;
}
class RangeValue : Value {
int max, min, value;
}
Obviously this won't output my required json for the first case when using IntegerValue since it will output
Gson gson = new Gson();
Data data = new Data();
data.name = "Arsénio";
data.value = new IntegerValue();
data.value.value = 12;
String result = gson.toJson(data, Data.class);
System.out.println(result);
Output:
{"name": "Arsénio", "value" : {"value" : 12}}
Whats the correct way to model my POJO's in this case ?
回答1:
I have managed to solve by using an type adapter for the IntegerValue not sure if this is the correct and simpler solution so i will wait a while before accept my own answer.
Gson gson = new GsonBuilder()
.registerTypeAdapter(IntValue.class, new IntegerValueTypeAdapter())
.create();
public class IntValueTypeAdapter extends TypeAdapter<IntegerValue> {
@Override
public void write(JsonWriter out, IntegerValue value) throws IOException {
out.value(value.value);
}
@Override
public IntegerValue read(JsonReader in) throws IOException {
// do something similar, but the other way around
throw new UnsupportedOperationException("deserialize not supported for IntegerValue");
}
}
回答2:
You can write a custom TypeAdapter:
public class ValueTypeAdapter extends TypeAdapter<Value> {
@Override
public Value read(JsonReader in) throws IOException {
Value value = null;
JsonParser jsonParser = new JsonParser();
JsonElement je = jsonParser.parse(in);
if (je instanceof JsonPrimitive) {
value = new Value();
value.value = ((JsonPrimitive) je).getAsInt();
} else if (je instanceof JsonObject) {
JsonObject jsonObject = (JsonObject) je;
value = new Value();
value.max = jsonObject.get("max").getAsInt();
value.min = jsonObject.get("min").getAsInt();
value.value = jsonObject.get("value").getAsInt();
}
return value;
}
@Override
public void write(JsonWriter out, Value value) throws IOException {
if (value != null) {
if (value.min == 0 && value.max == 0) {
out.value(value.value);
} else {
out.beginObject();
out.name("min").value(value.min);
out.name("max").value(value.max);
out.name("value").value(value.value);
out.endObject();
}
}
}
}
Your POJO Classes:
public static class Data {
String name;
Value value;
}
public static class Value {
int max, min, value;
}
Test:
String json0 = "{\"name\" : \"Arsénio\", \"value\" : 12}";
String json1 = "{\"name\" : \"Arsénio\", \"value\" : {\"min\" : 12, \"max\" : 100, \"value\" : 200}}";
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Value.class, new ValueTypeAdapter());
Gson gson = gsonBuilder.create();
// 1) Deserialize json to java instances
Data data0 = gson.fromJson(json0, Data.class);
Data data1 = gson.fromJson(json1, Data.class);
// 2) Serialize json to java instances to see your incoming json string equals to seriallize one
String serialized0 = gson.toJson(data0);
String serialized1 = gson.toJson(data1);
System.out.println("serialized0:" + serialized0);
System.out.println("serialized1:" + serialized1);
来源:https://stackoverflow.com/questions/26761541/gson-property-allow-primitive-or-composite-mapping