Java 用Gson解析Graphite-JSON响应

Java 用Gson解析Graphite-JSON响应,java,gson,graphite,Java,Gson,Graphite,我正在编写一个Java库,用于与来自Graphite的度量进行交互。 典型的JSON响应如下所示(取自官方文档): 其中,“datapoints”数组的第一个元素是值,第二个元素是时间戳。我已经建模了一个GraphiteDataset类,如下所示 class GraphiteDataset { private String target; private List<GraphiteDatapoint> datapoints; .... } 现在我需要将响应

我正在编写一个Java库,用于与来自Graphite的度量进行交互。 典型的JSON响应如下所示(取自官方文档):

其中,“datapoints”数组的第一个元素是值,第二个元素是时间戳。我已经建模了一个GraphiteDataset类,如下所示

class GraphiteDataset {
    private String target;
    private List<GraphiteDatapoint> datapoints;

    ....
}
现在我需要将响应(见上文)解析到GraphiteDataset中 使用Gson初始化。不幸的是,“数据点”的元素不是命名对象(例如,
{timestamp:1234,value:1.0}
),而是一个二维数组,因此我无法直接将其反序列化到某个类中。目前我的解决方案是使用一个中间类

class GraphiteIntermediateDataset {
    private String target;
    private List<String> datapoints;
    ...
}
类GraphiteIntermediateDataset{
私有字符串目标;
私有列表数据点;
...
}

它将数据点作为字符串,然后我将它们解析到相应的GraphiteDapPoint实例中。我认为我无法使用自定义反序列化程序。您有什么建议或技巧可以让它更方便一些吗?

JSON
[1.2123456]
是一个由
双精度
长长度
组成的数组,但它们都是
数字
,请尝试以下操作:

class GraphiteDataset {
    private String target;
    private List<List<Number>> datapoints;

    ....
}
假设构造函数如下所示:

class GraphiteDatapoint {
    private Long timestamp;
    private Double value;
    public GraphiteDatapoint(Double value, Long timestamp) {
        this.value = value;
        this.timestamp = timestamp;
    }
    ...
}

JSON
[1.2123456]
是一个由
双精度
长长度
组成的数组,但它们都是
数字
,因此请尝试以下方法:

class GraphiteDataset {
    private String target;
    private List<List<Number>> datapoints;

    ....
}
假设构造函数如下所示:

class GraphiteDatapoint {
    private Long timestamp;
    private Double value;
    public GraphiteDatapoint(Double value, Long timestamp) {
        this.value = value;
        this.timestamp = timestamp;
    }
    ...
}

最终的解决方案是引入一个中间类
GraphiteIntermediateDataset
,如下所示:

class GraphiteIntermediateDataset {
    private String target;
    private List<List<Number>> datapoints;
}
类GraphiteIntermediateDataset{
私有字符串目标;
私有列表数据点;
}
反序列化程序代码如下所示

List<GraphiteIntermediateDataset> intermediateDatasetList = GSON.fromJson(raw, new TypeToken<List<GraphiteIntermediateDataset>>(){}.getType());

GraphiteIntermediateDataset intermediateDataset = intermediateDatasetList.get(0);

... check if empty (which can happen), when true return an empty GraphiteDataset

