Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java GSON:如何将字段移动到父对象_Java_Json_Gson - Fatal编程技术网

Java GSON:如何将字段移动到父对象

Java GSON:如何将字段移动到父对象,java,json,gson,Java,Json,Gson,我正在使用将Java对象转换为JSON 目前我有以下结构: "Step": { "start_name": "Start", "end_name": "End", "data": { "duration": { "value": 292, "text": "4 min." }, "distance": { "value": 1009.0, "text": "1 km" }, "location

我正在使用将Java对象转换为JSON

目前我有以下结构:

"Step": {
  "start_name": "Start",
  "end_name": "End",
  "data": {
    "duration": {
      "value": 292,
      "text": "4 min."
    },
    "distance": {
       "value": 1009.0,
       "text": "1 km"
    },
    "location": {
       "lat": 59.0000,
       "lng": 9.0000,
       "alt": 0.0
    }
  }
}
当前,
持续时间
对象位于
数据
对象内。我想跳过
数据
对象,并将
持续时间
对象移动到
步骤
对象,如下所示:

"Step": {
  "start_name": "Start",
  "end_name": "End",
  "duration": {
    "value": 292,
    "text": "4 min."
  },
  "distance": {
     "value": 1009.0,
     "text": "1 km"
  },
  "location": {
     "lat": 59.0000,
     "lng": 9.0000,
     "alt": 0.0
  }
}
我如何使用GSON实现这一点


编辑:我尝试使用TypeAdapter修改Step.class,但在write方法中,我无法将duration对象添加到JsonWriter。

我认为在gson中没有更好的方法。可能从初始json获取java对象(映射),删除数据,设置持续时间并序列化为json:

Map initial = gson.fromJson(initialJson);

// Replace data with duration in this map
Map converted = ...

String convertedJson = gson.toJson(converted);

您可能可以通过编写,然后为
步骤
注册一个,并确保在其中使用
持续时间
等,而不是
数据
来完成此操作

// registering your custom serializer:
GsonBuilder builder = new GsonBuilder ();
builder.registerTypeAdapter (Step.class, new StepSerializer ());
Gson gson = builder.create ();
// now use 'gson' to do all the work
下面自定义序列化程序的代码,我正在从头开始写。它忽略了异常处理,可能无法编译,并且会重复创建
Gson
的实例等操作。但它代表了你想要做的事情:

class StepSerializer implements JsonSerializer<Step>
{
  public JsonElement serialize (Step src,
                                Type typeOfSrc,
                                JsonSerializationContext context)
    {
      Gson gson = new Gson ();
      /* Whenever Step is serialized,
      serialize the contained Data correctly.  */
      JsonObject step = new JsonObject ();
      step.add ("start_name", gson.toJsonTree (src.start_name);
      step.add ("end_name",   gson.toJsonTree (src.end_name);

      /* Notice how I'm digging 2 levels deep into 'data.' but adding
      JSON elements 1 level deep into 'step' itself.  */
      step.add ("duration",   gson.toJsonTree (src.data.duration);
      step.add ("distance",   gson.toJsonTree (src.data.distance);
      step.add ("location",   gson.toJsonTree (src.data.location);

      return step;
    }
}
类StepSerializer实现JsonSerializer
{
公共JsonElement序列化(步骤src,
SRC的类型,
JsonSerializationContext(上下文)
{
Gson-Gson=新的Gson();
/*无论何时序列化步骤,
正确序列化包含的数据*/
JsonObject步骤=新建JsonObject();
步骤.add(“启动名称”,gson.toJsonTree(src.start\u名称);
步骤.add(“end_name”,gson.toJsonTree(src.end_name);
/*注意我是如何在“数据”中深入挖掘两个层次的
JSON元素深入“步骤”本身1级*/
添加步骤(“持续时间”,gson.toJsonTree(src.data.duration);
添加步骤(“距离”,gson.toJsonTree(src.data.distance);
步骤.add(“位置”,gson.toJsonTree(src.data.location);
返回步骤;
}
}

遇到了同样的问题。@arjunsunkar的答案为我指明了正确的方向。我通过编写自定义序列化程序修复了它,但略有不同:

public class StepSerializer implements JsonSerializer<Step> {
    @Override
    public JsonElement serialize(Step src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject step = new JsonObject();
        step.add ("start_name", context.serialize(src.start_name);
        step.add ("end_name",   context.serialize(src.end_name);

        JsonObject data = context.serialize(src.data).getAsJsonObject();
        data.entrySet().forEach(entry -> {
            step.add(entry.getKey(), entry.getValue());
        });

        return step;
    }
}
公共类StepSerializer实现JsonSerializer{
@凌驾
公共JsonElement序列化(步骤src,类型typeOfSrc,JsonSerializationContext){
JsonObject步骤=新建JsonObject();
step.add(“start\u name”,context.serialize(src.start\u name);
step.add(“end\u name”,context.serialize(src.end\u name);
JsonObject data=context.serialize(src.data).getAsJsonObject();
data.entrySet().forEach(条目->{
添加(entry.getKey(),entry.getValue());
});
返回步骤;
}
}

这可以进一步改进,“开始名称”和“结束名称”道具仍然是硬编码的。可以通过检查根对象的入口集并排除其中的“数据”来删除道具,只留下需要展开硬编码的元素。

在这种情况下,我为嵌套的
数据
字段注册
类型适配器
。在适配器中,
数据
的字段被添加到父对象t、 不需要为封闭类创建适配器

public class Step {
    private String startName;
    private endName;
    @JsonAdapter(JsonFlatMapAdapter.class)
    private Map<String, Object> data;
    ...
}

public class JsonFlatMapAdapter extends TypeAdapter<Map<String, Object>> {

    @Override
    public void write(JsonWriter out, Map<String, Object> value) throws IOException {
        out.nullValue();
        Gson gson = new Gson();
        value.forEach((k,v) -> {
            try {
                out.name(k).jsonValue(gson.toJson(v));
            } catch (IOException e) {
            }
        });
    }

    @Override
    public Map<String, Object> read(JsonReader in) throws IOException {
        return null;
    }

}
公共类步骤{
私有字符串startName;
私有端名;
@JsonAdapter(JsonFlatMapAdapter.class)
私有地图数据;
...
}
公共类JsonFlatMapAdapter扩展了TypeAdapter{
@凌驾
public void write(JsonWriter out,Map值)抛出IOException{
out.nullValue();
Gson Gson=新的Gson();
forEach值((k,v)->{
试一试{
out.name(k).jsonValue(gson.toJson(v));
}捕获(IOE异常){
}
});
}
@凌驾
公共映射读取(JsonReader in)引发IOException{
返回null;
}
}

我只需要
序列化
,所以
反序列化
并不重要。上面只是我结构的一个例子。事实上,我的数据对象包含额外的字段,需要包含在
toJsonTree
中。有什么线索吗?这取决于具体情况。显示一个包含两个额外字段的示例,我将看看我能想到什么。注意:我的答案是基于Gson文档的。我以前从未做过这样奇怪的事情。我用数据对象中的附加字段更新了我的问题。@DennisMadsen-我更新了我的答案以反映您的更改。祝您好运。谢谢。有没有办法从src step和只要删除它的数据对象?如果可能的话,我就不必再添加开始和结束名称了。