javaxmljaxbjackson-databindjackson-dataformat-xml

jaxb - deserializing list of pojo with unbounded list inside


I hava a xml response like below:

<out>
<documentsInfoByClaimNumber>

               <caseId>654321</caseId>

               <documentDetails>

                  <documentId>123456</documentId>

                  <documentSource>brahbrah</documentSource>

                  <category>brahbrah</category>

                  <documentType>brahbrah</documentType>

                  <documentName>brahbrah.brah</documentName>

                  <createdDate>2020-06-22T17:00:25</createdDate>

               </documentDetails>

</documentsInfoByClaimNumber>
</out>

both documentsInfoByClaimNumber and documentDetails are unbounded list, could appear once or more

below are my pojos, I'm using lombok: jackson XmlMapper for parsing, with jaxb annotations

@Data
@NoArgsConstructor
@XmlRootElement(name = "getDocumentInfoByClaimNumberResponse")
@XmlAccessorType(XmlAccessType.FIELD)
public class GetDocumentInfoByClaimNumberRes {
    @XmlElementWrapper(name = "out")
    @XmlElement(name = "documentsInfoByClaimNumber")
    private List<Wrapper> out;

    @Data
    public static class Wrapper{
        private int caseId;

//        private DocumentDetails documentDetails;  without list it works
        @XmlElement(name="documentDetails")
        private List<DocumentDetails> documentDetails;
    }
}
@Data
public class DocumentDetails {
    private String documentId;
    private String documentSource;
    private String category;
    private String documentType;
    private String documentName;
    private LocalDateTime createdDate;
}

the problem is, with documentDetails only appear once, I got something like

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.service.casetrack.payload.DocumentDetails` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('123456')
(through reference chain: GetDocumentInfoByClaimNumberRes["out"]->java.util.ArrayList[1]->GetDocumentInfoByClaimNumberRes$Wrapper["documentDetails"]->java.util.ArrayList[0])

I can deserialize it without using List, but thus I can't deal with two or more elements. Any tricks for this?


Solution

  • check below .. i wish that is help for you

    package xml;
    
    import java.time.LocalDateTime;
    import java.util.List;
    
    import org.junit.Test;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.dataformat.xml.XmlMapper;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModule;
    
    import jakarta.xml.bind.annotation.XmlAttribute;
    import jakarta.xml.bind.annotation.XmlElement;
    import jakarta.xml.bind.annotation.XmlRootElement;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class stackOverFlowTest {
    
        @Test
        public void test01() throws JsonMappingException, JsonProcessingException {
            StringBuffer xml = new StringBuffer()
                    .append("<out>")
                    .append("   <documentsInfoByClaimNumber name=\"first\">")
                    .append("      <caseId>654321</caseId>")
                    .append("      <documentDetails>")
                    .append("         <documentId>123456</documentId>")
                    .append("         <documentSource>brahbrah</documentSource>")
                    .append("         <category>brahbrah</category>")
                    .append("         <documentType>brahbrah</documentType>")
                    .append("         <documentName>brahbrah.brah</documentName>")
                    .append("         <createdDate>2020-06-22T17:00:25</createdDate>")
                    .append("      </documentDetails>")
                    .append("   </documentsInfoByClaimNumber>")
                    .append("   <documentsInfoByClaimNumber name=\"secode\">")
                    .append("      <caseId>654321</caseId>")
                    .append("      <documentDetails>")
                    .append("         <documentId>123456</documentId>")
                    .append("         <documentSource>brahbrah</documentSource>")
                    .append("         <category>brahbrah</category>")
                    .append("         <documentType>brahbrah</documentType>")
                    .append("         <documentName>brahbrah.brah</documentName>")
                    .append("         <createdDate>2020-06-22T17:00:25</createdDate>")
                    .append("      </documentDetails>")
                    .append("   </documentsInfoByClaimNumber>")
                    .append("</out>");
    
            XmlMapper xmlMapper = XmlMapper.builder().defaultUseWrapper(false)
                    .addModule(new JakartaXmlBindAnnotationModule())
                    .disable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
                    .addModule(new JavaTimeModule())
                    .build();
    
            GetDocumentInfoByClaimNumberRes result = xmlMapper.readValue(xml.toString(),
                    GetDocumentInfoByClaimNumberRes.class);
    
            result.getDocumentsInfoByClaimNumber().forEach(f -> {
                log.info("name={} caseId={} list=>{}", f.getName(), f.getCaseId(), f.getDocumentDetails().toString());
            });
            // log.info("result=>{}", result.toString());
    
        }
    
        @Data
        @NoArgsConstructor
        @ToString
        @XmlRootElement(name = "out")
        static class GetDocumentInfoByClaimNumberRes {
            @XmlAttribute
            private String name;
    
            @XmlElement(name = "documentsInfoByClaimNumber")
            private List<DocumentsInfoByClaimNumber> documentsInfoByClaimNumber;
        }
    
        @Data
        @ToString
        @NoArgsConstructor
        static class DocumentsInfoByClaimNumber {
            @XmlAttribute
            private String name;
    
            @XmlElement
            private String caseId;
    
            @XmlElement(name = "documentDetails")
            private List<DocumentDetails> documentDetails;
        }
    
        @Data
        @ToString
        @NoArgsConstructor
        static class DocumentDetails {
            private String documentId;
            private String documentSource;
            private String category;
            private String documentType;
            private String documentName;
            private LocalDateTime createdDate;
        }
    
    }
    

    result

    11:03:20 INFO  [main] xml.stackOverFlowTest - name=first caseId=654321 list=>[stackOverFlowTest.DocumentDetails(documentId=123456, documentSource=brahbrah, category=brahbrah, documentType=brahbrah, documentName=brahbrah.brah, createdDate=2020-06-22T17:00:25)]
    11:03:20 INFO  [main] xml.stackOverFlowTest - name=secode caseId=654321 list=>[stackOverFlowTest.DocumentDetails(documentId=123456, documentSource=brahbrah, category=brahbrah, documentType=brahbrah, documentName=brahbrah.brah, createdDate=2020-06-22T17:00:25)]