2013-10-06 5 views
16

SpringMVCプロジェクトでJSON用の新しいJava API(JSR 353)を使用しています。SpringMVCで@ResponseBodyを使用してJsonObjectを返す

アイデアは、Jsonデータの一部を生成し、それをクライアントに戻すことです。私は多少このように見えるしているコントローラ:

@RequestMapping("/test") 
@ResponseBody 
public JsonObject test() { 
     JsonObject result = Json.createObjectBuilder() 
       .add("name", "Dade") 
       .add("age", 23) 
       .add("married", false) 
       .build(); 
     return result; 
    } 

そして、ときに私はこれにアクセスするには、代わりにJSONの予想される表現を得るための、私が代わりにこれらを取得する:

{"name":{"chars":"Dade","string":"Dade","valueType":"STRING"},"age":{"valueType":"NUMBER","integral":true},"married":{"valueType":"FALSE"}} 

これはなぜでしょうか?何が起こっている?そして、それがJSONを適切に返すようにするにはどうすればよいですか?

+2

どのようなAPIですか? –

+0

@SotiriosDelimanolis APIによると、あなたはJsonObjectを参照していますか?それはJSON処理のためのJSR 353:Java APIです。質問も更新されました – dade

答えて

22

新しいJSR 353 APIに特別なHandlerMethodReturnValueHandlerがないとわかった場合、その答えはかなり簡単です。代わりに、この場合、RequestResponseBodyMethodProcessor@ResponseBody)はMappingJackson2HttpMessageConverterを使用して、ハンドラメソッドの戻り値をシリアル化します。

内部では、MappingJackson2HttpMessageConverterObjectMapperを使用します。デフォルトでは、ObjectMapperはクラスのゲッターを使用してオブジェクトをJSONにシリアル化します。

あなたはJSR 353のGlassfishのプロバイダ実装を使用していると仮定すると、これらのクラスはorg.glassfish.json.JsonObjectBuilderImpl$JsonObjectImplorg.glassfish.json.JsonStringImpl、および org.glassfish.json.JsonNumberImpl、およびjavax.json.JsonValue$3(値FALSEための匿名クラス)です。

JsonObjectImpl(あなたの結果、すなわち。根、オブジェクトは)Map(特殊タイプ)ですので、ObjectMapperはマップキーはJSONのキーであるJSONのキーと値のペア要素、および地図値としてマップのエントリをシリアライズJSON値です。キーの場合、それはうまく動作し、nameage、およびmarriedとしてシリアル化されます。値については、上記のクラスとそれぞれのgetterを使用します。例えば、org.glassfish.json.JsonStringImpl

{"chars":"Dade","string":"Dade","valueType":"STRING"} 

同じことが他のフィールドに適用されるため、(すなわち、マップエントリの値である)JsonStringImplオブジェクトをシリアル化するためにJava Beanのゲッターを使用ObjectMapper

final class JsonStringImpl implements JsonString { 

    private final String value; 

    public JsonStringImpl(String value) { 
     this.value = value; 
    } 

    @Override 
    public String getString() { 
     return value; 
    } 

    @Override 
    public CharSequence getChars() { 
     return value; 
    } 

    @Override 
    public ValueType getValueType() { 
     return ValueType.STRING; 
    } 
    ... 
} 

として実装されています。

JSONを正しく書きたい場合は、Stringを返すだけです。

@RequestMapping("/test", produces="application/json") 
@ResponseBody 
public String test() { 
     JsonObject result = Json.createObjectBuilder() 
       .add("name", "Dade") 
       .add("age", 23) 
       .add("married", false) 
       .build(); 
     return result.toString(); 
} 

あなた自身のHandlerMethodReturnValueHandlerをもう少し複雑にしましたが、より報酬を与えてください。

+3

結果のJSONは '' {\ "foo \":\ "bar \"} "'のようにエスケープされ、 '{" foo ":" bar "}'のようにJSONだけを返す方法は? –

+0

@DzmitryLazerkaどこをエスケープしますか?上の 'test()'メソッドは何もエスケープしません。 –

+0

Springメッセージコンバータでは、テスト後に戻ります。結果は文字列であり、mime-typeのapplication/jsonはJSONに変換する必要があります。 MappingJackson2HttpMessageConverter(JacksonがWebMvcConfigurationSupportに存在する場合は、デフォルトで追加されます)を参照してください。それで、文字列をJSONに変換し、エスケープして二重引用符を追加します。 –

1

Sotirios Delimanolisの答えは本当にうまくいきますが、私の場合は適切なHttpMessageConverterの注文を確実に行わなければなりませんでした。これは、JodaTimeの値をISO 8601形式に変換する必要があったためです。このカスタムWebMvcConfigurerAdapter設定は私のために働いた:

@Configuration 
public class WebConfiguration extends WebMvcConfigurerAdapter { 

@SuppressWarnings("UnusedDeclaration") 
private static final Logger log = LoggerFactory.getLogger(WebConfiguration.class); 

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
    log.info("Configuring jackson ObjectMapper"); 
    final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
    final ObjectMapper objectMapper = new ObjectMapper(); 

    //configure Joda serialization 
    objectMapper.registerModule(new JodaModule()); 
    objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature. 
      WRITE_DATES_AS_TIMESTAMPS, false); 

    // Other options such as how to deal with nulls or identing... 
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT); 
    converter.setObjectMapper(objectMapper); 

    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); 
    /* 
    StringHttpMessageConverter must appear first in the list so that Spring has a chance to use 
    it for Spring RestController methods that return simple String. Otherwise, it will use 
     MappingJackson2HttpMessageConverter and clutter the response with escaped quotes and such 
    */ 
    converters.add(stringHttpMessageConverter); 
    converters.add(converter); 
    super.configureMessageConverters(converters); 
} 
} 
関連する問題