I am trying to parse an XML document which I got in a javax.ws.rs.core.Response
through a GET API Call made to a javax.ws.rs.client.Client
instance. But I get this error as shown below:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.fivetran.integrations.sage_intacct.model.AuditHistory` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('apbill')
at [Source: (StringReader); line: 1, column: 767] (through reference chain: com.fivetran.integrations.sage_intacct.model.AuditHistoryDataResponse["operation"]->com.fivetran.integrations.sage_intacct.model.AuditHistoryDataResponse$Operation["result"]->com.fivetran.integrations.sage_intacct.model.AuditHistoryDataResponse$Operation$Result["data"]->com.fivetran.integrations.sage_intacct.model.AuditHistoryDataResponse$Operation$Result$Data["audithistory"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1032)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1373)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:252)
at com.fasterxml.jackson.databind.deser.impl.InnerClassProperty.deserializeAndSet(InnerClassProperty.java:90)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:252)
at com.fasterxml.jackson.databind.deser.impl.InnerClassProperty.deserializeAndSet(InnerClassProperty.java:90)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:252)
at com.fasterxml.jackson.databind.deser.impl.InnerClassProperty.deserializeAndSet(InnerClassProperty.java:90)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
at com.fivetran.integrations.sage_intacct.SageIntacctApi.query(SageIntacctApi.java:95)
at com.fivetran.integrations.sage_intacct.SageIntacctUpdater.update(SageIntacctUpdater.java:32)
at com.fivetran.integrations.sage_intacct.SageIntacctService.update(SageIntacctService.java:65)
at com.fivetran.integrations.sage_intacct.SageIntacctService.update(SageIntacctService.java:11)
at com.fivetran.core.Service.update(Service.java:112)
at com.fivetran.scripts.RunMock.lambda$updateCore2$12(RunMock.java:408)
at com.fivetran.integrations.db.DbTimer.time(DbTimer.java:132)
at com.fivetran.scripts.RunMock.lambda$updateCore2$13(RunMock.java:404)
at java.lang.Thread.run(Thread.java:748)
Here is the XML received through the response which, I am trying to parse:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<control>
<status>success</status>
<senderid>****</senderid>
<controlid>****</controlid>
<uniqueid>false</uniqueid>
<dtdversion>3.0</dtdversion>
</control>
<operation>
<authentication>
<status>success</status>
<userid>****</userid>
<companyid>****</companyid>
<locationid></locationid>
<sessiontimestamp>2020-03-04T15:34:12+00:00</sessiontimestamp>
<sessiontimeout>2020-03-05T00:02:11+00:00</sessiontimeout>
</authentication>
<result>
<status>success</status>
<function>readByQuery</function>
<controlid>4ea65c74-6f5a-445d-afa4-193ddbc9e0b0</controlid>
<data listtype="audithistory" count="xxx" totalcount="xxx" numremaining="xxx" resultId="7765623331Xl-KdJcLu-MlRbvnEh3F@AAAAAc4">
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2695</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>04/30/2019 07:50:33</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.142</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2695:CXMf@QsGq23aoxHxufF1fLwAAABI</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2696</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>04/30/2019 07:50:33</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.142</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2696:CXMf@QsGq23aoxHxufF1fLwAAABI</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2697</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>05/01/2019 07:47:48</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.145</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2697:CXMlPI0DRiZxFRyT4zhOG6QAAABA</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2698</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>05/01/2019 07:47:48</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.145</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2698:CXMlPI0DRiZxFRyT4zhOG6QAAABA</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2703</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>05/13/2019 07:54:51</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.143</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2703:CXNkiyNsWQ4t5uGiof1TQpQAAABQ</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2711</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>05/31/2019 08:32:35</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.144</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2711:CXPDmoVV1YLVGVrbHHkQXoAAAAAY</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2712</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>05/31/2019 08:32:35</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.144</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2712:CXPDmoVV1YLVGVrbHHkQXoAAAAAY</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2713</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>06/01/2019 07:43:35</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.140</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2713:CXPIspoYfO8BxtOLDz7eNZgAAAAk</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
<audithistory>
<OBJECTTYPE>apbill</OBJECTTYPE>
<OBJECTKEY>2714</OBJECTKEY>
<USERID>admin</USERID>
<ACCESSTIME>06/01/2019 07:43:36</ACCESSTIME>
<ACCESSMODE>Create</ACCESSMODE>
<WORKFLOWACTION></WORKFLOWACTION>
<IPADDRESS>192.168.3.140</IPADDRESS>
<SOURCE>system</SOURCE>
<NOTES></NOTES>
<ID>apbill:2714:CXPIspoYfO8BxtOLDz7eNZgAAAAk</ID>
<ACTION_DETAILS></ACTION_DETAILS>
</audithistory>
</data>
</result>
</operation>
</response>
The POJOs which I have made in order to map the above XML.
AuditHistory.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "audithistory")
public class AuditHistory {
public String OBJECTTYPE;
public String OBJECTKEY;
public String USERID;
public String ACCESSTIME;
public String ACCESSMODE;
public String WORKFLOWACTION;
public String IPADDRESS;
public String SOURCE;
public String NOTES;
public String ID;
public String ACTION_DETAILS;
}
AuditHistoryDataResponse.java
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;
@JacksonXmlRootElement(localName = "response")
public class AuditHistoryDataResponse {
public Control control;
public Operation operation;
public class Control
{
public String status;
public String senderid;
public String controlid;
public String uniqueid;
public String dtdversion;
}
public class Operation
{
public Authentication authentication;
public Result result;
public class Result
{
public String status;
public String function;
public String controlid;
public Data data;
public class Data
{
@JacksonXmlProperty(isAttribute = true)
public String listtype;
@JacksonXmlProperty(isAttribute = true)
public String count;
@JacksonXmlProperty(isAttribute = true)
public String totalcount;
@JacksonXmlProperty(isAttribute = true)
public String numremaining;
@JacksonXmlProperty(isAttribute = true)
public String resultId;
public List<AuditHistory> audithistory;
}
}
public class Authentication
{
public String status;
public String userid;
public String companyid;
public String locationid;
public String sessiontimestamp;
public String sessiontimeout;
}
}
}
Code to make the API call and receive the response
public void query(SageIntacctEndpoint endpoint) {
MultivaluedMap<String, Object> headerParams = new MultivaluedHashMap<>();
headerParams.add("Accept", "application/xml");
headerParams.add("Content-Type", "application/xml");
//POJO that is used as the data that is passed as a part of the cURL request
DataRequest request = setupDataRequestPayload(endpoint);
try {
// MAPPER is the XmlMapper object
String XML = MAPPER.writeValueAsString(request);
Response response =
HTTP.target(API_URL)
.request(MediaType.APPLICATION_XML_TYPE)
.headers(headerParams)
.post(Entity.entity(XML, MediaType.APPLICATION_XML_TYPE));
AuditHistoryDataResponse xmlObject = MAPPER.readValue(response.readEntity(String.class), AuditHistoryDataResponse.class);
System.out.println ("Checkpoint");
} catch (Exception ex) {
ex.printStackTrace();
}
}
A brief explanation of the query
Routine: I am executing a cURL request using JAVA and sending XML as a string in the payload section.
The POJOs that I have shown may be different. All of them are public variables, there are no constructors, getters, and setters but they have been working for me so far until now I.e when there are multiple nodes of the same type as shown in the XML.
But what am I missing here? This is the first time I am looking into Jackson. Are there any annotations that I am missing or being wrongly used?
Couple of References that I looked into in an effort this problem:
- https://dzone.com/articles/parse-xml-to-java-objects-using-jackson
- https://www.baeldung.com/jackson-xml-serialization-and-deserialization
- http://pojo.sodhanalibrary.com/Convert (Used to create the POJOs that I am currently using sans the getters and setters)