我有一个使用Spring(v4.0.5)的http服务。它的http端点是使用Spring Web MVC配置的。响应是由模式生成的JAXB2-anotated类。响应包含在JAXBElement
中,因为生成的JAXB类没有运行@XmlRootElement
注释(并且模式不能修改为医生)。我不得不fight a bit获得XML编组工作;无论如何,它正在发挥作用。
现在我正在设置JSON编组。我遇到的是获取具有JAXBElement
“信封”的JSON文档。
{
"declaredType": "io.github.gv0tch0.sotaro.SayWhat",
"globalScope": true,
"name": "{urn:io:github:gv0tch0:sotaro}say",
"nil": false,
"scope": "javax.xml.bind.JAXBElement$GlobalScope",
"typeSubstituted": false,
"value": {
"what": "what",
"when": "2014-06-09T15:56:46Z"
}
}
我想要编组的只是value
- 对象:
{
"what": "what",
"when": "2014-06-09T15:56:46Z"
}
这是我的JSON编组配置(弹簧上下文配置的一部分):
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonMapper" />
<property name="supportedMediaTypes" value="application/json" />
</bean>
<bean id="jacksonMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss'Z'" />
<property name="timeZone">
<bean class="java.util.TimeZone" factory-method="getTimeZone">
<constructor-arg type="java.lang.String" value="UTC" />
</bean>
</property>
</bean>
</property>
</bean>
我希望通过配置ObjectMapper
可以实现这一点。我想也可以推出我自己的序列化器。思考?建议?
答案 0 :(得分:9)
您可以为JAXBElement类注册mixin annotation,它会将@JsonValue注释放在JAXBElement.getValue()方法上,使其返回值为JSON表示。这是一个例子:
提供给xjc
的示例.xsd chema文件。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item" type="Thing"/>
<xs:complexType name="Thing">
<xs:sequence>
<xs:element name="number" type="xs:long"/>
<xs:element name="string" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Java主类:
public class JacksonJAXBElement {
// a mixin annotation that overrides the handling for the JAXBElement
public static interface JAXBElementMixin {
@JsonValue
Object getValue();
}
public static void main(String[] args) throws JAXBException, JsonProcessingException {
ObjectFactory factory = new ObjectFactory();
Thing thing = factory.createThing();
thing.setString("value");
thing.setNumber(123);
JAXBElement<Thing> orderJAXBElement = factory.createItem(thing);
System.out.println("XML:");
JAXBContext jc = JAXBContext.newInstance(Thing.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(orderJAXBElement, System.out);
System.out.println("JSON:");
ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(JAXBElement.class, JAXBElementMixin.class);
System.out.println(mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(orderJAXBElement));
}
}
输出:
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<item>
<number>123</number>
<string>value</string>
</item>
JSON:
{
"number" : 123,
"string" : "value"
}
答案 1 :(得分:3)
有关完全配置项目的示例:
JAXBElement
- 包装。前往here。
基本要素是:
JAXBElement
- 包装器中解开响应对象。AnnotationIntrospectorPair
introspector(注意,页面有点过时了)它将JAXB注释introspector配置为主要的introspector(确保响应符合XSD规定的内容),将Jackson作为次要内容(确保JAXBElement
展开 mixin 正在播放中。Mixin :
/**
* Ensures, when the Jackson {@link ObjectMapper} is configured with it, that
* {@link JAXBElement}-wrapped response objects when serialized as JSON documents
* do not feature the JAXBElement properties; but instead the JSON-document that
* results in marshalling the member returned by the {@link JAXBElement#getValue()}
* call.
* <p>
* More on the usage and configuration options is available
* <a href="http://wiki.fasterxml.com/JacksonMixInAnnotations">here</a>.
*/
public interface JaxbElementMixin {
@JsonValue
Object getValue();
}
Spring上下文配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-4.0.xsd">
<context:component-scan base-package="io.github.gv0tch0.sotaro"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="ignoreAcceptHeader" value="false" />
<property name="useJaf" value="false" />
<property name="defaultContentType" value="application/xml" />
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
</bean>
<bean id="typeFactory" class="com.fasterxml.jackson.databind.type.TypeFactory" factory-method="defaultInstance" />
<bean id="jaxbIntrospector" class="com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector">
<constructor-arg ref="typeFactory" />
</bean>
<bean id="jacksonIntrospector" class="com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector" />
<bean id="annotationIntrospector" class="com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair">
<!-- Note that in order to get the best of both the JAXB annotation instrospector and the Mixin configuration
the JAXB introspector needs to be the primary introspector, hence it needs to stay at position 0. -->
<constructor-arg index="0" ref="jaxbIntrospector" />
<constructor-arg index="1" ref="jacksonIntrospector" />
</bean>
<bean id="jacksonMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="annotationIntrospector" ref="annotationIntrospector" />
<!-- The mixin ensures that when JAXBElement wrapped responses are marshalled as JSON the
JAXBElement "envelope" gets discarded (which makes our JSON responses conform to spec). -->
<property name="mixInAnnotations">
<map key-type="java.lang.Class" value-type="java.lang.Class">
<entry key="javax.xml.bind.JAXBElement" value="io.github.gv0tch0.sotaro.JaxbElementMixin" />
</map>
</property>
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss'Z'" />
<property name="timeZone">
<bean class="java.util.TimeZone" factory-method="getTimeZone">
<constructor-arg type="java.lang.String" value="UTC" />
</bean>
</property>
</bean>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonMapper" />
<property name="supportedMediaTypes" value="application/json" />
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="supportJaxbElementClass" value="true" />
<property name="contextPath" value="io.github.gv0tch0.sotaro" />
</bean>
<bean id="xmlConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller" />
<property name="supportedMediaTypes" value="application/xml" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters register-defaults="false">
<ref bean="xmlConverter" />
<ref bean="jsonConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
</beans>