Exception occurs while parsing seemingly valid XML in Spring’s Web Client [closed]

The problem is that I’m trying to request some API, and it’s response body has xml content that is for some reason not being parsed at all. You may skip ahead by not double-checking whether I matched the elements’ names in xml correctly according to the target class, because I’m pretty sure this is not the problem
Here’s an example response:

<?xml version="1.0" encoding="utf-8"?><OperationStateResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://merchant.roboxchange.com/WebService/"><Result><Code>0</Code></Result><State><Code>10</Code><RequestDate>2023-09-03T22:34:33.6440213+03:00</RequestDate><StateDate>2023-09-01T15:53:38.1766667+03:00</StateDate></State><Info xsi:type="OperationInfoExt"><IncCurrLabel>BankCardPSBR</IncCurrLabel><IncSum>100.000000</IncSum><IncAccount>553691******5490</IncAccount><PaymentMethod><Code>BankCard</Code><Description>Банковской картой</Description></PaymentMethod><OutCurrLabel>BNR</OutCurrLabel><OutSum>100.000000</OutSum><OpKey>0296FAD0-7D7B-4DC0-99FE-A6064335A29C-Rf4RYsTRWZ</OpKey></Info><UserFields /></OperationStateResponse>

This is unformatted version, and there’s a formatted one:

<?xml version="1.0" encoding="utf-8"?>
<OperationStateResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://merchant.roboxchange.com/WebService/">
    <Result>
        <Code>0</Code>
    </Result>
    <State>
        <Code>10</Code>
        <RequestDate>2023-09-03T22:34:33.6440213+03:00</RequestDate>
        <StateDate>2023-09-01T15:53:38.1766667+03:00</StateDate>
    </State>
    <Info xsi:type="OperationInfoExt">
        <IncCurrLabel>BankCardPSBR</IncCurrLabel>
        <IncSum>100.000000</IncSum>
        <IncAccount>553691******5490</IncAccount>
        <PaymentMethod>
            <Code>BankCard</Code>
            <Description>Банковской картой</Description>
        </PaymentMethod>
        <OutCurrLabel>BNR</OutCurrLabel>
        <OutSum>100.000000</OutSum>
        <OpKey>0296FAD0-7D7B-4DC0-99FE-A6064335A29C-Rf4RYsTRWZ</OpKey>
    </Info>
    <UserFields />
</OperationStateResponse>

In order to make this xml decodable into an object of my class, I used annotations from jakarta.xml.bind.annotation, such as @XmlRootElement. Here’s the gist of the class:

@XmlRootElement(name = "OperationStateResponse", namespace = "http://merchant.roboxchange.com/WebService/")
@NoArgsConstructor
public class OperationStateResponseBody implements Serializable {

    private Result result;

    private State state;

    @XmlElement(name = "Result")
    public Result getResult() {
        return this.result;
    }

    @XmlElement(name = "State")
    public State getState() {
        return this.state;
    }
    
    public static class State {
        ...
        // fields declared in the same manner as in the outer class
    }

    public static class Result {
        ...
        // fields declared in the same manner as in the outer class
    }

    // other not related stuff

}

What I invite you to notice is that I’ve added the namespace parameter to the @XmlRootElement annotation. Without it, no exception occurs, but the mapped response object is empty (fields are null). On top of that, if you follow the link, you’re gonna see that it gives an 403, what I think might be the problem here.
If I remove the parameter, I receive this error:

Caused by: org.springframework.core.codec.DecodingException: Could not unmarshal XML to class ru.kotomore.excursionapi.services.dto.OperationStateResponseBody
Caused by: jakarta.xml.bind.UnmarshalException: null
Caused by: com.sun.istack.SAXParseException2: unexpected element (uri:"http://merchant.roboxchange.com/WebService/", local:"OperationStateResponse"). Expected elements are <{}OperationStateResponse>

So what I’ve tried doing is:

  1. Removing namespace parameter in @XmlRootElement annotation, which didn’t give desired outcome. Exception gone, but mapped object is empty
  2. Changing @XmlRootElement annotation and all related ones to @Jackson… analogies. This way web client fails to recognize the target class as mappable at all. The reason is that apparently Spring does not support @Jackson… annotations in Spring (I am not stating this, but that’s my take that I’ve read from some other answer on Stackoverflow).

I’m guessing there has to be some way of simply ignoring the namespace given in the xml, but of course I don’t know whether it’s the case. I’ve been scratching my head all day long trying to solve this problem, it’s the last step to have my job project done, please help 🙁

EDIT:
Sorry, forgot to add the web client request code:

webClient.get()
                     .uri(uriBuilder -> uriBuilder.scheme(HttpScheme.HTTPS.toString())
                                                  .host("auth.robokassa.ru")
                                                  .path("/Merchant/WebService/Service.asmx/OpStateExt")
                                                  .queryParam(
                                                          "MerchantLogin",
                                                          paymentServiceConfigurationProperties.getMerchantName())
                                                  .queryParam("invoiceID", invoice.getId())
                                                  .queryParam("Signature", invoice.getSignature2())
                                                  .build())
                     .accept(MediaType.TEXT_XML)
                     .retrieve()
                     .bodyToMono(OperationStateResponseBody.class)
                     .subscribe(r -> invoiceStatusHandler(invoice, r));

  • 1

    You say that the problem is that an API gives an XML response. This is not a problem; it’s a situation. Reading further down I find a reference to an exception, and a 403 response, which is ‘Forbidden’, but the problem is buried in amongst parts you invite me not to read, and something that appears to be an authentication failure. Needs clarity, I think.

    – 

  • @TangentiallyPerpendicular Yeah, I’ll clarify the beginning to describe the problem better. The error that the program generated points at attribute from root element, that’s why I’m thinking the content of the xml doesn’t matter. On top of that, I obviously tried asking ChatGPT about the problem, so the target class is generated by it. By taking a glance at the class, I didn’t notice any noticeable issues, and the error that the program gives makes me think that parsing process stops once it hits the root element

    – 

  • @TangentiallyPerpendicular I might be wrong, but 403 in this case is a nonsensical response code for namespace URI, since it has to be publicly accessible (correct me, if I’m wrong). And even if it doesn’t there’s no way I can configure xml parsers to use some kind of authentication just to receive the namespace info

    – 

  • I refer you to this page on the use of ChatGPT to generate content for use on Stack Overflow. Specifically the first two paragraphs: “All use of generative AI (e.g., ChatGPT1 and other LLMs) is banned when posting content on Stack Overflow. This includes ‘asking’ the question to an AI generator then copy-pasting its output…”

    – 




  • @TangentiallyPerpendicular I didn’t use the code generated by ChatGPT entirely and without any thought process. I replaced the code of my class to see that it doesn’t have any meaningful difference, and it doesn’t. This post doesn’t contain any unprocessed and “copypasted” ChatGPT-generated content. On top of that, the piece of code that I’ve pointed out to be generated by ChatGPT is extremely simple and doesn’t matter at all

    – 

Leave a Comment