CFL*_*eff 11 java json jsonserializer jackson
假设我有以下三个类(为了简洁省略了getter和setter):
@JsonAutoDetect
public class InfoCollection{
private InfoType1 info1;
private InfoType2 info2;
}
@JsonAutoDetect
public class InfoType1{
private String fieldA;
}
@JsonAutoDetect
public class InfoType2{
private String fieldB;
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试编写一个以这种格式JsonSerializer.serialize()序列化InfoCollection对象的函数:
{
"allInfo":{
"fieldA":"foo",
"fieldB":"bar"
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我现在拥有的:
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("allInfo");
jsonGenerator.writeObject(myInfoCollection.getInfo1());
jsonGenerator.writeObject(myInfoCollection.getInfo2());
jsonGenerator.writeEndObject();
Run Code Online (Sandbox Code Playgroud)
这导致以下异常:
org.codehaus.jackson.JsonGenerationException: Can not start an object, expecting field name
Run Code Online (Sandbox Code Playgroud)
我错过了一些小事情,还是我完全错误地采取了这种做法?
注:一对夫妇提出的解决方案迄今涉及编写的每一个人领域InfoType1和InfoType2.我正在寻找一个不需要这个的解决方案,因为我想在具有许多领域的大型类中使用该解决方案.
而不是调用writeFieldName("allInfo")你应该调用writeObjectFieldStart("allInfo")因为"allInfo"是另一个JSON对象.因此,您的自定义序列化程序应该采用以下方式:
public void serialize(InfoCollection infoCollection, JsonGenerator jgen, SerializerProvider provider) throws IOException{
jgen.writeStartObject();
jgen.writeObjectFieldStart("allInfo");
jgen.writeObjectField("fieldA", infoCollection.getInfo1().getFieldA());
jgen.writeObjectField("fieldB", infoCollection.getInfo2().getFieldB());
jgen.writeEndObject();
jgen.writeEndObject();
}
Run Code Online (Sandbox Code Playgroud)
或者您可以尝试基于注释的方法:
@JsonRootName("allInfo")
public class InfoCollection {
@JsonUnwrapped
private InfoType1 info1;
@JsonUnwrapped
private InfoType2 info2;
/* getters, setters */
}
Run Code Online (Sandbox Code Playgroud)
(您需要启用SerializationConfig.Feature.WRAP_ROOT_VALUE功能才能使其正常工作.请参阅序列化功能)
将来,当您有堆栈跟踪时,请让我们知道问题出现在哪一行。
也就是说,解决办法可能是:
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("allInfo");
jsonGenerator.writeStartObject(); // start nested object
jsonGenerator.writeFieldName("fieldA"); // start field
jsonGenerator.writeObject(myInfoCollection.getInfo1().fieldA);
jsonGenerator.writeFieldName("fieldB"); // start fieldB
jsonGenerator.writeObject(myInfoCollection.getInfo2().fieldB);
jsonGenerator.writeEndObject(); // end nested object
jsonGenerator.writeEndObject();
Run Code Online (Sandbox Code Playgroud)
使用包装对象的解决方案:
@JsonAutoDetect
public class Wrapper {
private transient InfoCollection data; // transient makes Jackson ignore this
public String getFieldA() { return data.info1.fieldA; }
public String getFieldB() { return data.info1.fieldB; }
}
Run Code Online (Sandbox Code Playgroud)
这让杰克逊只看到你想要什么以及你想要如何得到它。
或者,使用反射递归收集所有字段及其名称:
List<Pair<String, Object>> data = collectFields( myInfoCollection );
Run Code Online (Sandbox Code Playgroud)
collectFields应该检查所有字段并将所有内容添加到列表中,该列表可以是原始规则,也可以是field.getType().getName().startsWith("java.lang")您需要的位置规则或任何其他规则。
如果该字段是引用,则递归collectFields()调用。
有了列表后,只需jsonGenerator循环调用即可写入结果。
| 归档时间: |
|
| 查看次数: |
35637 次 |
| 最近记录: |