我有一个简单的Spring MVC应用程序,它使用RestTemplate类对ReST服务进行Ajax调用。模式中的一些元素以大写字母开头。带有小写字母的2个元素(代码,消息)不会产生任何问题。 JAXB生成的类具有@XmlElement注释和name属性。这似乎被忽略了。我已经读过需要使用JaxbAnnotationIntrospector但没有任何更改生效。见下面的课程。我已经尝试在Spring配置中为RestTemplate添加一个bean类定义,添加一个对象映射器,但没有任何帮助。在堆栈跟踪的前几行中查看OTPRO元素的错误:
[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: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@4ccbe679; 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: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@4ccbe679; 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>
* <complexType name="documentResponse">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="code" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="message" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="OTPRO" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="OT" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="OTPhone" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="DT" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="DTPhone" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </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);
Spring config:
<?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 :(得分:1)
解决方案是使用JacksonAnnotationIntrospector和JaxbAnnotationIntrospector的组合。在这种情况下,Jackson需要识别请求中的@JsonIgnoreProperties和@JsonInclude注释。但杰克逊总是抛出“无法识别的领域”错误。 JAXB可以使用大写字段读取响应,但不会识别请求中的注释。
要使用两个内省检索器,以下代码已添加到服务类中:
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 introspector:
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);
答案 1 :(得分: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;
}
}