类型安全和正确的数据绑定是您的朋友。 Gson 有几种方法可以完成您需要的工作。比如声明数据传输对象:
final class GraphiteDataset {
final String target;
// The incoming DTO has property `datapoints`, however Java conventions suggest dataPoints (as far as I understand English).
@SerializedName("datapoints")
final List<GraphiteDataPoint> dataPoints;
// Actually, Gson does not need this constructor, and the DTO can even have a single private default one.
// But in order to make it consistent with the next class just making it programmatically instantiable...
// Also, but may be opinion-based, hiding constructors is really a good idea since one can hide the instantiation strategy whilst constructors cannot.
private GraphiteDataset(final String target, final List<GraphiteDataPoint> dataPoints) {
this.target = target;
this.dataPoints = dataPoints;
}
}
final class GraphiteDataPoint {
final double value;
final long timestamp;
private GraphiteDataPoint(final double value, final long timestamp) {
this.value = value;
this.timestamp = timestamp;
}
// Instantiation must be accessible programmatically somehow
static GraphiteDataPoint graphiteDataPoint(final double value, final long timestamp) {
return new GraphiteDataPoint(value, timestamp);
}
}
然后实现一个 GraphiteDataPoint JSON 反序列化器:
// In Gson serializers and deserializers can only deal with intermediate Gson JSON tree representation of objects (JsonElement-s).
// For some cases it's quite simple, if the given data to serialize/deserialize does not consume much memory
final class GraphiteDataPointJsonDeserializer
implements JsonDeserializer<GraphiteDataPoint> {
private static final JsonDeserializer<GraphiteDataPoint> graphiteDataPointJsonDeserializer = new GraphiteDataPointJsonDeserializer();
private GraphiteDataPointJsonDeserializer() {
}
// Not letting to instantiate a stateless (so it's thread-safe) deserializer twice or more
static JsonDeserializer<GraphiteDataPoint> getGraphiteDataPointJsonDeserializer() {
return graphiteDataPointJsonDeserializer;
}
@Override
public GraphiteDataPoint deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final JsonArray asJsonArray = jsonElement.getAsJsonArray();
final double value = asJsonArray.get(0).getAsJsonPrimitive().getAsDouble();
final long timestamp = asJsonArray.get(1).getAsJsonPrimitive().getAsLong();
return graphiteDataPoint(value, timestamp);
}
}
或类型适配器:
// Type adapters, unlike serializers and deserializers, are designed to work with streams.
// They may look too low-level and tedious/hard to implement, but for some cases they can be useful in both serialization and deserialization.
// For the case #1: no need to serialize nested objects recursively to transform them to JSON trees that can be important for large objects.
// For the case #2: intermediate JSON trees are not necessary (but internal buffers are).
final class GraphiteDataPointTypeAdapter
extends TypeAdapter<GraphiteDataPoint> {
private static final TypeAdapter<GraphiteDataPoint> graphiteDataPointTypeAdapter = new GraphiteDataPointTypeAdapter();
private GraphiteDataPointTypeAdapter() {
}
static TypeAdapter<GraphiteDataPoint> getGraphiteDataPointTypeAdapter() {
return graphiteDataPointTypeAdapter;
}
@Override
public void write(final JsonWriter out, final GraphiteDataPoint value) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public GraphiteDataPoint read(final JsonReader in)
throws IOException {
in.beginArray();
final double value = in.nextDouble();
final long timestamp = in.nextLong();
in.endArray();
return graphiteDataPoint(value, timestamp);
}
}
两种实现方式基本相同,但可能对您依赖数据(反)序列化策略和成本至关重要。使用示例:
private static final String JSON = "[{\"target\":\"entries\",\"datapoints\":[[1.0,1311836008],[2.0,1311836009],[3.0,1311836010],[5.0,1311836011],[6.0,1311836012]]}]";
// Gson is thread-safe and can be shared between threads, so no need to instantiate it every time it's needed
private static final Gson gsonWithDeserializers = new GsonBuilder()
.registerTypeAdapter(GraphiteDataPoint.class, getGraphiteDataPointJsonDeserializer())
.create();
private static final Gson gsonWithTypeAdapters = new GsonBuilder()
.registerTypeAdapter(GraphiteDataPoint.class, getGraphiteDataPointTypeAdapter())
.create();
private static final TypeToken<List<GraphiteDataset>> graphiteDatasetsTypeToken = new TypeToken<List<GraphiteDataset>>() {
};
public static void main(final String... args) {
dumpGraphiteDatasets(gsonWithDeserializers.fromJson(JSON, graphiteDatasetsTypeToken.getType()));
dumpGraphiteDatasets(gsonWithTypeAdapters.fromJson(JSON, graphiteDatasetsTypeToken.getType()));
}
private static void dumpGraphiteDatasets(final Iterable<GraphiteDataset> graphiteDatasets) {
graphiteDatasets.forEach(graphiteDataset -> {
out.println(graphiteDataset.target);
graphiteDataset.dataPoints.forEach(graphiteDataPoint -> {
out.print(" ");
out.print(graphiteDataPoint.value);
out.print(" ");
out.println(graphiteDataPoint.timestamp);
});
});
}
输出:
entries
1.0 1311836008
2.0 1311836009
3.0 1311836010
5.0 1311836011
6.0 1311836012
entries
1.0 1311836008
2.0 1311836009
3.0 1311836010
5.0 1311836011
6.0 1311836012