7

I am trying to go from XSD->POJO->JSON for use with UPS tracking API which is case sensitive. I'm using Jackson 2.6.7 In the generated JSON. I am seeing camel case names when I should see below:

"TrackRequest": { "InquiryNumber": "1Z12345E6205277936" }

The generated Java bean is annotated like so:

@XmlElement(name = "TrackRequest")
protected TrackRequest trackRequest;

I've tried a few mapping feature settings such as USE_WRAPPER_NAME_AS_PROPERTY_NAME and USE_STD_BEAN_NAMING which don't appear to have the desired result.

I'm generating the JSON like so:

ObjectMapper mapper = new ObjectMapper();
String jsonRequest = mapper.writeValueAsString(upsRequest);

The upsRequest bean looks like this:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "upsSecurity",
    "trackRequest"
})
@XmlRootElement(name = "Request")
public class Request {

    @XmlElement(name = "UPSSecurity")
    protected UPSSecurity upsSecurity;
    @XmlElement(name = "TrackRequest")
    protected TrackRequest trackRequest;

    /**
     * Gets the value of the upsSecurity property.
     * 
     * @return
     *     possible object is
     *     {@link UPSSecurity }
     *     
     */
    public UPSSecurity getUPSSecurity() {
        return upsSecurity;
    }

    /**
     * Sets the value of the upsSecurity property.
     * 
     * @param value
     *     allowed object is
     *     {@link UPSSecurity }
     *     
     */
    public void setUPSSecurity(UPSSecurity value) {
        this.upsSecurity = value;
    }

    /**
     * Gets the value of the trackRequest property.
     * 
     * @return
     *     possible object is
     *     {@link TrackRequest }
     *     
     */
    public TrackRequest getTrackRequest() {
        return trackRequest;
    }

    /**
     * Sets the value of the trackRequest property.
     * 
     * @param value
     *     allowed object is
     *     {@link TrackRequest }
     *     
     */
    public void setTrackRequest(TrackRequest value) {
        this.trackRequest = value;
    }

}

According to the docs, I should be getting the desired output unless I'm missing something

Half_Duplex
  • 5,102
  • 5
  • 42
  • 58
  • 1
    You could always try adding JSON annotations too, e.g. `@JsonProperty("TrackRequest")`. If it doesn't work on the field, try on the getter method instead. – Andreas May 07 '17 at 19:52
  • I gave that a try previously, it did create the desired property but the other undesired property was still created. – Half_Duplex May 07 '17 at 22:24

3 Answers3

24

JAXB annotations are not by default supported. You need to add the jackson-module-jaxb-annotations module and then register that with the ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • This worked. ObjectMapper now names properties exactly how specified in the annotation with no other features configured. – Half_Duplex May 08 '17 at 14:23
  • Follow up: In the response XSD I have a complex type defined, but in the JSON response that property comes in as an empty string. Is there a config feature to handle that or should I modify my XSD? – Half_Duplex May 08 '17 at 18:20
  • Its' been a while since I've worked with XSDs, so I'm not quite sure what you're talking about. One thing to note though is that Jackson doesn't support all JAXB annotations. See [this](http://fasterxml.github.io/jackson-module-jaxb-annotations/javadoc/2.2.0/com/fasterxml/jackson/module/jaxb/JaxbAnnotationIntrospector.html) – Paul Samsotha May 08 '17 at 18:37
0

As mentioned in a comment, add @JsonProperty to the fields.

It works fine for me, using Jackson 2.7.0:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "trackRequest" })
@XmlRootElement(name = "Request")
class Request {

    @XmlElement(name = "TrackRequest")
    @JsonProperty("TrackRequest")
    private TrackRequest trackRequest;

    public Request() {
    }
    public Request(TrackRequest trackRequest) {
        this.trackRequest = trackRequest;
    }
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "inquiryNumber" })
class TrackRequest {

    @XmlElement(name = "InquiryNumber")
    @JsonProperty("InquiryNumber")
    private String inquiryNumber;

    public TrackRequest() {
    }
    public TrackRequest(String inquiryNumber) {
        this.inquiryNumber = inquiryNumber;
    }
}

Test

Request upsRequest = new Request(new TrackRequest("1Z12345E6205277936"));
Marshaller marshaller = JAXBContext.newInstance(Request.class).createMarshaller();
marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
marshaller.marshal(upsRequest, System.out);
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.writeValue(System.out, upsRequest);

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Request>
    <TrackRequest>
        <InquiryNumber>1Z12345E6205277936</InquiryNumber>
    </TrackRequest>
</Request>
{
  "TrackRequest" : {
    "InquiryNumber" : "1Z12345E6205277936"
  }
}

Both XML and JSON output is using PascalCase.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • This works and I did get the desired output with this annotation, however I prefer to stick with the JAXB annotations I'm familiar with. – Half_Duplex May 08 '17 at 14:24
0

To use this functionality to read the @JsonProperty and the XmlElement in spring-boot and its Jackson2ObjectMapperBuilder, you easily create a Bean to get the Builder everytime you need.

@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    //configure features for serialization and deserialization
    return builder;
}

You can now autowire the builder and configure the ObjectMapper directly there where you need it:

@Component
public class MyClass {

    private ObjectMapper objectMapper;

    public MyClass(Jackson2ObjectMapperBuilder jacksonBuilder) {
        super();
        objectMapper = jacksonBuilder.build().registerModule(new JaxbAnnotationModule());
    }

    public String serialize(){
        AnyObject ao = new AnyObject();
        String json = objectMapper.writeValueAsString(ao);
        return json;
    }
}
Patrick
  • 12,336
  • 15
  • 73
  • 115