2016-04-18 59 views
0

RestTemplateクラスを使用してReSTサービスにAjax呼び出しを行う簡単なSpring MVCアプリケーションがあります。スキーマの一部の要素は大文字で始まります。小文字の2つの要素(コード、メッセージ)は問題ありません。 JAXBによって生成されたクラスには、@ XmlElementアノテーションと名前プロパティがあります。これは無視されるようです。私は、JaxbAnnotationIntrospectorを使用する必要があるが、その変更は有効でないことを読んだ。下記のクラスを参照してください。私はオブジェクトのマッパーを追加するが、何も役立たないSpringの設定でRestTemplateのBeanクラス定義を追加しようとしました。大文字の要素名でSpring RestTemplateが失敗する

[4/18/16 9:52:43:988 EDT] 00000024 SystemErr  R org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "OTPRO" (class com.ssdr.rest.message.SSDRResponse), not marked as ignorable (7 known properties: "dt", "ot", "message", "otpro", "otphone", "code", "dtphone"]) 
at [Source: [email protected]e679; line: 4, column: 14] (through reference chain: com.ssdr.rest.message.SSDRResponse["OTPRO"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "OTPRO" (class com.ssdr.rest.message.SSDRResponse), not marked as ignorable (7 known properties: "dt", "ot", "message", "otpro", "otphone", "code", "dtphone"]) 
at [Source: [email protected]e679; line: 4, column: 14] (through reference chain: com.ssdr.rest.message.SSDRResponse["OTPRO"]) 
[4/18/16 9:52:44:019 EDT] 00000024 SystemErr  R at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:126) 
[4/18/16 9:52:44:019 EDT] 00000024 SystemErr  R at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153) 
[4/18/16 9:52:44:019 EDT] 00000024 SystemErr  R at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:81) 

JAXB生成されたクラス:

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlType; 

/** 
* <p>Java class for documentResponse complex type. 
* 
* <p>The following schema fragment specifies the expected content contained within this class. 
* 
* <pre> 
* &lt;complexType name="documentResponse"> 
* &lt;complexContent> 
*  &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> 
*  &lt;sequence> 
*   &lt;element name="code" type="{http://www.w3.org/2001/XMLSchema}string"/> 
*   &lt;element name="message" type="{http://www.w3.org/2001/XMLSchema}string"/> 
*   &lt;element name="OTPRO" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="OT" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="OTPhone" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="DT" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="DTPhone" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*  &lt;/sequence> 
*  &lt;/restriction> 
* &lt;/complexContent> 
* &lt;/complexType> 
* </pre> 
* 
* 
*/ 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "documentResponse", propOrder = { 
"code", 
"message", 
"otpro", 
"ot", 
"otPhone", 
"dt", 
"dtPhone" 
}) 
public class DocumentResponse { 

@XmlElement(required = true) 
protected String code; 
@XmlElement(required = true) 
protected String message; 
@XmlElement(name = "OTPRO", nillable = true) 
protected String otpro; 
@XmlElement(name = "OT", nillable = true) 
protected String ot; 
@XmlElement(name = "OTPhone", nillable = true) 
protected String otPhone; 
@XmlElement(name = "DT", nillable = true) 
protected String dt; 
@XmlElement(name = "DTPhone", nillable = true) 
protected String dtPhone; 
... 

サービスクラス:

SSDRResponse resp = null; 
    RestTemplate restTemplate = new RestTemplate(); 
    HttpEntity<SSDRRequest> httpRequest = new HttpEntity<SSDRRequest>(req, createHeaders()); 
    resp = restTemplate.postForObject(SERVICE_URI, httpRequest, SSDRResponse.class); 

春の設定:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd 
     http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> 

    <context:annotation-config /> 

    <!-- Scans the classpath of this application for @Components to deploy as beans --> 
    <context:component-scan base-package="com.ssdr" /> 

    <!-- Configures the @Controller programming model --> 
    <mvc:annotation-driven /> 

    <!-- Forwards requests to the "/" resource to the "index" view --> 
<!-- 
    <mvc:view-controller path="/" view-name="index" /> 
--> 
    <!-- Make webapp/resources directory accessible to web app --> 
    <mvc:resources location="/resources/" mapping="/resources/**" /> 

    <!-- Resolves view names to protected .jsp resources within the context root directory --> 
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <property name="prefix" value="/WEB-INF/jsp/" /> 
     <property name="suffix" value=".jsp" /> 
    </bean> 

<bean class="org.springframework.web.client.RestTemplate"> 
    <property name="messageConverters"> 
     <list> 
      <bean 
       class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
       <property name="supportedMediaTypes" value="application/json" /> 
       <property name="objectMapper"> 
        <bean class="com.fasterxml.jackson.databind.ObjectMapper"> 
         <property name="annotationIntrospector"> 
          <bean 
           class="com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector" /> 
         </property> 
        </bean> 
       </property> 
      </bean> 
     </list> 
    </property> 
</bean> 

