Jersey Client API

Yesterday i finished refactoring the Jersey Client API and sprinkling it with some JavaDoc. This API was originally being used for Jersey unit testing but i think it is applicable in the larger context of a general RESTful client API.

With some HTTP-based client APIs you have to do a lot of crufty work to make even the simplest request and process a response. In addition they do not really capture the concept of resources and the uniform interface. I think this may be one reason why client-side code generation for creating a 'proxy' to a HTTP-based service is more prevalent than i think it should be. With this client API it is very easy to produce requests and consume responses with resources and the uniform interface at the fore of the API. Hopefully if you play with this API you will see how easy it is to use and why code-generation (and in general relying statically on specific server-side artifacts) is of less importance in this respect.

At the end of this blog is a complete example showing the basic features of the client-side API. This works with the latest Jersey 0.6 build. It contains a resource, called PropertiesResource, a message body reader/writer for reading and writing properties, and some client code in the Main.run method. When this code is executed it should complete successfully with no exception thrown. The example tests simple create, read, update and delete of properties where the server is in control of the property names and the client chooses the property values.

Let's go through the statements of the Main.run method.

Setting up the client:

ClientConfig cc = new DefaultClientConfig();
cc.getProviderClasses().add(PropertiesProvider.class);
Client c = Client.create(cc);

The client can utilize message body readers and writers just like the server-side (in addition to IoC frameworks). I have yet to implement the client-scanning parts so for now it is necessary to explicitly register readers and writers.

Create a resource proxy to the properties resource:

ResourceProxy pResource = c.proxy("http://localhost:9998/");

Now we can start calling methods on the resource proxy:

Properties p = pResource.get(Properties.class);
assertTrue(p.size() == 0);

A GET request should return a Properties instance that has no properties. Notice how the HTTP method is used a bit like RMI but since the interface is uniform it never varies for standard HTTP-based resources. Like the server-side the client side can easily avail of Java types for representations.

Creating a new property resource:

ClientResponse cr = pResource.
  type("text/plain").
  post(ClientResponse.class, "some stuff");
assertTrue(cr.getStatus() == 201);

A POST method is called on the properties resource. The builder pattern is used to set the content type of the request (it is possible for the client to specify what is acceptable using the accept method) and the post method is invoked with the requested return type and the request entity (a String instance). The status code of the response should be 201 (Created). Notice that the client can choose to get all the response information or the representation previously shown for the GET request. The same methods are used as it is the return type that specifies such behavior.

Verify the created property resource: 

ResourceProxy vResource = c.proxy(cr.getLocation());
String content = vResource.get(String.class);
assertTrue("some stuff".equals(content)); 

The response to the POST request (if successful) will contain the location to the newly created property resource. This can be used to create a new resource proxy. A get method is called on that resource proxy and it should return the same information that was POSTed.

Verify the contents of the created property resource are also present in the properties resource:

p = pResource.get(Properties.class);
assertTrue(p.size() == 1);
assertTrue(p.contains("some stuff"));

Delete the created resource:

try {
    vResource.delete();
} catch (UniformInterfaceException e) {
    assertTrue(false);
}

The DELETE method on the property resource is invoked. In this case the client does not send anything and does not request a response. If something other than a successful response occurs an exception will be thrown.

Verify that the property resource has been deleted: 

try {
    content = vResource.get(String.class);
} catch (UniformInterfaceException e) {
    assertTrue(e.getResponse().getStatus() == 404);
}

In this case we expect an exception to be thrown. The ClientResponse can be obtained from the exception to check the status code, which should be 404 (Not Found). But we can also do it like this if we wish:

cr = vResource.get(ClientResponse.class);
assertTrue(cr.getStatus() == 404);

So it is possible to verify the status code explicitly or work under the assumption that success is the norm and errors are the exception.

Hopefully that gives you a flavor of how to use the API from a resource and uniform interface perspective. Given the recent blogs on Jersey and Abdera (see here and here) it should be easy to apply Abdera on the Jersey client side as it was on the server side.

