2016-03-24 34 views
1

ジャンクソンの多型逆シリアル化機能を使用して、ヘッダ/フィールドにネストされたプロパティに基づいてオブジェクトを逆シリアル化する方法を見つけようとしています。制御対象:オブジェクト内にネストされた型のプロパティを持つJackson多型逆シリアル化

JSON 1 - カテゴリ1:

{ 
"id":"someId", 
"header":{ 
      "category":"CATEGORY1", 
      "somOtherProperty":"someValue" 
      } 
"nextField":"nextValue", 
... 
} 

JSON 2 - カテゴリ2

{ 
"id":"someId", 
"header":{ 
      "category":"CATEGORY2", 
      "somOtherProperty":"someValue" 
      } 
"nextField":"nextValue", 
... 
} 

親クラス(このような注釈何か)

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "category") 
@JsonSubTypes({ 
     @Type(value = Category1Class.class, name = "CATEGORY1"), 
     @Type(value = Category2Class.class, name = "CATEGORY2") }) 
public class ParentClass{ 
    private Header header; 
    private String nextField; 
    ... 
} 

public class Header{ 
    private String category; 
    private String somOtherProperty; 
    ... 
} 

子クラス

@JsonTypeName("CATEGORY1") 
public class Category1Class extends ParentClass{ 
    ... 
} 

@JsonTypeName("CATEGORY2") 
public class Category2Class extends ParentClass{ 
    ... 
} 

は、デシリアライゼーションのこの種を行うために私を可能にするか、私は何かが欠けていジャクソンのボックス機能のうちはありますか?

+0

がhttps://www.thomaskeller.biz/blog/2013/09/10/customを見ます多形型ハンドリングとジャックソン/ –

答えて

1

ジャクソンApi AsPropertyTypeDeserializerを見ると、プロパティを使用するサブタイプ識別を担当するクラスがあります。そのクラスを見るとdeserializeTypedFromObjectというメソッドがあり、を使ってサブクラスを識別します。このクラスを拡張してメソッドdeserializeTypedFromObjectforPropertyをオーバーライドすることができます。拡張クラスで

package com.dilipkumarg.tutorials.dynamicsubtype; 

import java.io.IOException; 

import com.fasterxml.jackson.core.JsonParser; 
import com.fasterxml.jackson.databind.BeanProperty; 
import com.fasterxml.jackson.databind.DeserializationContext; 
import com.fasterxml.jackson.databind.JavaType; 
import com.fasterxml.jackson.databind.JsonDeserializer; 
import com.fasterxml.jackson.databind.JsonNode; 
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; 
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; 
import com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer; 
import com.fasterxml.jackson.databind.node.TreeTraversingParser; 
import com.fasterxml.jackson.databind.type.SimpleType; 

public class CustomTypeDeserializer extends AsPropertyTypeDeserializer { 
public CustomTypeDeserializer(
     final JavaType bt, final TypeIdResolver idRes, 
     final String typePropertyName, final boolean typeIdVisible, final Class<?> defaultImpl) { 
    super(bt, idRes, typePropertyName, typeIdVisible, defaultImpl); 
} 

public CustomTypeDeserializer(
     final AsPropertyTypeDeserializer src, final BeanProperty property) { 
    super(src, property); 
} 

@Override 
public TypeDeserializer forProperty(
     final BeanProperty prop) { 
    return (prop == _property) ? this : new CustomTypeDeserializer(this, prop); 
} 

@Override 
public Object deserializeTypedFromObject(
     final JsonParser jp, final DeserializationContext ctxt) throws IOException { 
    JsonNode node = jp.readValueAsTree(); 
    Class<?> subType = findSubType(node); 
    JavaType type = SimpleType.construct(subType); 

    JsonParser jsonParser = new TreeTraversingParser(node, jp.getCodec()); 
    if (jsonParser.getCurrentToken() == null) { 
     jsonParser.nextToken(); 
    } 
    /* 16-Dec-2010, tatu: Since nominal type we get here has no (generic) type parameters, 
    * we actually now need to explicitly narrow from base type (which may have parameterization) 
    * using raw type. 
    * 
    * One complication, though; can not change 'type class' (simple type to container); otherwise 
    * we may try to narrow a SimpleType (Object.class) into MapType (Map.class), losing actual 
    * type in process (getting SimpleType of Map.class which will not work as expected) 
    */ 
    if (_baseType != null && _baseType.getClass() == type.getClass()) { 
     type = _baseType.narrowBy(type.getRawClass()); 
    } 
    JsonDeserializer<Object> deser = ctxt.findContextualValueDeserializer(type, _property); 
    return deser.deserialize(jsonParser, ctxt); 
} 

protected Class<?> findSubType(JsonNode node) { 
    Class<? extends ParentClass> subType = null; 
    String cat = node.get("header").get("category").asText(); 
    if (cat.equals("CATEGORY1")) { 
     subType = Category1Class.class; 
    } else if (cat.equals("CATEGORY2")) { 
     subType = Category2Class.class; 
    } 
    return subType; 
} 
} 

我々は代わりに、我々はheaderフィールドのcategoryフィールドに動的に識別さidResolverを使用して、サブタイプ識別を迂回。
新しいCustomTypeDeserializerインスタンスを作成するにはTypeResolverBuilderが必要です。

package com.dilipkumarg.tutorials.dynamicsubtype; 

import java.util.Collection; 

import com.fasterxml.jackson.databind.DeserializationConfig; 
import com.fasterxml.jackson.databind.JavaType; 
import com.fasterxml.jackson.databind.jsontype.NamedType; 
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; 
import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; 


public class CustomTypeResolver extends StdTypeResolverBuilder { 
    @Override 
    public TypeDeserializer buildTypeDeserializer(final DeserializationConfig config, final JavaType baseType, final Collection<NamedType> subtypes) { 
     return new CustomTypeDeserializer(baseType, null, 
      _typeProperty, _typeIdVisible, _defaultImpl); 
    } 
} 

今、私たちは、サブタイプを識別するためのCustomTypeResolverを持っているが、それは「ParentClass」が見つかり時にどのようにJackonこのクラスを見て知っているのだろうか? ObjectMapperを作成中

  1. は、カスタム設定でJackonAnnotationInterceptorを拡張し、それを設定します。
    我々は2つの方法でそれを行うことができます。

  2. @JsonTypeResolver注釈を使用します。これは、何も構成する必要がないため、推奨されるアプローチです。タイプを含めた後

は、私たちの新しいParentClassクラスはなりリゾルバ:

package com.dilipkumarg.tutorials.dynamicsubtype; 

import com.fasterxml.jackson.annotation.JsonTypeInfo; 
import com.fasterxml.jackson.databind.annotation.JsonTypeResolver; 

@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) 
@JsonTypeResolver(CustomTypeResolver.class) 
public class ParentClass { 
    private Header header; 
    private String nextField; 
    ... 
} 

here

関連する問題