Usage of client.reset in CXF Rest client - java

I am working on Rest web services and client using CXF 3.1.2 , and i have few clarification as below,
Service:
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
public class GenServiceImpl {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogin/{ext}")
public String agentLogin(#PathParam("ext") Integer ext) {
return "EventAgentLoggedIn";
}
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes({"application/xml", MediaType.TEXT_PLAIN})
#Path("/agentLogout")
public String agentLogout(String ext) {
return "EventAgentLoggedOut";
}
}
Client:
import javax.ws.rs.core.Response;
import org.apache.cxf.jaxrs.client.WebClient;
public class TestClient {
static final String REST_URI = "http://localhost:8080/RestfulSample/Restful";
public static void main(String[] args) {
WebClient client = WebClient.create(REST_URI);
//Get
client.path("agentLogin").path(new Integer(1234)).accept(MediaType.TEXT_PLAIN);
String agentLoginResponse = client.get(String.class);
System.out.println(agentLoginResponse);
client.reset();
//Post
client.path("agentLogout").accept(MediaType.TEXT_PLAIN);
Response agentLogoutResponse = client.post("10245");
System.out.println(agentLogoutResponse.readEntity(String.class));
client.reset();
}
Clarifications:
In my above example - In service class Post method(agentLogout) , i am getting error if i replace #Consumes({"application/xml", MediaType.TEXT_PLAIN})
with
#Consumes(MediaType.TEXT_PLAIN) whereas it works fine in Get method(agentLogin), may i know why it is so?
It is right to use client.reset(); - Here i am trying to use single WebClient to access all my methods.
Could you please let me know what i tried in my example is best practice ? and it will be appreciated if you could correct me here
Thanks,

Here are the clarifications.
Set content type to text/plain while posting. And you can set in your servers side class #Consumes(MediaType.TEXT_PLAIN)
client.replaceHeader("Content-Type",MediaType.TEXT_PLAIN);
Yes you can use rest method, here is java doc
When reusing the same WebClient instance for multiple invocations,
one may want to reset its state with the help of the reset() method,
for example, when the Accept header value needs to be changed and the
current URI needs to be reset to the baseURI (as an alternative to a
back(true) call). The resetQuery() method may be used to reset the
query values only. Both options are available for proxies too.
I would prefer to use proxy and access REST more like OOPS.
You could create interface for the above server class(Generally I careate REST definition as interface and then implement the interface( more like SOAP way)), which could be auto generated using WADLToJava maven plugin from WADL.
Here is sample interface for above server side rest class
public interface GenService {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogin/{ext}")
public String agentLogin(#PathParam("ext") Integer ext);
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogout")
public String agentLogout(String ext);
}
Since you are not using spring , I will create a singleton class
public class CxfRestSingleton {
public static GenService obj;
public static GenService getInstance() {
if (obj == null) {
obj = JAXRSClientFactory.create("http://localhost:8080/RestfulSample/Restful", GenService.class);
}
return obj;
}
}
And you can access the rest using below code.
public static void main( String[] args )
{
System.out.println( CxfRestSingleton.getInstance().agentLogin(12345));
}

Related

Why wrong path annotation doesn't crash REST API with Jersey?

I have a running RESTful API fully working with everything ok. I'm using a HTML with JS to access my REST methods with Jersey and Tomcat7 to host it. This is the code:
package pact;
import java.io.IOException;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.google.gson.Gson;
import repo.Pessoa;
import repo.Repo;
#Path("/")
public class Rest {
Gson gson = new Gson();
#POST
#Path("escreve")
#Consumes(MediaType.APPLICATION_JSON)
public void escreve(String dado) throws IOException {
Pessoa pessoa = gson.fromJson(dado, Pessoa.class);
Repo.escreve(pessoa);
}
#GET
#Path("le")
#Produces(MediaType.APPLICATION_JSON)
public String le() {
List<Pessoa> list = Repo.le();
String json = gson.toJson(list);
return json;
}
#POST
#Path("loja")
#Consumes(MediaType.APPLICATION_JSON)
public void loja(String dado){
Repo.seleciona(gson.fromJson(dado, Pessoa.class));
}
#GET
#Path("lojale")
#Produces(MediaType.APPLICATION_JSON)
public String lojale() {
return gson.toJson(Repo.retorna());
}
}
The problem is, if I change my web.xml at <url-pattern>/rest/*</url-pattern> to something like <url-pattern>/reste/*</url-pattern> Tomcat's description automatically changes to "Restart" and after restarting, all routes are changed to access my REST methods. Why I change #Path("/") to something like #Path("/pessoa/*") nothing happens, even saving all project, deleting Tomcat, creating another Server and publishing on it. Does this line matters? I've saw it in a tutorial and never changed. Does Jersey uses something like this?
Have you tried to set #Path("/pessoa/") instead of #Path("/pessoa/*") . I think you do not need the * as only /pessoa/ itself will match both /pessoa and /pessoa/something

"Publish" object through http

I have an object with state and non-serializable fields, like threads, and I would to invoke functions on it like one would do it through RMI but through http. I don't want to scale and I am in an isolated network. I am currently using Jetty, like this:
public class ObjectHandler extends AbstractHandler {
MyStatefulObject obj;
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String action = request.getParameter("action");
switch (action) {
case "method1":
obj.method1(request.getParameter("some-parameter"));
break;
case "method2":
obj.method2(request.getParameter("some-other-parameter"));
break;
}
baseRequest.setHandled(true);
}
}
which is kind of weird. I would like to use something like Servlets, and use the different methods to tell apart the action to do, or use JAX-RS to use the calling url to tell apart the action to do. But both of those methods are stateless, that is, I cannot pass an object to a servlet, and, at least with jersey, the construction was made with the class, not with and instance of it, so I could not control the construction of the MyStatefulObject object. So, is there a library for, let's say, annotate an object and pass it to a server instance and start listening to requests? I would like to make something like this:
#Path("/")
public class MyStatefulObject {
MyStatefulObject(Parameter param1, Param) {
//some building stuff
}
#POST
#Path("/path1")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8")
void method1(Parameter param) {}
#POST
#Path("/path2")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8")
Object method2(Parameter param) {
return new Object();
}
}
while outside I would have:
Server server = new Server(8081);
server.setHandler(new MyStatefulObject(param));
server.start();
server.join();
Is there a library that makes me able to do that? as I say before, I don't want to scale (this is running in a small network) and there is no security concerns. I just want to "publish" an object.
In the end, Jersey does allow stateful objects to be published, using the ResourceConfig class with an object (as opposed with a Class, which is the use I found more frequently). Funny cause in this question they want to do the exact opposite. We simply register an object in the ResourceConfig.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.net.URI;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import javax.inject.Singleton;
#Path("calculator")
public class Calculator {
int i = -1;
public Calculator(int i) {
this.i = i;
}
#GET
#Path("increment")
#Produces(MediaType.APPLICATION_JSON)
public String increment() {
i = i + 1;
return "" + i;
}
public static void main(String[] args) throws Exception {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new Calculator(10));
Server server = JettyHttpContainerFactory.createServer(new URI("http://localhost:8080"), resourceConfig);
server.start();
}
}

Is there a client-side mock framework for RESTEasy?

RESTEasy provides the Server-side Mock Framework for mocking server requests. Is there an equivalent for unit testing the client framework?
Is InMemoryClientExecutor intended for this purpose? I'm having trouble finding documentation and examples of how this class should be used.
Looks like InMemoryClientExecutor may be used for client-side mocking. Looking in the source, it internally uses the same classes as the server-side mock framework, namely, MockHttpRequest and MockHttpResponse.
InMemoryClientExecutor gives you the ability to override createResponse for mocking responses and also has a constructor which takes a Dispatcher, if you want to customize and intercept calls that way.
Here's a quick and dirty snippet leveraging the client framework example,
import javax.ws.rs.*;
import javax.ws.rs.core.Response.*;
import org.jboss.resteasy.client.*;
import org.jboss.resteasy.client.core.*;
import org.jboss.resteasy.client.core.executors.*;
import org.jboss.resteasy.mock.*;
import org.jboss.resteasy.plugins.providers.*;
import org.jboss.resteasy.spi.*;
public class InMemoryClientExecutorExample {
public interface SimpleClient {
#GET
#Path("basic")
#Produces("text/plain")
String getBasic();
#PUT
#Path("basic")
#Consumes("text/plain")
void putBasic(String body);
#GET
#Path("queryParam")
#Produces("text/plain")
String getQueryParam(#QueryParam("param")String param);
#GET
#Path("matrixParam")
#Produces("text/plain")
String getMatrixParam(#MatrixParam("param")String param);
#GET
#Path("uriParam/{param}")
#Produces("text/plain")
int getUriParam(#PathParam("param")int param);
}
public static void main(String[] args) {
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
ClientExecutor executor = new InMemoryClientExecutor() {
#Override
protected BaseClientResponse<?> createResponse(ClientRequest request, MockHttpResponse mockResponse) {
try {
System.out.println("Client requesting " + request.getHttpMethod() + " on " + request.getUri());
}
catch(Exception ex) {
ex.printStackTrace();
}
mockResponse.setStatus(Status.OK.getStatusCode());
return super.createResponse(request, mockResponse);
}
};
SimpleClient client = ProxyFactory.create(SimpleClient.class, "http://localhost:8081", executor);
client.putBasic("hello world");
}
}

Invoke RESTful webservice with parameter

I have a simple RESTful web service that print "Hello World !"
I'm using NetBeans and the code looks like:
package resource;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
#Path("simple")
public class SimpleResource {
#Context
private UriInfo context;
/** Creates a new instance of SimpleResource */
public SimpleResource() {
}
#GET
#Produces("application/xml")
public String getXml() {
//TODO return proper representation object
return "<greeting>Hello World !</greeting>";
}
#PUT
#Consumes("application/xml")
public void putXml(String content) {
}
}
I call this web service from this URL : http://localhost:8080/WebService/resources/simple.
Now, I want to send a parameter to this web service, then print this parameter after the "Hello world" message.
How can we do that?
Thanks!
The two main ways of handling a parameter in REST are via parsing the path and via extracting the query part.
Path parameters
These handle this case — /foo/{fooID} — where {fooID} is a template that will be replaced by the parameter you want:
#GET
#Produces("text/plain")
#Path("/foo/{fooID}")
public String getFoo(#PathParam("fooID") String id) {
// ...
}
These are great for the case where you can consider the parameter to be describing a resource.
Query parameters
These handle this case — /?foo=ID — just like you'd get from doing traditional form processing:
#GET
#Produces("text/plain")
#Path("/")
public String getFoo(#QueryParam("foo") String id) {
// ...
}
These are great for the case where you consider the parameter to be describing an adjunct to the resource, and not the resource itself. The #FormParam annotation is extremely similar, except it is for handling a POSTed form instead of GET-style parameters
Other types of parameters
There are other types of parameter handling supported by the JAX-RS spec (matrix parameters, header parameters, cookie parameters) which all work in about the same way to the programmer, but are rarer or more specialized in use. A reasonable place to start exploring the details is the JAX-RS javadoc itself, as that has useful links.
The sample code for a web service which accepts parameters in URl will look like this:
#GET
#Path("/search")
public String getUserDetailsFromAddress(
#QueryParam("name") String name) {
return "Hello"+name;
}
and the URL will be like this:
http://localhost:8080/searchapp/mysearch/search?name=Tom
Try adding a Path annotation like this:
#javax.ws.rs.Path(“/bookstore/books/{bookId}”)

Why writer for media type application/json missing

Basically I have a restful service (post) that consumes(application/json) and produces (application/json). The single param for this service is an annotated java object.
I am using org.jboss.resteasy.client.ClientRequest to send the request to the service. However, I am getting this exception in the client end and the exception:
could not find writer for content-type application/json type.
Does this mean that I am missing some library jars or I have to write my own writer for application/json?
I am using resteasy 1.1
Mark
Raman is correct. Jettison is a valid option. You can also use Jackson.
If you are using maven, it is as simple as including the following dependency in you pom:
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>2.3.2.Final</version>
</dependency>
At which point you should have no problem writing code such as:
SomeBean query = new SomeBean("args")
request.body("application/json", query);
ClientResponse response = request.post();
actually I had the same problem, I did solve it by adding jettison provider for application/json mime type. I don't know whether resteasy 1.1 containts jettison provider but version 1.2 does.
Also if you are using jdk 1.6 you must exclude javax.xml.stream:stax-api jar file, otherwise you will have a problem.
Here is the example:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="account")
public class Account {
private Long id;
private String accountNo;
public Account(){}
public Account(String no) {
accountNo=no;
}
#Id
#XmlElement
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#XmlElement
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String a) {
accountNo = a;
}
}
and JAXB class:
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
#Path("/account")
public class AccountService {
#GET
#Path("/{accountNo}")
#Produces("application/json")
public Account getAccount(#PathParam("accountNo") String accountNo) {
return new Account(accountNo);
}
}
That's all, have a nice day!
Add below to the Resource class or the method causing the exception
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)

Categories