    <!-- <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 
     <property name="mediaTypes"> 
     <map> 
      <entry key="html" value="text/html"/> 
      <entry key="json" value="application/json"/> 
     </map> 
     </property> 
     <property name="viewResolvers"> 
     <list> 
      <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> 
      <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> 
      <property name="prefix" value="/WEB-INF/jsp/"/> 
      <property name="suffix" value=".jsp"/> 
      </bean> 
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
      <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> 
      <property name="prefix" value="/WEB-INF/jsp/"/> 
      <property name="suffix" value=".jsp"/> 
      </bean> 
     </list> 
     </property> 
     <property name="defaultViews"> 
     <list> 
      <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"> 
      <property name="prefixJson" value="true"/> 
      </bean> 
     </list> 
     </property> 
    </bean> --> 

</beans> 
スタックトレースの最初の数行にOTPRO要素上のエラーを参照してください。

注:大文字の要素は無視したくありません。

+0

サービスがjsonを返すように見え、XMLとしてデシリアライズしようとしていますか? – david

+0

クラスはXMLスキーマから生成されますが、要求/応答はJSONです。また、レスポンスに返される "code"フィールドと "message"フィールドに問題はありません。これらの名前は小文字です。大文字のフィールドのみが「JSONを読み取れませんでした:認識できないフィールド」エラーが発生します。 –

+0

ジャックソン特有のアノテーションを問題のフィールドに追加する必要があると思います。 – david

答えて

1

解決策は、JacksonAnnotationIntrospectorとJaxbAnnotationIntrospectorの組み合わせを使用することでした。この場合、ジャクソンは要求内の@JsonIgnorePropertiesアノテーションと@JsonIncludeアノテーションを認識する必要がありました。しかし、ジャクソンは常に「認識されないフィールド」のエラーを投げた。 JAXBは大文字のフィールドで応答を読み取ることができますが、要求の注釈は認識しません。

次のコードは、サービスクラスに追加された両方のintrospectorsを使用するには:

List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); 
    MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter(); 
    ObjectMapper objMapper = new ObjectMapper(); 
    /* 
    * Jackson introspector needed for @JsonIgnoreProperties and @JsonInclude annotations 
    * JAXB introspector is needed to handle the uppercase element names in the response 
    */ 
    AnnotationIntrospector primary = new JacksonAnnotationIntrospector(); 
    AnnotationIntrospector secondary = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); 
    AnnotationIntrospector pair = AnnotationIntrospector.pair(primary, secondary); 
    objMapper.setAnnotationIntrospector(pair); 
    jaxMsgConverter.setObjectMapper(objMapper); 
    messageConverters.add(jaxMsgConverter); 

    SSDRResponse resp = null; 
    RestTemplate restTemplate = new RestTemplate(); 
    // Set message converter with Jackson and JAXB introspectors in RestTemplate 
    restTemplate.setMessageConverters(messageConverters); 
    HttpEntity<SSDRRequest> httpRequest = new HttpEntity<SSDRRequest>(req, createHeaders()); 
    resp = restTemplate.postForObject(SERVICE_URI, httpRequest, SSDRResponse.class); 

だけJAXBのイントロスペクタを使用するには:

List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); 
    MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter(); 
    ObjectMapper jaxMapper = new ObjectMapper(); 
    AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); 
    jaxMapper.setAnnotationIntrospector(introspector); 
    jaxMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // ignore unknown properties 
    jaxMsgConverter.setObjectMapper(jaxMapper); 
    messageConverters.add(jaxMsgConverter); 
0

私の春のブート構成(使用する準備ができて):

@Configuration 
@EnableWebMvc 
@EnableAutoConfiguration 
@ComponentScan(basePackages = {"path.to.your.package"}) 
public class WebMvcConfig extends WebMvcConfigurerAdapter { 
    @Bean 
    public ObjectMapper objectMapper() { 
     ObjectMapper jacksonMapper = new ObjectMapper(); 
     AnnotationIntrospector primary = new JacksonAnnotationIntrospector(); 
     AnnotationIntrospector secondary = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); 
     AnnotationIntrospector pair = AnnotationIntrospector.pair(primary, secondary); 

     jacksonMapper.setAnnotationIntrospector(pair); 
     jacksonMapper.configure(SerializationFeature.INDENT_OUTPUT, true); 
     return jacksonMapper; 
    } 

    @Bean 
    public RestTemplate getRestTemplate() { 
     List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); 
     MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter(); 

     ObjectMapper objectMapper = objectMapper(); 
     jaxMsgConverter.setObjectMapper(objectMapper); 
     messageConverters.add(jaxMsgConverter); 

     HttpClientBuilder builder = HttpClientBuilder.create(); 
     HttpClient httpClient = builder.build(); 
     HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); 
     RestTemplate template = new RestTemplate(new BufferingClientHttpRequestFactory(factory)); 

     template.setMessageConverters(messageConverters); 

     return template; 
    } 
}