복붙노트

[SPRING] JAXBElement 랩퍼없이 JAXBElement 랩핑 응답을 JSON 마샬링하는 방법은 무엇입니까?

SPRING

JAXBElement 랩퍼없이 JAXBElement 랩핑 응답을 JSON 마샬링하는 방법은 무엇입니까?

Spring (v4.0.5)을 사용하는 http 서비스가 있습니다. http 엔드 포인트는 Spring Web MVC를 사용하여 구성됩니다. 응답은 스키마에서 생성 된 JAXB2- anotated 클래스입니다. 생성 된 JAXB 클래스는 @XmlRootElement 주석을 사용하지 않기 때문에 응답은 JAXBElement에 래핑됩니다 (스키마는이를 의사에게 수정할 수 없습니다). XML을 마샬링하는 일과 조금씩 싸워야했습니다. 어쨌든, 그것은 효과가있다.

이제 JSON 마샬링을 설정하고 있습니다. 내가 실행중인 것은 JAXBElement "envelope"을 특징으로하는 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"
  }
}

marshalled으로 바꾸고 싶은 것은 바로 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를 구성하여이 작업을 수행 할 수 있기를 바랍니다. 나는 내 자신의 시리얼 라이저를 롤아웃하는 것이 효과가있을 것이라고 생각한다. 생각? 제안?

해결법

  1. ==============================

    1.@JsonValue 주석을 JAXBElement.getValue () 메소드에 넣는 JAXBElement 클래스에 대한 mixin 주석을 등록하여 반환 값을 JSON 표현으로 만들 수 있습니다. 다음은 그 예입니다.

    @JsonValue 주석을 JAXBElement.getValue () 메소드에 넣는 JAXBElement 클래스에 대한 mixin 주석을 등록하여 반환 값을 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>
    

    자바 메인 클래스 :

    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"
    }
    
  2. ==============================

    2.완전히 구성된 프로젝트의 예는 다음과 같습니다.

    완전히 구성된 프로젝트의 예는 다음과 같습니다.

    여기로가.

    필수적인 부분은 다음과 같습니다.

    MI 편지 :

    /**
     * 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>
    
  3. from https://stackoverflow.com/questions/24124149/how-to-json-marshal-jaxbelement-wrapped-responses-without-the-jaxbelement-wrappe by cc-by-sa and MIT license