List<GraphiteDatapoint> gDatapoints = intermediateDataset
         .stream()
         .map(ds -> {
            return new GraphiteDatapoint(ds.get(0).longValue(),
                                         ds.get(1).doubleValue())
            }
         .collect(Collectors.toList());
return new GraphiteDataset()
       .setDatapoints(gDatapoints);
List intermediateDatasetList=GSON.fromJson(原始,新类型令牌(){}.getType());
GraphiteIntermediateDataset intermediateDataset=intermediateDatasetList.get(0);
…检查是否为空(可能发生),如果为真,则返回一个空的GraphiteDataset
列表gDatapoints=中间数据集
.stream()
.map(ds->{
返回新的GraphiteDatapoint(ds.get(0).longValue(),
ds.get(1.doubleValue())
}
.collect(Collectors.toList());
返回新的GraphiteDataset()
.设定数据点(gDatapoints);

最终解决方案是引入一个中间类
GraphiteIntermediateDataset
,如下所示:

class GraphiteIntermediateDataset {
    private String target;
    private List<List<Number>> datapoints;
}
类GraphiteIntermediateDataset{
私有字符串目标;
私有列表数据点;
}
反序列化程序代码如下所示

List<GraphiteIntermediateDataset> intermediateDatasetList = GSON.fromJson(raw, new TypeToken<List<GraphiteIntermediateDataset>>(){}.getType());

GraphiteIntermediateDataset intermediateDataset = intermediateDatasetList.get(0);

... check if empty (which can happen), when true return an empty GraphiteDataset

List<GraphiteDatapoint> gDatapoints = intermediateDataset
         .stream()
         .map(ds -> {
            return new GraphiteDatapoint(ds.get(0).longValue(),
                                         ds.get(1).doubleValue())
            }
         .collect(Collectors.toList());
return new GraphiteDataset()
       .setDatapoints(gDatapoints);
List intermediateDatasetList=GSON.fromJson(原始,新类型令牌(){}.getType());
GraphiteIntermediateDataset intermediateDataset=intermediateDatasetList.get(0);
…检查是否为空(可能发生),如果为真,则返回一个空的GraphiteDataset
列表gDatapoints=中间数据集
.stream()
.map(ds->{
返回新的GraphiteDatapoint(ds.get(0).longValue(),
ds.get(1.doubleValue())
}
.collect(Collectors.toList());
返回新的GraphiteDataset()
.设定数据点(gDatapoints);

类型安全和正确的数据绑定是您的朋友。Gson有几种方法可以满足您的需要。例如,声明数据传输对象:

最终类石墨化塔塞{
最终字符串目标;
//传入的DTO具有属性“datapoints”,但是Java约定建议使用datapoints(就我的英语理解而言)。
@SerializedName(“数据点”)
最后列出数据点;
//实际上,Gson不需要这个构造函数,DTO甚至可以有一个私有的默认构造函数。
//但为了使它与下一个类保持一致,只需使它以编程方式实例化。。。
//此外,但可能是基于观点的,隐藏构造函数确实是一个好主意,因为可以隐藏实例化策略,而构造函数不能。
专用GraphiteDataset(最终字符串目标,最终列表数据点){
this.target=目标;
this.dataPoints=数据点;
}
}
最终类石墨化点{
最终双值;
最终长时间戳;
专用GraphiteDapPoint(最终双精度值,最终长时间戳){
这个值=值;
this.timestamp=时间戳;
}
//实例化必须以某种方式通过编程进行访问
静态GraphiteDapPoint GraphiteDapPoint(最终双精度值,最终长时间戳){
返回新的GraphiteDapPoint(值、时间戳);
}
}
然后实现GraphiteDataPoint JSON反序列化器:

//在Gson中,序列化程序和反序列化程序只能处理对象的中间Gson JSON树表示(JsonElement-s)。
//在某些情况下,如果要序列化/反序列化的给定数据不消耗太多内存,那么它非常简单
最终类GraphiteDataPointJsonDeserializer
实现JsonDeserializer{
私有静态最终JsonDeserializer graphiteDataPointJsonDeserializer=新graphiteDataPointJsonDeserializer();
私有GraphiteDataPointJsonDeserializer(){
}
//不允许两次或多次实例化无状态(因此是线程安全的)反序列化程序
静态JsonDeserializer getGraphiteDataPointJsonDeserializer()的{
返回graphiteDataPointJsonDeserializer;
}
@凌驾
公共GraphiteDataPoint反序列化(最终JsonElement JsonElement、最终类型类型、最终JsonDeserializationContext)
抛出JsonParseException{
final JsonArray asJsonArray=jsonElement.getAsJsonArray();
最终双精度值=asJsonArray.get(0.getAsJsonPrimitive().getAsDouble();
最终长时间戳=asJsonArray.get(1.getAsJsonPrimitive().getAsLong();
返回GraphiteDapPoint(值、时间戳);
}
}
或类型适配器:

//与序列化程序和反序列化程序不同,类型适配器设计用于处理流。