0

I am porting an old application that runs on JBoss to Spring Boot/Tomcat and have most everything working except the response XML. The old code appears to be using xmlbeans for the XSD source generation. I've changed this to use JAXB. Here's my class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EventsResponseType1_1", propOrder = {
    "getAllEventCodesResponse",
    "saveEventCodeResponse",
    "failMessageResponse",
    "getEmailHistoryResponse"
})
public class EventsResponseType11 {

    protected GetAllEventCodesResponseType getAllEventCodesResponse;
    protected SaveEventCodeResponseType saveEventCodeResponse;
    @XmlElement(name = "FailMessageResponse")
    protected ResponseType failMessageResponse;
    protected GetEmailHistoryResponseType getEmailHistoryResponse;

    // Getters and setters
}

And one of the element classes:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getAllEventCodesResponseType", propOrder = {
    "_return",
    "results"
})
public class GetAllEventCodesResponseType {

    @XmlElement(name = "Return", required = true)
    protected ReturnType _return;
    @XmlElement(name = "Results")
    protected GetAllEventCodesResponseType.Results results;

    // Getters and setters
}

Here's the response XML:

<com.foo.bar.EventsResponseType11>
  <getAllEventCodesResponse>
      <__return>
         <returnCode>0</returnCode>
         <returnMessage />
      </__return>
      <results>
         <eventCodes>
            <com.foo.bar.EventCodeInfoType>
               <eventCodeID>1</eventCodeID>
               <eventCode>1000</eventCode>
               <eventCodeDesc>Success</eventCodeDesc>
               <eventCodeIndicator>SUCCESS</eventCodeIndicator>
               <eventCodeContext>General</eventCodeContext>
               <createdBy>system</createdBy>
            </com.foo.bar.EventCodeInfoType>
         </eventCodes>
      </results>
   </getAllEventCodesResponse>
</com.foo.bar.EventsResponseType11>

I have configured my application:

@SpringBootApplication
@ComponentScan("com.foo.bar")
public class WsApp extends WebMvcConfigurerAdapter{

    public static void main(String[] args) {
        SpringApplication.run(WsApp.class, args);
    }

    /**
     * Configure the XML as the only return type on requests
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.TEXT_XML);

        XStreamMarshaller xmlMarshaller = new XStreamMarshaller();

        MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(xmlMarshaller);
        xmlConverter.setSupportedMediaTypes(mediaTypes);

        converters.add(xmlConverter);

        super.configureMessageConverters(converters);
    }
}

And my controller:

@RestController
@RequestMapping("/go")
public class EventService { 
    @RequestMapping(value = "/events", method = RequestMethod.POST)
    public ResponseEntity<EventsResponseType11> events(@RequestBody EventsRequestType11 request){

        EventsResponseType11 responseDoc = eventCodesProxy.invoke(request);

        return ResponseEntity.ok(responseDoc);
    }
}

So my first question is, how can I stop the marshaller from including the package name on those elements that have it.

And second, since the XSD defines a field as "return" JAXB added an underscore to the field name. The @XmlElement annotation on that field identifies this as "Return" which is what I want on the response (without any underscores)

I've tried using a JAXB Marshaller in place of the XStreamMarshaller with no luck. If at all possible, I would opt not to modify the schema because it's old and has a lot of inter-department dependencies.

Thanks in advance for your help!

Bret Hodgson
  • 113
  • 1
  • 7
  • For starters stop using the `XStreamMarshaller` as that doesn't do anything with the JAXB annotations. What you now see is basically the default behavior of XStream. You should use the JAXB marshaller instead. – M. Deinum Feb 03 '17 at 10:09
  • While this does make sense, I had tried this approach with questionable results. I replaced the XStream marshaller with `Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();` `jaxb2Marshaller.setPackagesToScan("com.xsd.package");` and now the service is only returning JSON. Why? Since I configured my message converter to return ONLY XML I wouldn't have expected this. Also I added `@XmlRootElement` to my top level object `EventsResponseType11` with no luck. – Bret Hodgson Feb 03 '17 at 15:08
  • What is returned depends on the request and the requested return type. You shouldn't modify the generated classes as next time they will be gone again and you forget to add them. Just wrap the result in a `JAXBElement` instead of returning a plain `EventsResponseType11` return a `JAXBElement< EventsResponseType11>` instead . There is a method on the generated `ObjectFactory` which can do this for you. – M. Deinum Feb 05 '17 at 07:34
  • @M.Deinum see my solution below. I didn't have to modify my classes directly. I had to modify the schemas better to represent an element wrapper class, which is what you see as `EventsResponseType11`. So in a way I wrapped them in a `JAXBElement` via the schema. Returning that type is now appropriate as it adheres to the spec. – Bret Hodgson Feb 07 '17 at 01:32
  • You modified XSD and with that the contract (how small the change it is a change with a risk) simply wrapping it in the JAXBElement doesn't need a change and would simply make it work. – M. Deinum Feb 07 '17 at 06:38
  • @M.Deinum I should elaborate a bit. The XSD was only modified to change how the element is represented. Before, there was this declaration: `` where `EventsResponseType1_1` was represented as a complex type in the same schema. This complex type was intended to be used only for this element. What I did was put that complex type directly in the `` wrapper which gave me the @XmlRootElement annotation. Why this wasn't happening prior to this change I'm not sure. – Bret Hodgson Feb 07 '17 at 19:57

1 Answers1

0

So after a lot of trial and error, I stumbled upon this post:

Spring 4 mvc REST XML and JSON response

My application class:

@SpringBootApplication
@ComponentScan("com.foo.bar")
@EnableWebMvc
public class WsApp extends WebMvcConfigurerAdapter{

    public static void main(String[] args) {
        SpringApplication.run(WsApp.class, args);
    }

    /**
     * Configure the negotiator to return ONLY XML
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).
            favorParameter(true).
            parameterName("mediaType").
            ignoreAcceptHeader(true).
            useJaf(false).
            defaultContentType(MediaType.APPLICATION_XML).
            mediaType("xml", MediaType.APPLICATION_XML);
    }
}

I stated before that I wouldn't be too happy about modifying the XSDs, but I had to make a few tweaks to add the @XmlRootElement. I had tried to modify the JAXB source generation through additional libraries but that didn't work out so well.

Community
  • 1
  • 1
Bret Hodgson
  • 113
  • 1
  • 7