2016-04-18 61 views
0

我有一个简单的Spring MVC应用程序,它使用RestTemplate类对ReST服务进行Ajax调用。模式中的一些元素以大写字母开头。小写字母的2个元素(代码,消息)不会造成任何问题。由JAXB生成的类具有@XmlElement注释和name属性。这似乎被忽略了。我读过JaxbAnnotationIntrospector需要使用,但没有任何更改使生效。见下面的课。我已经尝试在Spring配置中为RestTemplate添加一个bean类定义,添加一个对象映射器,但没有任何帮助。见OTPRO元件上错误在堆栈跟踪的前几行:带有大写元素名称的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; 
... 

Service类:

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

Spring配置:

<?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> 

注意:我不想简单地忽略大写元素。

+0

它看起来像服务正在返回JSON,你试图将其反序列化为XML? – david

+0

这些类是从XML模式生成的,但请求/响应是JSON。此外,响应中返回的“代码”和“消息”字段没有问题。这些名字是小写的。只有大写字段会导致“无法读取JSON:无法识别的字段”错误。 –

+0

我想你需要添加一些杰克逊特定的注释到那些有问题的领域。 – david

回答

1

解决方案是使用JacksonAnnotationIntrospector和JaxbAnnotationIntrospector的组合。在这种情况下,Jackson需要识别请求中的@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; 
    } 
} 
相关问题