{
vendors: [
{
vendor: {
id: 367,
name: "Kuhn-Pollich",
company_id: 1,
}
},
{
vendor: {
id: 374,
name: "Sawayn-Hermann",
company_id: 1,
}
}]
}
我有一个Vendor对象,可以从单个“vendor”json中正确地反序列化,但是我想将其反序列化为Vendor[]
,我只是无法弄清楚如何让Jackson合作。有什么提示吗?
答案 0 :(得分:31)
这是一个粗略但更具声明性的解决方案。我无法将其归结为单个注释,但这似乎运作良好。还不确定大数据集的性能。
鉴于此JSON:
{
"list": [
{
"wrapper": {
"name": "Jack"
}
},
{
"wrapper": {
"name": "Jane"
}
}
]
}
这些模型对象:
public class RootObject {
@JsonProperty("list")
@JsonDeserialize(contentUsing = SkipWrapperObjectDeserializer.class)
@SkipWrapperObject("wrapper")
public InnerObject[] innerObjects;
}
和
public class InnerObject {
@JsonProperty("name")
public String name;
}
杰克逊伏都教的实施方式如下:
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface SkipWrapperObject {
String value();
}
和
public class SkipWrapperObjectDeserializer extends JsonDeserializer<Object> implements
ContextualDeserializer {
private Class<?> wrappedType;
private String wrapperKey;
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException {
SkipWrapperObject skipWrapperObject = property
.getAnnotation(SkipWrapperObject.class);
wrapperKey = skipWrapperObject.value();
JavaType collectionType = property.getType();
JavaType collectedType = collectionType.containedType(0);
wrappedType = collectedType.getRawClass();
return this;
}
@Override
public Object deserialize(JsonParser parser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode objectNode = mapper.readTree(parser);
JsonNode wrapped = objectNode.get(wrapperKey);
Object mapped = mapIntoObject(wrapped);
return mapped;
}
private Object mapIntoObject(JsonNode node) throws IOException,
JsonProcessingException {
JsonParser parser = node.traverse();
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(parser, wrappedType);
}
}
希望这对某人有用!
答案 1 :(得分:25)
您的数据存在问题,因为您的数组中包含内部包装器对象。据推测,您的Vendor
对象旨在处理id
,name
,company_id
,但这些多个对象中的每一个也都包含在具有单个属性{{1}的对象中}。
我假设你正在使用杰克逊Data Binding模型。
如果是这样,那么有两件事需要考虑:
第一种是使用特殊的Jackson配置属性。杰克逊 - 自1.9以来我相信,如果你使用旧版本的杰克逊,这可能无法使用 - 提供UNWRAP_ROOT_VALUE
。它适用于将结果包装在要丢弃的顶级单属性对象中的情况。
所以,玩弄:
vendor
第二个是使用包装器对象。即使在丢弃外部包装器对象之后,仍然存在将objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
对象包装在单个属性对象中的问题。使用包装器解决这个问题:
Vendor
同样,您也可以定义一个包装类来处理外部对象,而不是使用class VendorWrapper
{
Vendor vendor;
// gettors, settors for vendor if you need them
}
。假设您有正确的UNWRAP_ROOT_VALUES
,Vendor
对象,您可以定义:
VendorWrapper
VendorsWrapper的对象树类似于您的JSON:
class VendorsWrapper
{
List<VendorWrapper> vendors = new ArrayList<VendorWrapper>();
// gettors, settors for vendors if you need them
}
// in your deserialization code:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(jsonInput, VendorsWrapper.class);
最后,您可以使用杰克逊Tree Model将其解析为VendorsWrapper:
vendors:
[
VendorWrapper
vendor: Vendor,
VendorWrapper:
vendor: Vendor,
...
]
,丢弃外部节点,并为JsonNodes
中的每个JsonNode
调用:
ArrayNode
这可能会导致更少的代码,但它似乎不比使用两个包装器笨拙。
答案 2 :(得分:10)
@Patrick 我会稍微改进你的解决方案
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectNode objectNode = jp.readValueAsTree();
JsonNode wrapped = objectNode.get(wrapperKey);
JsonParser parser = node.traverse();
parser.setCodec(jp.getCodec());
Vendor mapped = parser.readValueAs(Vendor.class);
return mapped;
}
它运行得更快:)
答案 3 :(得分:0)
我参加聚会已经很晚了,但一种方法是使用静态内部类来解包值:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
class Scratch {
private final String aString;
private final String bString;
private final String cString;
private final static String jsonString;
static {
jsonString = "{\n" +
" \"wrap\" : {\n" +
" \"A\": \"foo\",\n" +
" \"B\": \"bar\",\n" +
" \"C\": \"baz\"\n" +
" }\n" +
"}";
}
@JsonCreator
Scratch(@JsonProperty("A") String aString,
@JsonProperty("B") String bString,
@JsonProperty("C") String cString) {
this.aString = aString;
this.bString = bString;
this.cString = cString;
}
@Override
public String toString() {
return "Scratch{" +
"aString='" + aString + '\'' +
", bString='" + bString + '\'' +
", cString='" + cString + '\'' +
'}';
}
public static class JsonDeserializer {
private final Scratch scratch;
@JsonCreator
public JsonDeserializer(@JsonProperty("wrap") Scratch scratch) {
this.scratch = scratch;
}
public Scratch getScratch() {
return scratch;
}
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
Scratch scratch = objectMapper.readValue(jsonString, Scratch.JsonDeserializer.class).getScratch();
System.out.println(scratch.toString());
}
}
但是,将 objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
与 @JsonRootName("aName")
、as pointed out by pb2q 结合使用可能更容易