2013-10-08 15 views
14

を使うポリモーフィックなオブジェクトモデルにJSONをデシリアライズ私は春のMVC(v3.2.0.RELEASE)Webアプリケーションで、次のオブジェクトモデルがあります:私はするためのクラスをシリアライズするとき春とJsonTypeInfo注釈

public class Order { 
    private Payment payment; 
} 

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.WRAPPER_OBJECT) 
@JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class) 
public interface Payment {} 


@JsonTypeName("creditCardPayment") 
public class CreditCardPayment implements Payment {} 

をJSONは、私は(私が望む正確に何である)以下の結果が得られます。

{ 
    "payment" : { 
    "creditCardPayment": { 
     ... 
    } 
} 

残念ながら、私は上記のJSONを取るとしようとする私のオブジェクトモデルに戻し、それをデシリアライズ場合、私は次の例外を取得します:

Could not read JSON: Could not resolve type id 'creditCardPayment' into a subtype of [simple type, class Payment] at [Source: [email protected]; line: 1, column: 58] (through reference chain: Order["payment"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id 'creditCardPayment' into a subtype of [simple type, class Payment] at [Source: [email protected]; line: 1, column: 58] (through reference chain: Order["payment"])

次のように私のアプリケーションは、スプリングJavaConfを介して構成されている:

@Configuration 
@EnableWebMvc 
public class AppWebConf extends WebMvcConfigurerAdapter { 

    @Bean 
    public ObjectMapper objectMapper() { 
     ObjectMapper objectMapper = new ObjectMapper(); 
     objectMapper.setSerializationInclusion(Include.NON_NULL); 
     objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false); 
     return objectMapper; 
    } 

    @Bean 
    public MappingJackson2HttpMessageConverter mappingJacksonMessageConverter() { 
     MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
     converter.setObjectMapper(objectMapper()); 
     return converter; 
    } 

    @Bean 
    public Jaxb2RootElementHttpMessageConverter jaxbMessageConverter() { 
     return new Jaxb2RootElementHttpMessageConverter(); 
    } 

    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
     converters.add(jaxbMessageConverter()); 
     converters.add(mappingJacksonMessageConverter()); 
    } 
} 

試験のために、私は2つの方法を有するコントローラは、一方がHTTP GETリクエスト(この1つは動作)と、1つの注文を返す持っていますHTTP POST(これは失敗)を介して注文を受け取ります。

@Controller 
public class TestController { 

    @ResponseBody 
    @RequestMapping(value = "/test", method = RequestMethod.GET) 
    public Order getTest() {} 

    @RequestMapping(value = "/test", method = RequestMethod.POST) 
    public void postTest(@RequestBody order) {} 

} 

私は様々な議論からすべての提案を試みましたが、これまで運がなかった。誰でも私が間違っていることを見つけることができますか?

答えて

8

は注釈

+1

! 'Payment'インターフェースから' @ JsonSubTypes.Type(name = "creditCardPayment"、value = CreditCardPayment.class)を削除し、 'AppWebConf'クラスに' objectMapper.registerSubtypes(CreditCardPayment.class);を追加しました。私の設定を一般的なものにしたいと思っていたので、注釈がうまくいかなかったのは残念ですが、少なくともこの問題は私には分かりません。ありがとうございました。 – grigori

+2

私は同じ問題に直面し、上記の解決策は役に立たない。 –

2

作品registerSubtypes()方法を使用する代わりに、ObjectMapper.registerSubtypesを使用して、サブタイプを登録してみてください!

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type") 
public interface Geometry { 
    //... 
} 

public class Point implements Geometry{ 
    //... 
} 
public class Polygon implements Geometry{ 
    //... 
} 
public class LineString implements Geometry{ 
    //... 
} 

GeoJson geojson= null; 
ObjectMapper mapper = new ObjectMapper(); 
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES); 
mapper.registerSubtypes(Polygon.class,LineString.class,Point.class); 

try { 
    geojson=mapper.readValue(source, GeoJson.class);    
} catch (IOException e) { 
    e.printStackTrace(); 
} 

注1:Interfaceと実装クラスを使用します。私は、クラスを実装クラスごとにクラスをデシリアライズするには、ObjectMapperの "registerSubtypes"メソッドを使用してそれらをすべて登録する必要があります。

注2:また、@JsonTypeInfo(use = JsonTypeInfo.Id.NAME、include = JsonTypeInfo.As.PROPERTY、property = "type") "をインタフェースの注釈として使用します。

mapperがPOJOの値をjsonとして書き込むときに、プロパティの順序を定義することもできます。

これは以下の注釈を使用して行うことができます。

@JsonPropertyOrder({"type","crs","version","features"}) 
public class GeoJson { 

    private String type="FeatureCollection"; 
    private List<Feature> features; 
    private String version="1.0.0"; 
    private CRS crs = new CRS(); 
    ........ 
} 

+0

コードと一緒に行く説明はおそらく役に立ちます –

+1

申し訳ありませんが、私はそれを逃しました。ですから、いくつかの機能でもう一度やり直しましょう。 –

0

ラッシュミンの回答がうまくいきました。com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id into a subtype of Blahの問題を回避する別の方法が見つかりました。registerSubtypesを使用する必要はありません。あなたにできることは、親クラスに次の注釈を追加します:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type") 

注差がJsonTypeInfo.Id.CLASS代わりのJsonTypeInfo.Id.NAMEであること。欠点は、作成されたJSONに完全な名前空間を含むクラス名全体が含まれることです。アップサイドは、サブタイプの登録について心配する必要がないということです。

+1

これは私にこのエラーを与えます: '原因:com.fasterxml.jackson.databind.JsonMappingException:予期しないトークン(END_OBJECT)、予期されたFIELD_NAME:タイプID(クラスcom.microstar.tap3のための)を含むプロパティ 'タイプ'がありません。 [source:org.glassfish.jersey.me[email protected]5699c6f9;で、 にあります。行:1、列:1023](参照チェーン:java.util.ArrayList [0]) ' –

2

私はdropwizardベースのサービスで作業中に同様の問題が発生しました。私はdropwizardコードが動作するのと同じ方法で私のものが私にとってうまくいかない理由を完全に理解していませんが、元の投稿のコードがなぜ機能しないのか分かります。 @JsonSubTypesは、単一の値ではなく、サブタイプの配列を必要とします。だから、あなたが行を置き換えるなら...私はあなたのコードが動作すると信じて

@JsonSubTypes({ @JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class) }) 

...と

@JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class) 

このエラーメッセージがポップアップしている場合は、サブタイプが検出されている可能性があります。上記のような行を追加するか、または@JsonTypeNameタグを持つクラスのディスカバリーで問題を探してみてください。

0

同じエラーが発生し、以下のJSONをDeserializerの入力として(CreditCardPaymentの代わりに私のクラス名を使用)と同等の機能を使用していました。

{ "タイプ": "たCreditCardPayment"、 ..... }

0

私は@JsonTypeInfoにdefaultImpl = SomeClass.classを追加していたし、それがSomeClass2.class変換しようとしていた私のケースで働いていた