You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "David Liszewski (Updated) (JIRA)" <ji...@apache.org> on 2012/01/26 18:00:40 UTC

[jira] [Updated] (CXF-4064) Problem with JAX-RS annotated interface

     [ https://issues.apache.org/jira/browse/CXF-4064?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

David Liszewski updated CXF-4064:
---------------------------------

    Summary: Problem with JAX-RS annotated interface   (was: Problem with JAX-RS annotated interface between client and service )
    
> Problem with JAX-RS annotated interface 
> ----------------------------------------
>
>                 Key: CXF-4064
>                 URL: https://issues.apache.org/jira/browse/CXF-4064
>             Project: CXF
>          Issue Type: Bug
>          Components: JAX-RS
>    Affects Versions: 2.3.3
>         Environment: $ uname -a 
> Darwin dented.local 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun  7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386
> $ java -version
> java version "1.6.0_29"
> Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-10M3527)
> Java HotSpot(TM) Client VM (build 20.4-b02-402, mixed mode)
>            Reporter: David Liszewski
>
> When one is developing both server and client components, it is highly desirable to adhere to DRY principles and declare a JAX-RS resource interface exactly once.  The User Guide (Index > RESTful Services > JAX-RS > JAX-RS Client API) explicitly says that it should be possible to share an annotated interface between client and server: 
> {quote}
> With the proxy-based API, one can reuse on the client side the interfaces or even the resource classes which have already been designed for processing the HTTP requests on the server side (note that a {{cglib}}-nodeps dependency will need to be available on the classpath for proxies created from concrete classes). When reused on the client side, they simply act as remote proxies.
> {quote}
> However, when I modified the basic JAX-RS sample to do exactly that, two (GETs) of the four methods do not work. In fact, the only modification made was to refactor the interface with annotations out of the server implementation class, without even attempting a proxy client.
> _Note_:  I definitely reproduced this with {{2.3.3}} but I think same occurs in 2.5.x releases. 
> This is what {{mvn -Pclient}} prints out running {{./samples/jax_rs/basic}}: 
> {noformat}
> Sent HTTP GET request to query customer info
> java.io.FileNotFoundException: http://localhost:9000/customerservice/customers/123
> 	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1434)
> 	at java.net.URL.openStream(URL.java:1010)
> 	at demo.jaxrs.client.Client.main(Client.java:53)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> 	at java.lang.reflect.Method.invoke(Method.java:597)
> 	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:291)
> 	at java.lang.Thread.run(Thread.java:680)
> Sent HTTP GET request to query sub resource product info
> java.io.FileNotFoundException: http://localhost:9000/customerservice/orders/223/products/323
> 	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1434)
> 	at java.net.URL.openStream(URL.java:1010)
> 	at demo.jaxrs.client.Client.main(Client.java:64)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> 	at java.lang.reflect.Method.invoke(Method.java:597)
> 	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:291)
> 	at java.lang.Thread.run(Thread.java:680)
> Sent HTTP PUT request to update customer info
> Response status code: 200
> Response body: 
> Sent HTTP POST request to add customer
> Response status code: 200
> Response body: 
> <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>124</id><name>Jack</name></Customer>
> {noformat}
> The added interface {{ICustomerService.java}} and modified {{Client.java}} and {{CustomerService.java}} classes are shown below. {{Client.java}} was modified to catch any exceptions thrown and continue with the next function point:
> {code:title=ICustomerService.java|borderStyle=solid}
> package demo.jaxrs;
> 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.core.Response;
> import demo.jaxrs.server.Customer;
> import demo.jaxrs.server.Order;
> @Path("/customerservice/")
> public interface ICustomerService {
>     @GET
>     @Path("/customers/{id}/")
>     public Customer getCustomer(@PathParam("id") String id);
>     @PUT
>     @Path("/customers/")
>     public Response updateCustomer(Customer customer);
>     @POST
>     @Path("/customers/")
>     public Response addCustomer(Customer customer);
>     @DELETE
>     @Path("/customers/{id}/")
>     public Response deleteCustomer(@PathParam("id") String id);
>     @Path("/orders/{orderId}/")
>     public Order getOrder(@PathParam("orderId") String orderId);
> }
> {code}
> {code:title=Client.java|borderStyle=solid}
> package demo.jaxrs.client;
> import java.io.File;
> import java.io.InputStream;
> import java.net.URL;
> import org.apache.commons.httpclient.HttpClient;
> import org.apache.commons.httpclient.methods.FileRequestEntity;
> import org.apache.commons.httpclient.methods.PostMethod;
> import org.apache.commons.httpclient.methods.PutMethod;
> import org.apache.commons.httpclient.methods.RequestEntity;
> import org.apache.cxf.helpers.IOUtils;
> import org.apache.cxf.io.CachedOutputStream;
> public final class Client {
>     private Client() {
>     }
>     public static void main(String args[])  {
>         // Sent HTTP GET request to query all customer info
>         /*
>          * URL url = new URL("http://localhost:9000/customers");
>          * System.out.println("Invoking server through HTTP GET to query all
>          * customer info"); InputStream in = url.openStream(); StreamSource
>          * source = new StreamSource(in); printSource(source);
>          */
>         // Sent HTTP GET request to query customer info
>         try {
>             System.out.println("Sent HTTP GET request to query customer info");
>             URL url = new URL("http://localhost:9000/customerservice/customers/123");
>             InputStream in = url.openStream();
>             System.out.println(getStringFromInputStream(in));
>         } catch (Exception e) {
>             e.printStackTrace();
>         }
>         // Sent HTTP GET request to query sub resource product info
>         try{
>             System.out.println("\n");
>             System.out.println("Sent HTTP GET request to query sub resource product info");
>             URL url = new URL("http://localhost:9000/customerservice/orders/223/products/323");
>             InputStream in = url.openStream();
>             System.out.println(getStringFromInputStream(in));
>         } catch (Exception e) {
>             e.printStackTrace();
>         }
>         // Sent HTTP PUT request to update customer info
>         System.out.println("\n");
>         System.out.println("Sent HTTP PUT request to update customer info");
>         Client client = new Client();
>         String inputFile = client.getClass().getResource("update_customer.xml").getFile();
>         File input = new File(inputFile);
>         PutMethod put = new PutMethod("http://localhost:9000/customerservice/customers");
>         RequestEntity entity = new FileRequestEntity(input, "text/xml; charset=ISO-8859-1");
>         put.setRequestEntity(entity);
>         HttpClient httpclient = new HttpClient();
>         try {
>             int result = httpclient.executeMethod(put);
>             System.out.println("Response status code: " + result);
>             System.out.println("Response body: ");
>             System.out.println(put.getResponseBodyAsString());
>         } catch (Exception e) {
>             e.printStackTrace();
>         } finally {
>             // Release current connection to the connection pool once you are
>             // done
>             put.releaseConnection();
>         }
>         // Sent HTTP POST request to add customer
>         System.out.println("\n");
>         System.out.println("Sent HTTP POST request to add customer");
>         inputFile = client.getClass().getResource("add_customer.xml").getFile();
>         input = new File(inputFile);
>         PostMethod post = new PostMethod("http://localhost:9000/customerservice/customers");
>         post.addRequestHeader("Accept" , "text/xml");
>         entity = new FileRequestEntity(input, "text/xml; charset=ISO-8859-1");
>         post.setRequestEntity(entity);
>         httpclient = new HttpClient();
>         try {
>             int result = httpclient.executeMethod(post);
>             System.out.println("Response status code: " + result);
>             System.out.println("Response body: ");
>             System.out.println(post.getResponseBodyAsString());
>         } catch (Exception e) {
>             e.printStackTrace();
>         } finally {
>             // Release current connection to the connection pool once you are
>             // done
>             post.releaseConnection();
>         }
>         System.out.println("\n");
>         System.exit(0);
>     }
>     private static String getStringFromInputStream(InputStream in) throws Exception {
>         CachedOutputStream bos = new CachedOutputStream();
>         IOUtils.copy(in, bos);
>         in.close();
>         bos.close();
>         return bos.getOut().toString();
>     }
> }
> {code}
> {code:title=CustomerService.java|borderStyle=solid}
> package demo.jaxrs.server;
> import java.util.HashMap;
> import java.util.Map;
> 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.core.Response;
> import demo.jaxrs.ICustomerService;
> public class CustomerService implements ICustomerService {
>     long currentId = 123;
>     Map<Long, Customer> customers = new HashMap<Long, Customer>();
>     Map<Long, Order> orders = new HashMap<Long, Order>();
>     public CustomerService() {
>         init();
>     }
>     public Customer getCustomer(@PathParam("id") String id) {
>         System.out.println("----invoking getCustomer, Customer id is: " + id);
>         long idNumber = Long.parseLong(id);
>         Customer c = customers.get(idNumber);
>         return c;
>     }
>     public Response updateCustomer(Customer customer) {
>         System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName());
>         Customer c = customers.get(customer.getId());
>         Response r;
>         if (c != null) {
>             customers.put(customer.getId(), customer);
>             r = Response.ok().build();
>         } else {
>             r = Response.notModified().build();
>         }
>         return r;
>     }
>     public Response addCustomer(Customer customer) {
>         System.out.println("----invoking addCustomer, Customer name is: " + customer.getName());
>         customer.setId(++currentId);
>         customers.put(customer.getId(), customer);
>         return Response.ok(customer).build();
>     }
>     public Response deleteCustomer(@PathParam("id") String id) {
>         System.out.println("----invoking deleteCustomer, Customer id is: " + id);
>         long idNumber = Long.parseLong(id);
>         Customer c = customers.get(idNumber);
>         Response r;
>         if (c != null) {
>             r = Response.ok().build();
>             customers.remove(idNumber);
>         } else {
>             r = Response.notModified().build();
>         }
>         return r;
>     }
>     public Order getOrder(@PathParam("orderId") String orderId) {
>         System.out.println("----invoking getOrder, Order id is: " + orderId);
>         long idNumber = Long.parseLong(orderId);
>         Order c = orders.get(idNumber);
>         return c;
>     }
>     final void init() {
>         Customer c = new Customer();
>         c.setName("John");
>         c.setId(123);
>         customers.put(c.getId(), c);
>         Order o = new Order();
>         o.setDescription("order 223");
>         o.setId(223);
>         orders.put(o.getId(), o);
>     }
> }
> {code}
> Here is a {{diff}} output, should that be more helpful:
> {noformat}
> $ diff  -r basic/src basic_interface/src 
> Only in basic_interface/src/demo/jaxrs: ICustomerService.java
> diff -r basic/src/demo/jaxrs/client/Client.java basic_interface/src/demo/jaxrs/client/Client.java
> 40c40
> <     public static void main(String args[]) throws Exception {
> ---
> >     public static void main(String args[])  {
> 50,53c50,57
> <         System.out.println("Sent HTTP GET request to query customer info");
> <         URL url = new URL("http://localhost:9000/customerservice/customers/123");
> <         InputStream in = url.openStream();
> <         System.out.println(getStringFromInputStream(in));
> ---
> >         try {
> >             System.out.println("Sent HTTP GET request to query customer info");
> >             URL url = new URL("http://localhost:9000/customerservice/customers/123");
> >             InputStream in = url.openStream();
> >             System.out.println(getStringFromInputStream(in));
> >         } catch (Exception e) {
> >             e.printStackTrace();
> >         }
> 56,60c60,68
> <         System.out.println("\n");
> <         System.out.println("Sent HTTP GET request to query sub resource product info");
> <         url = new URL("http://localhost:9000/customerservice/orders/223/products/323");
> <         in = url.openStream();
> <         System.out.println(getStringFromInputStream(in));
> ---
> >         try{
> >             System.out.println("\n");
> >             System.out.println("Sent HTTP GET request to query sub resource product info");
> >             URL url = new URL("http://localhost:9000/customerservice/orders/223/products/323");
> >             InputStream in = url.openStream();
> >             System.out.println(getStringFromInputStream(in));
> >         } catch (Exception e) {
> >             e.printStackTrace();
> >         }
> 72d79
> < 
> 77a85,86
> >         } catch (Exception e) {
> >             e.printStackTrace();
> 99a109,110
> >         } catch (Exception e) {
> >             e.printStackTrace();
> 105d115
> < 
> diff -r basic/src/demo/jaxrs/server/CustomerService.java basic_interface/src/demo/jaxrs/server/CustomerService.java
> 32,33c32,34
> < @Path("/customerservice/")
> < public class CustomerService {
> ---
> > import demo.jaxrs.ICustomerService;
> > 
> > public class CustomerService implements ICustomerService {
> 42,43d42
> <     @GET
> <     @Path("/customers/{id}/")
> 51,52d49
> <     @PUT
> <     @Path("/customers/")
> 67,68d63
> <     @POST
> <     @Path("/customers/")
> 78,79d72
> <     @DELETE
> <     @Path("/customers/{id}/")
> 96d88
> <     @Path("/orders/{orderId}/")
> {noformat}

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira