[ https://issues.apache.org/jira/browse/CXF-4064?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13194911#comment-13194911 ]
Sergey Beryozkin commented on CXF-4064: --------------------------------------- Cool, thanks again for testing it > 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 > Assignee: Sergey Beryozkin > > 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