Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AJAX JSONP with Jersey / JAX-RS Restful service

I've read a lot of questions on stackoverflow but i've not got solution to my problem.

This is my Restful service:

@GET
@Path("/GetAllProducts")
@Produces(MediaType.APPLICATION_JSON)
public String getAllProducts() {        
    return  "{\"name\":\"MAC\", \"quantity\":\"10\"}";
}

It works fine on browser but when i used AJAX, it didn't display errors but showed a popup: Failed object[Object]

And my AJAX code:

$.ajax({
    url: "http://localhost:8080/Restful/REST/WebService/GetAllProducts",
    type: 'GET',
    contentType: "application/json; charset=utf-8",
    dataType: "jsonp",
    success: function() { 
        alert("Success"); 
    },
    error: function(e) { 
        alert('Failed! ' + e); 
    }
});

I tried to add: "crossDomain: true" but it didn't work.

Please help me! Thanks!

like image 632
Trong Lam Phan Avatar asked Mar 18 '23 17:03

Trong Lam Phan


1 Answers

First let me explain some ways we could debug this..

We could...

  • Change the error function in the AJAX call. The first argument is actually the jqHXR object, not the error message. The arguments actually go jqhxr, status, errorMsg. So if we used the function:

    error: function(jqxhr, status, errorMsg) {
        alert('Failed! ' + errorMsg);
    }
    

    we would see this alert:

    enter image description here

    Doesn't really help in this case if you don't know what it means, but sometimes it's helpful.

We could...

  • Check the server log

    In this case the server log doesn't show any errors meaning the request was processed successfully and the response was returned.

We could...

  • Use a browser development tool. For Firefox, you should install Firebug. You can see the request and all the headers and such

enter image description here

You can see the request is being made with a callback query parameter. Also pay close attention to the Accept header, which reads application/javascript

Chrome has the same type of tool, and AFAIK, it is built in, and you can find it under Developer Tools.

That being said..

There error comes from the dataType setting in your AJAX request. JSONP is not the same a JSON. JSONP is Javascript code sent back from the server that is meant to be processed by the front end. So jQuery is expecting JSONP format, that's why it set's the headers the application/javascript and that's why the "Syntax Error" message, as JSON format is not the same syntax as JSONP.

So to fix it, you just simply need to set the dataType as json

dataType: "json",
success: function(data) {
    alert("Success: " + JSON.stringify(data));
},

Now you will see a few things:

  1. The Success message of course:

    enter image description here

  2. The request is no longer being made with the callback query parameter, as that is only for the JSONP protocol.

    enter image description here

  3. The Accept headers now use application/json

    enter image description here


Just an FYI, contentType sets the Content-Type header. That is only useful when we are sending information, say in a POST request.


UPDATE

Just for completeness:

I'm not sure if you were expecting JSONP outoup, but if you were, one thing you need to know is that JSONP support is not standard in JAX-RS. It dependends on the JAX-RS implementation, how you will need to configure the support.

First here's how your AJAX request should change to: (or something similar)

$.ajax({
    url: "http://localhost:8080/Restful/REST/WebService/GetAllProducts",
    type: 'GET',
    jsonp: 'callback',
    dataType: "jsonp",
    success: function(data) {
        alert("Success: " + JSON.stringify(data));
    },
    error: function(jqxhr, status, errorMsg) {
        alert('Failed! ' + errorMsg);
    }
});

With JSONP, the request will look something like url?callback=someFunctionToCall, where someFunctionToCall is what the server wraps around the JSON, and is the name of the our Javascript function we want to be invoked. So the return response might look something like:

someFunctionToCall({"name":"MAC", "quantity":"10"})

With jQuery though, we don't need to send the callback query parameter. Its value will be made at random. When I tested, this was the request and response:

// request
.../GetAllProducts?callback=jQuery20302583482212586644_1418019088133
// response
jQuery20302583482212586644_1418019088133({"name":"MAC", "quantity":"10"})

On return of the response, our success function will be called, passing in the data, as would a normal response. The above AJAX request will alert the exact same message as above.

Support for Resteasy

With Reasteasy (3.x.x at least), we should first have the Resteasy Jackson provider

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jackson2-provider</artifactId>
    <scope>provided</scope>
</dependency>

All we need to do is add the JSONP interceptor to our deployment

org.jboss.resteasy.plugins.providers.jackson.JacksonJsonpInterceptor

I haven't gotten the exact science down of which media types need to be added for this support, but I tested with

@Produces({"text/javascript","application/javascript", "application/json"})

For Jersey 2.x

Jersey comes with built in support for JSONP, so we don't need any other dependencies, from the default distribution. We just need to add the @JSONP annotation.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.glassfish.jersey.server.JSONP;

@Path("/WebService")
public class ProductsResource {

    @GET
    @Path("/GetAllProducts")
    @Produces({"application/json", "application/javascript"})
    @JSONP(queryParam = "callback")
    public String getAllProducts() {
        return "{\"name\":\"MAC\", \"quantity\":\"10\"}";
    }
}

Using the same jQuery code as above, will give the same result. See more at JSON with Padding Support

like image 155
Paul Samsotha Avatar answered Mar 20 '23 06:03

Paul Samsotha