tomaytotomato
tomaytotomato

Reputation: 4028

Spring MessageConverter HTTP 415 response?

I am wanting to use Spring MVC's MessageConverter to instantiate an object called IPNMessage . SDK link

Paypal IPN messages come in a text-plain format which I want to deserialize into IPNMessage object.

cmd=_notify-validate&payment_type=instant&payment_date=Fri Apr 08 2016 09:40:07 GMT+0100 (GMT Standard Time)&payment_status=Completed&address_status=confirmed&payer_status=verified&first_name=John&last_name=Smith&[email protected]&payer_id=TESTBUYERID01&address_name=John Smith&address_country=United States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San Jose&address_street=123 any street&[email protected]&[email protected]&[email protected]&residence_country=US&item_name1=something&item_number1=AK-1234&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=12.34&mc_gross_1=12.34&mc_handling=2.06&mc_handling1=1.67&mc_shipping=3.02&mc_shipping1=1.02&txn_type=cart&txn_id=297973429&notify_version=2.1&custom=xyz123&invoice=abc1234&test_ipn=1&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31A4TqrEbg4g7qEUK.b0lBrPhTpK8o

Message Convert Class:

    public class PaypalIPNHttpMessageConverter extends AbstractHttpMessageConverter<IPNMessage> {

    public PaypalIPNHttpMessageConverter() {
        super(new MediaType("application", "text-plain"), MediaType.ALL);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return false;
    }

    @Override
    protected IPNMessage readInternal(Class<? extends IPNMessage> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        //Converts HTTPRequest into map<string,string> that IPNMessage can then parse
        String requestString = IOUtils.toString(inputMessage.getBody(), "UTF-8");
        Map<String, String[]> requestMap = new LinkedHashMap<>();
        for (String keyValue : requestString.split("&")) { //each key value is delimited by &
            String[] pairs = keyValue.split("=", 2); // = pairs a key to a value
            requestMap.put(pairs[0], pairs[1].split(",")); // , splits multiple values for that key
        }
        return new IPNMessage(requestMap);
    }

    @Override
    protected void writeInternal(IPNMessage ipnMessage, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

    }
}

Config in servlet.xml

<bean class="com.kappa.PaymentController">
    <property name="delegate" ref="paymentService"/>
    <property name="paypalDelegate" ref="paypalIPNService"/>
    <property name="messageConverter" ref="paypalIPNHttpMessageConverter"/>
</bean>

Controller Endpoint

    @Override
@Auditable
@RequestMapping(value = "/processPaypalIPNRequest.do", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void processPaypalIPNRequest(@RequestBody IPNMessage ipnMessage) {
    paypalDelegate.processPaypalIPNRequest(ipnMessage);
}

When I fire a POST request I get a HTTP 415 saying my request body is not supported.

Am I missing further configuration of Spring?

Note: I placed break points in the message converter class but they are not reached, so this problem is occurring higher up, Not sure where though.

Upvotes: 1

Views: 180

Answers (2)

tomaytotomato
tomaytotomato

Reputation: 4028

The issue was to do with the supports() method in the MessageConverter, not evaluating the class signature is the same as IPNMessage (that it is producing).

@Override
protected boolean supports(Class<?> clazz) {
    return clazz == IPNMessage.class;
}

This was causing Spring to throw HTTP415 errors at a higher level before it reached the controller.

Upvotes: 0

a better oliver
a better oliver

Reputation: 26838

IPNMessage has a constructor that expects a request. So the easiest solution would be to change your method like this:

public void processPaypalIPNRequest(HttpServletRequest request) {
  paypalDelegate.processPaypalIPNRequest(new IPNMessage(request));
}

If you want your own message converter then it ideally would also do new IPNMessage(request).

Upvotes: 2

Related Questions