If you want you can still build client requests independently and pass them to the Client instance. You can also add filters for say performing authentication. There is a lot that still can be done. For example, a client requesting a CreatedResponse could verify the status code and location header and throw an exception if it does not conform. Asynchronous requests may be possible by the client requesting say Future<String> or Future<ClientResponse>. I already have a feature request to add request/response progress listeners. Since services may be clients too there is lots of opportunity for such clients to share resources with the server making things more efficient and scalable. So much to do! If you would like to help out just contact me :-)


import com.sun.net.httpserver.HttpServer;
import com.sun.ws.rest.api.client.Client;
import com.sun.ws.rest.api.client.ClientResponse;
import com.sun.ws.rest.api.client.ResourceProxy;
import com.sun.ws.rest.api.client.UniformInterfaceException;
import com.sun.ws.rest.api.client.config.ClientConfig;
import com.sun.ws.rest.api.client.config.DefaultClientConfig;
import com.sun.ws.rest.api.container.httpserver.HttpServerFactory;
import com.sun.ws.rest.spi.resource.Singleton;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Properties;
import java.util.UUID;
import javax.ws.rs.ConsumeMime;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ProduceMime;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

public class Main {

    @ProduceMime("text/plain")
    @Provider
    public static class PropertiesProvider implements
            MessageBodyWriter<Properties>,
            MessageBodyReader<Properties> {

        public void writeTo(Properties p, MediaType mediaType,
                MultivaluedMap<String, Object> headers, OutputStream out)
                throws IOException {
            p.store(out, null);
        }

        public boolean isWriteable(Class<?> type) {
            return Properties.class.isAssignableFrom(type);
        }

        public long getSize(Properties p) {
            return -1;
        }

        public boolean isReadable(Class<?> type) {
            return Properties.class.isAssignableFrom(type);
        }

        public Properties readFrom(Class<Properties> type, MediaType mediaType,
                MultivaluedMap<String, String> headers, InputStream in)
                throws IOException {
            Properties p = new Properties();
            p.load(in);
            return p;
        }
    }
   
    @Path("/")
    @ProduceMime("text/plain")
    @ConsumeMime("text/plain")
    @Singleton
    public static class PropertiesResource {
        @HttpContext UriInfo uriInfo;
       
        Properties p = new Properties();
       
        @GET public Properties get() {
            return p;
        }
       
        @POST public Response post(String in) {
            String id = UUID.randomUUID().toString();
           
            p.setProperty(id, in);
           
            URI u = uriInfo.getAbsolutePathBuilder().path(id).build();
            return Response.created(u).build();
        }
       
        @Path("{id}") @GET public synchronized String getContent(
                @PathParam("id") String id) {
            String content = p.getProperty(id);
            if (content == null) throw new WebApplicationException(404);
           
            return content;
        }
       
        @Path("{id}") @PUT public synchronized void updateContent(
                @PathParam("id") String id) {
            String content = p.getProperty(id);
            if (content == null) throw new WebApplicationException(404);
           
            p.setProperty(id, content);
        }
       
        @Path("{id}") @DELETE public synchronized void deleteContent(
                @PathParam("id") String id) {
            String content = p.getProperty(id);
            if (content == null) throw new WebApplicationException(404);
           
            p.remove(id);
        }
    }
   
    public static void run() throws Exception {
        // Create the client
        ClientConfig cc = new DefaultClientConfig();
        // Include the properties provider
        cc.getProviderClasses().add(PropertiesProvider.class);
        Client c = Client.create(cc);
       
        // Create the resource proxy to the resource
        ResourceProxy pResource = c.proxy("http://localhost:9998/");
       
        // Get the current properties and verify it is empty
        Properties p = pResource.get(Properties.class);       
        assertTrue(p.size() == 0);
       
        // Create a new property
        ClientResponse cr = pResource.
                type("text/plain").
                post(ClientResponse.class, "some stuff");
        assertTrue(cr.getStatus() == 201);

        // Verify the created resource
        ResourceProxy vResource = c.proxy(cr.getLocation());
        String content = vResource.get(String.class);
        assertTrue("some stuff".equals(content));
       
        // Get the current properties and verify the contents
        p = pResource.get(Properties.class);
        assertTrue(p.size() == 1);
        assertTrue(p.contains("some stuff"));
       
        // Delete the created resource
        try {
            vResource.delete();
        } catch (UniformInterfaceException e) {
            // This will occur when a status >= 300 occurs
            assertTrue(false);
        }
       
        // Verify resource is deleted
        try {
            content = vResource.get(String.class);
        } catch (UniformInterfaceException e) {
            // This will occur when a status >= 300 occurs
            assertTrue(e.getResponse().getStatus() == 404);
        }
       
        // Verify resource is deleted using ClientResponse
        cr = vResource.get(ClientResponse.class);
        assertTrue(cr.getStatus() == 404);
       
        // Verify properties resource contains no properties
        p = pResource.get(Properties.class);
        assertTrue(p.size() == 0);       
    }
   
