{
vendors: [
{
vendor: {
id: 367,
name: "Kuhn-Pollich",
company_id: 1,
}
},
{
vendor: {
id: 374,
name: "Sawayn-Hermann",
company_id: 1,
}
}]
}
単一の「ベンダー」jsonから適切にデシリアライズできるVendorオブジェクトがありますが、これをVendor[]
にデシリアライズしたいのですが、ジャクソンを協力させる方法がわかりません。任意のヒント?
配列に内部wrapperオブジェクトがあるという点で、データには問題があります。おそらく、Vendor
オブジェクトはid
、name
、company_id
を処理するように設計されていますが、これらの複数のオブジェクトはそれぞれ、単一のプロパティvendor
を持つオブジェクトにラップされています。
Jackson Data Binding モデルを使用していると仮定しています。
その場合、考慮すべき2つのことがあります。
1つ目は、特別なJackson構成プロパティを使用することです。ジャクソン-1.9以降、古いバージョンのジャクソンを使用している場合、これは利用できない可能性があります- UNWRAP_ROOT_VALUE
を提供します。結果が、破棄するトップレベルの単一プロパティオブジェクトにラップされている場合のために設計されています。
だから、遊んでください:
objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
2つ目は、ラッパーオブジェクトの使用です。外側のラッパーオブジェクトを破棄した後でも、Vendor
オブジェクトが単一プロパティオブジェクトにラップされるという問題があります。これを回避するにはラッパーを使用します。
class VendorWrapper
{
Vendor vendor;
// gettors, settors for vendor if you need them
}
同様に、UNWRAP_ROOT_VALUES
を使用する代わりに、ラッパークラスを定義して外部オブジェクトを処理することもできます。正しいVendor
、VendorWrapper
オブジェクトがあると仮定して、以下を定義できます。
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);
VendorsWrapperのオブジェクトツリーは、JSONに類似しています。
VendorsWrapper:
vendors:
[
VendorWrapper
vendor: Vendor,
VendorWrapper:
vendor: Vendor,
...
]
最後に、Jackson Tree Model を使用して、これをJsonNodes
に解析し、外部ノードを破棄し、各JsonNode
についてArrayNode
、呼び出し:
mapper.readValue(node.get("vendor").getTextValue(), Vendor.class);
その結果、コードが少なくなる可能性がありますが、2つのラッパーを使用するよりも不器用ではないようです。
ラフですが、より宣言的なソリューションです。単一のアノテーションにまとめることはできませんでしたが、これはうまくいくようです。また、大規模なデータセットのパフォーマンスについてもわかりません。
この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);
}
}
これが誰かに役立つことを願っています!
@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;
}
より速く動作します:)