0

Java 8, Spring 5.x

Given

ResponseEntity<Object> responnse = restTemplate.exchange( myUrl, HttpMethod.GET, reqquest, Object.class);

returns some XML

<LinkedHashMap>
  <Entity>
    <name>Person</name>
    <href>../12345</href>
    <Attribute>
      <name>lastName</name>
      <type>String</type>
      <value>Nixon</value>
    </Attribute>
    <Attribute>
      <name>firstName</name>
      <type>String</type>
      <value>Dick</value>
     </Attribute>
   </Entity>
 </LinkedHashMap>

and

@JsonIgnoreProperties(ignoreUnknown=true)
@JacksonXmlRootElement(localName="Person")
@Entity
public class Person implements java.io.Serializable {

    private static final long serialVersionUID = 123456789L;

    @Id
    private Long id;
    private String lastName;
    private String firstName;
    ...
}

how do I adjust this to where I can

if( responnse.hasBody()){
    Person person = xmlMapper.readValue( responnse.getBody(), Person.class);
    ...
}

I'm think xmlMapper needs some customizing to handle the id, at the least.

TIA,

Still-struggling Steve

code_warrior
  • 77
  • 10

1 Answers1

0

I don't know if there is elegant and general solution, but you can create custom deserializer, where you manually traverse the XML and populate Person class:

class PersonDeserializer extends StdDeserializer<Person> {

    protected PersonDeserializer() {
        super(Person.class);
    }

    @Override
    public Person deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Person result = new Person();
        do {
            String value = p.getText();

            if (value.equals("Attribute")) {
                p.nextToken(); // {
                p.nextToken(); // name
                p.nextToken(); // <attrName>

                String propertyName = p.getText();

                if (propertyName.equals("lastName")) {
                    p.nextToken(); // type
                    p.nextToken(); // String
                    p.nextToken(); // value
                    p.nextToken(); // <attrValue>
                    result.setLastName(p.getText());
                } else if (propertyName.equals("firstName")) {
                    p.nextToken(); // type
                    p.nextToken(); // String
                    p.nextToken(); // value
                    p.nextToken(); // value=<attrProperty>
                    result.setFirstName(p.getText());
                }
            } else if (value.equals("href")) {
                p.nextToken(); // value
                String href = p.getText();
                Long id = Long.parseLong(href.replaceAll("\\D", "")); // "../12345" => "12345"
                result.setId(id);
            }

            p.nextToken();

        } while (p.hasCurrentToken());

        return result;
    }
}

and then call like this

XmlMapper mapper = new XmlMapper();
SimpleModule module = new SimpleModule("xmlPersonModule");
module.addDeserializer(Person.class, new PersonDeserializer());
mapper.registerModule(module);

String xml = """
        <LinkedHashMap>
          <Entity>
            <name>Person</name>
            <href>../12345</href>
            <Attribute>
              <name>lastName</name>
              <type>String</type>
              <value>Nixon</value>
            </Attribute>
            <Attribute>
              <name>firstName</name>
              <type>String</type>
              <value>Dick</value>
             </Attribute>
           </Entity>
         </LinkedHashMap>
        """;

Person person = mapper.readValue(xml, Person.class);
System.out.println(person);

Output:

Person(id=12345, lastName=Nixon, firstName=Dick)

P.S. This is ugly and non-flexible solution, which will fail when given XML structure gets changed but... it just works :)

Nikolai Shevchenko
  • 7,083
  • 8
  • 33
  • 42