    private static void assertTrue(boolean v) {
        if (v == false) throw new RuntimeException();
    }
   
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServerFactory.create("http://localhost:9998/");
        server.start();
       
        try {
            run();
        } finally {
            server.stop(0);
        }
    }
}
Comments:

Great news! I'll be putting this into use shortly.

Posted by Chad Sturtz on February 08, 2008 at 02:11 PM CET #

This is awesome!
To my knowledge there is not an existing Java package that handles invoking REST Services.

If not already, you might consider making this its own project separate from Jersey. This would allow people to use your client api without including the server side stuff if they don't need it.

Great job.

Posted by James Lorenzen on February 08, 2008 at 02:13 PM CET #

Hi!

I'd encourage you to also look at the APIs we have in the swingx-ws project (swingx-ws.dev.java.net). They were developed exactly for interacting with HTTP resources from the client. Here's a small sample of what you do to use swingx-ws for connecting to a REST endpoint:

Session s = new Session();
Response r = s.get("http://somesite.com/someresource");
String body = r.getBody();

Of course this is the shorthand, there is a much more fleshed out API available as well:

Session s = new Session();
Request req = new Request();
req.setUrl("http://someurl/someresource");
req.setMethod(Method.POST);
req.setBody("some body to be posted");
//can use Basic authentication
req.setUsername("rich");
req.setPassword("secret");
Response r = s.execute(req);
Status s = r.getStatus();
if (s == Status.OK) {...}

Works with HTTP, HTTPS, etc. It built on the standard java networking APIs, has support for reading/writing headers, params, and so forth. I've used it for several RESTful clients, including Iris (http://swinglabs.java.sun.com/iris).

Richard

Posted by Richard Bair on February 09, 2008 at 04:47 PM CET #

Chad: Thanks! let me know what you think.

James: Yes a separation would be good, i need to evaluate transition of Jersey to a maven build process and that separation would make sense as part of it. Unfortunately at the moment i don't have time to work on such a transition...

Richard: thanks for the interesting info. Do you have any links to JavaDoc so i can look at the API more closely?

The example (specifically the second) you pointed to is a good example of what i did not want to achieve with the API i am experimenting with. I wanted the REST uniform interface constraint to be reflected in the API upfront so that it is a bit like using the high-level JAX-WS client or a RMI proxy in addition to reusing concepts from the Jersey/JAX-RS server side, especially the pluggable message readers/writers typing system. Once one has a concept of a ResoureProxy it becomes a bit like a typed Java reference to a resource and one can start to do interesting things with it. For example, we support WADL for resources on the server side. The ResourceProxy could GET the WADL and do some processing of that. Or a ResourceProxy could hold authentication information so that for each request one does not have to repeat the same information.

The API is a reasonably thin veneer that requires that a lower-level API, like HttpURLConnection that i use to day, or say using the APIs you pointed to. Perhaps we could cooperate?

Posted by Paul Sandoz on February 11, 2008 at 03:02 AM CET #

Hey Paul,

The best place to get the code and docs would be http://swinglabs.org/downloads.jsp. Then find the weekly builds for swingx-ws.

As a client developer, often I don't care about or have access to typed resources. For example, if I'm going to interact with the Flickr APIs, there are some (IMO) lousy flickr java APIs that could be used, or I could just talk to the Flickr API directly. I prefer the latter. But it depends on what you're trying to do as the client developer.

Beneath the hood I'm also using HttpURLConnection. My APIs are really just an attempt to model the HTTP request/response cycle the way I conceptually think of it. They're also definitely meant to have higher level APIs layered on top to make GUI programming even easier. They might be a reasonable implementation to base your APIs on as well :-)

To be honest though, as a client developer, I've been leery of JAX-WS, RMI, and other such approaches to web services. Often it is just easier as a developer to deal with a chunk of XML and deal with it by hand.

JavaScript and ActionScript have a big leg up in this department, because they can actually reliably send serialized objects over the wire. For simple data, the JavaBeans Encoder/Decoder would work equally well. I suspect most data sent over a REST api would be simple data, so maybe using this approach would lend a much simpler API. I'm always leery of heavyweight approaches. The simpler, the better.

Thanks
Richard

Posted by Richard Bair on February 12, 2008 at 02:26 PM CET #

Hi Richard,

Thanks for the link, i will check things out.

By typed i meant typed according to the REST uniform interface constraint and not typed to a particular particular service. (Note that the example in the blog does not create a specific client API and it should be easy to work out how to modify the types of data being sent and received without having to change that API.)

I understand why you are leary of JAX-WS and RMI. The similarity i was referring to was that the developer uses an interface to directly interact with the service. This is the same for the RESTful client API except that the \*same\* interface is used for all URIs to resources (the uniform interface constraint). However that constraint and the API does not constrain in any way what data (heavy or light) can be sent and received and what APIs may be used to produce or consume that data.

Once we have a concept of a type for the uniform interface i can start doing the following for the Jersey server side, namely inject pre-configued ResourceProxy instances:

@Path ("resource)
public class MyResource {
@WebResourceRef("http://foo.service.com") ResourceProxy foo;

@WebResourceRef("http://bar.service.com") ResourceProxy bar;

// Feed is the Abdera Feed class
@GET public Feed getFeed() {
Feed foo = foo.get(Feed.class);
Feed bar = bar.get(Feed.class);
Feed f = // merge foo and bar
return f;
}
}

Using a request/response model makes it harder for the developer to do this type of thing because the
URI is not at the fore of the API.

I agree the two APIs represent different models: one is request/response based and one is uniform interface based. The latter is conceptually at a higher-level.

I was considering using the Apache HttpClient as the base for the RESTful API as HttpURLConnection is a bit limited! but i i will look closely at your API.

Posted by Paul Sandoz on February 13, 2008 at 04:35 AM CET #

Is there a point to get the "client api". I just want to have a look at it.

Best Regards,
Daniel

Posted by Daniel Manzke on February 24, 2008 at 06:25 AM CET #

Hi Daniel,

It is in the latest Jersey build:

https://jersey.dev.java.net/servlets/ProjectDocumentList?folderID=7653&expandFolder=7653&folderID=0

i.e. the client/server are currently part of the same jersey.jar.

Paul.

Posted by Paul Sandoz on February 25, 2008 at 03:13 AM CET #

Hi all,

Is it possible to set a timeout value for the client?

If the server is alive, everything is fine, but when I close the server and create the resource, it waits too much to return timeout. I want to decrease this time.

Thanks...

Posted by Omer Basar on May 28, 2008 at 01:20 AM CEST #

Hi Omer,

Currently it is not possible. I have been planning to sort out such configuration of this an other things like redirection etc.

Would you mind logging an issue so i can track it:

https://jersey.dev.java.net/issues/

(You need to log in with a java.net account to log an issue.)

Thanks,
Paul.

Posted by Paul Sandoz on May 28, 2008 at 02:17 AM CEST #

Hi Paul,

In the example above, how would I invoke the updateContent using put?

I was trying something like this. But, it did not work.

// Update the property
WebResource uResource = c.resource(cr.getLocation());
Properties up = pResource.get(Properties.class);
String key = (String) up.keys().nextElement();
up.setProperty(key, "some more stuff");
cr = uResource.type("text/plain").put(ClientResponse.class, up);

// Get the current properties and verify the contents
p = pResource.get(Properties.class);
assertTrue(p.size() == 1);
assertTrue(p.contains("some more stuff"));

Thanks!
Arul

Posted by Arul Dhesiaseelan on May 28, 2008 at 10:58 AM CEST #

Do you want to PUT the all the properties or just a single property ?

If a single property do:

cr = uResource.type("text/plain").put(ClientResponse.class, "some more stuff");

If all properties then you need to implement a PUT method as follows:

@PUT public void put(Properties p) {
this.p = p;
}

and do this:

Properties up = pResource.get(Properties.class);
String key = (String) up.keys().nextElement();
up.setProperty(key, "some more stuff");
cr = pResource.type("text/plain").put(ClientResponse.class, up);

Paul.

Posted by Paul Sandoz on May 28, 2008 at 11:17 AM CEST #

Paul,

I was trying to just update one property as shown below.

// Update the property
WebResource uResource = c.resource(cr.getLocation());
cr = uResource.type("text/plain").put(ClientResponse.class, "some more stuff");

// Get the current properties and verify the contents
Properties u = uResource.get(Properties.class);
assertTrue(u.size() == 1);
assertTrue(u.contains("some more stuff"));//assert fails here

But the assert fails here.

Thanks,
Arul

Posted by guest on May 28, 2008 at 12:10 PM CEST #

There was a bug in the @PUT method, it should be:

@Path("{id}") @PUT public synchronized void updateContent(
@PathParam("id") String id, String newContent) { ... }

It was not receiving an entity (the new property value). See below for updated code using the latest build.

Paul.
import com.sun.net.httpserver.HttpServer;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.jersey.spi.resource.Singleton;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Properties;
import java.util.UUID;
import javax.ws.rs.ConsumeMime;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ProduceMime;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

public class Main {

@ProduceMime("text/plain")
@Provider
public static class PropertiesProvider implements
MessageBodyWriter<Properties>,
MessageBodyReader<Properties> {

public long getSize(Properties p) {
return -1;
}

public boolean isWriteable(Class<?> type, Type arg1, Annotation[] arg2) {
return Properties.class.isAssignableFrom(type);
}

public void writeTo(Properties p, Class<?> arg1, Type arg2, Annotation[] arg3,
MediaType arg4, MultivaluedMap<String, Object> arg5, OutputStream out)
throws IOException, WebApplicationException {
p.store(out, null);
}

public boolean isReadable(Class<?> type, Type arg1, Annotation[] arg2) {
return Properties.class.isAssignableFrom(type);
}

public Properties readFrom(Class<Properties> arg0, Type arg1, Annotation[] arg2,
MediaType arg3, MultivaluedMap<String, String> arg4, InputStream in)
throws IOException, WebApplicationException {
Properties p = new Properties();
p.load(in);
return p;
}
}

@Path("/")
@ProduceMime("text/plain")
@ConsumeMime("text/plain")
@Singleton
public static class PropertiesResource {
@Context UriInfo uriInfo;

Properties p = new Properties();

@GET public Properties get() {
return p;
}

@POST public Response post(String in) {
String id = UUID.randomUUID().toString();

p.setProperty(id, in);

URI u = uriInfo.getAbsolutePathBuilder().path(id).build();
return Response.created(u).build();
}

@Path("{id}") @GET public synchronized String getContent(
@PathParam("id") String id) {
String content = p.getProperty(id);
if (content == null) throw new WebApplicationException(404);

return content;
}

@Path("{id}") @PUT public synchronized void updateContent(
@PathParam("id") String id, String newContent) {
String content = p.getProperty(id);
if (content == null) throw new WebApplicationException(404);

p.setProperty(id, newContent);
}

@Path("{id}") @DELETE public synchronized void deleteContent(
@PathParam("id") String id) {
String content = p.getProperty(id);
if (content == null) throw new WebApplicationException(404);

p.remove(id);
}
}

public static void run() throws Exception {
// Create the client
ClientConfig cc = new DefaultClientConfig();
// Include the properties provider
cc.getProviderClasses().add(PropertiesProvider.class);
Client c = Client.create(cc);

// Create the resource proxy to the resource
WebResource pResource = c.resource("http://localhost:9998/");

// Get the current properties and verify it is empty
Properties p = pResource.get(Properties.class);
assertTrue(p.size() == 0);

// Create a new property
ClientResponse cr = pResource.
type("text/plain").
post(ClientResponse.class, "some stuff");
assertTrue(cr.getStatus() == 201);

// Verify the created resource
WebResource vResource = c.resource(cr.getLocation());
String content = vResource.get(String.class);
assertTrue("some stuff".equals(content));

// Get the current properties and verify the contents
p = pResource.get(Properties.class);
assertTrue(p.size() == 1);
assertTrue(p.contains("some stuff"));

// Update the current property
WebResource uResource = c.resource(cr.getLocation());
vResource.put("some more stuff");

// Get the current properties and verify the contents
p = pResource.get(Properties.class);
assertTrue(p.size() == 1);
assertTrue(p.contains("some more stuff"));

// Delete the created resource
try {
vResource.delete();
} catch (UniformInterfaceException e) {
// This will occur when a status >= 300 occurs
assertTrue(false);
}

// Verify resource is deleted
try {
content = vResource.get(String.class);
} catch (UniformInterfaceException e) {
// This will occur when a status >= 300 occurs
assertTrue(e.getResponse().getStatus() == 404);
}

// Verify resource is deleted using ClientResponse
cr = vResource.get(ClientResponse.class);
assertTrue(cr.getStatus() == 404);

// Verify properties resource contains no properties
p = pResource.get(Properties.class);
assertTrue(p.size() == 0);
}

private static void assertTrue(boolean v) {
if (v == false) throw new RuntimeException();
}

public static void main(String[] args) throws Exception {
HttpServer server = HttpServerFactory.create("http://localhost:9998/");
server.start();

try {
run();
} finally {
server.stop(0);
}
}
}

Posted by Paul Sandoz on May 29, 2008 at 12:50 AM CEST #

Hi Paul,

Thanks for fixing this code.

Regards,
Arul

Posted by Arul Dhesiaseelan on May 29, 2008 at 11:51 AM CEST #

Hi,

jersey-0.8-ea and jersey-0.9-ea are not in maven repositories.

http://download.java.net/maven/1/jersey/jars/

Are these jars put another repository?

Posted by Ömer Başar on August 08, 2008 at 01:40 AM CEST #

See here:

http://download.java.net/maven/2/com/sun/jersey/jersey/

we moved over to Maven 2 as we converted the project to use Maven 2.

Also take note of a recent blog entry i wrote:

http://blogs.sun.com/sandoz/entry/modularizing_jersey

We are in transition, which i realize can be very confusing. When we release 0.9 it should be much clearer.

Paul.

Posted by Paul Sandoz on August 08, 2008 at 04:00 AM CEST #

[Trackback] TOTD #56 explains how to create a RESTful Web service endpoint using Jersey and publish the resource using JSON representation. The blog entry showed how the endpoint can be accessed from a Web browser. This Tip Of The Day explains...

Posted by Arun Gupta's Blog on November 26, 2008 at 07:03 AM CET #

Hi Arun,
A quick newbie question.

I copy pasted the code above, and was wondering, whats the jar files for this import?

com.sun.ws.rest.api.client.\*

Thanks

David

Posted by David on January 07, 2009 at 01:28 PM CET #

Hi David,

Note that this blog is using an old version of the Client API. IIRC you should be able to change the package "com.sun.ws.rest.api.client.\*" to "com.sun.jersey.api.client.\*" and the code should work... if it does not please ask further questions (you can email users@jersey.dev.java.net).

For Jersey-based dependencies see:

https://jersey.dev.java.net/source/browse/\*checkout\*/jersey/tags/jersey-1.0.1/jersey/dependencies.html

The JavaDoc is here:

https://jersey.dev.java.net/source/browse/\*checkout\*/jersey/tags/jersey-1.0.1/api/jersey/index.html

Paul.

Posted by Paul Sandoz on January 08, 2009 at 02:21 AM CET #

can u pls help me
while i am executing the small Rest webservices (@GET)
i getting the problem like
GET http://localhost:8080/com.infosys/rest returned a response status of 404

Posted by Srinivasarao.K on October 08, 2010 at 08:17 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

sandoz

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today