Java client for REST web service with Netbeans - java

I am trying to write a Java client for a REST web service, defined this way:
#Path("/")
public class Translator {
public Translator() { }
#POST
#Produces("application/json")
#Path("/translate")
public String translate(#QueryParam("dir") String dir, #QueryParam("string")String string, #QueryParam("user")String user, #QueryParam("key")String key){
return doTranslation(dir, string, user, key);
}
}
I have tried to use the NetBeans option "New Restful Java client", selecting for the REST source the project that contains the webservice.
But it generates a class with one method that does not have parameters:
public class NewJerseyClient {
private WebTarget webTarget;
private Client client;
private static final String BASE_URI = "http://localhost:8086/TranslatorREST/Translator";
public NewJerseyClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget = client.target(BASE_URI);
}
public String translate() throws ClientErrorException {
return webTarget.path("translate").request().post(null, String.class);
}
}
So I don't see a way to pass parameters to the web service.
I can succesfully use this web service from SoapUI, provided that I don't enable the option "Post QueryString", in which case the web service receives "null" for all the parameters.
Thanks in advance.

You can add the parameters with .queryParam() :
public class NewJerseyClient {
private WebTarget webTarget;
private Client client;
private static final String BASE_URI = "http://localhost:8086/TranslatorREST/Translator";
public NewJerseyClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget = client.target(BASE_URI);
}
public String translate() throws ClientErrorException {
return webTarget.path("translate").queryParam("dir", "myDir")
.queryParam("string", "myString")
.queryParam("user", "myUser")
.queryParam("key", "myKey").request().post(null, String.class);
}
}

Related

Retrofit2 response code=401, message=Unauthorized. How to solve?

I use Retrofit2 to make REST API requests. I have my dummy server (that runs with spring boot) on my machine:
#RestController
class SecureServiceController {
private int counter = 1;
#RequestMapping(value = "/nnrf-nfm/v1/nf-instances/bee75393-2ac3-4e60-9503-854e733309d4", method = RequestMethod.PUT)
public ResponseEntity<NFProfile> nNrfNfManagementNfRegister() {
System.out.println(counter++ + ". Got NrfClient register request. " + new Date());
NFProfile nfProfile = new NFProfile();
nfProfile.setHeartBeatTimer(2);
ResponseEntity<NFProfile> responseEntity = ResponseEntity.status(201).body(nfProfile);
return responseEntity;
}
}
When client make request from the same machine it works. But when client make request from remote machine I have error response:
Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://myhostname:8443/nnrf-nfm/v1/nf-instances/bee75393-2ac3-4e60-9503-854e733309d4}
Response error body: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>Error</title></head><body><h1>Error</h1></body></html>
I've read that such error means that client don't have the rights to access and need to add access token. But my server does not ask any access token (at least explicitly) and it should not ask it.
How to solve this problem?
My apiClient:
public class ApiClient {
private Map<String, Interceptor> apiAuthorizations;
private Builder okBuilder;
private retrofit2.Retrofit.Builder adapterBuilder;
private JSON json;
//a lot setters and getters
public <S> S createService(Class<S> serviceClass) {
return this.adapterBuilder.client(this.okBuilder.build()).build().create(serviceClass);
}
public void configureFromOkclient(OkHttpClient okClient) {
this.okBuilder = okClient.newBuilder();
this.addAuthsToOkBuilder(this.okBuilder);
}
}
my interface:
public interface NfInstanceIdDocumentApi {
#Headers({"Content-Type:application/json"})
#PUT("nf-instances/{nfInstanceID}")
Call<NFProfile> registerNFInstance(#Body NFProfile body, #Path("nfInstanceID") UUID nfInstanceID, #Header("Content-Encoding") String contentEncoding, #Header("Accept-Encoding") String acceptEncoding);
}
How I do call:
OkHttpClient okHttpClient= ClientFactory.createClient();
ApiClient client = new ApiClient();
client.configureFromOkclient(okHttpClient);
NFProfile body = getNfProfile();
String baseUri = getBaseUri();
UUID uuid = getUUID();
//create call
client.getAdapterBuilder().baseUrl(baseUri);
NfInstanceIdDocumentApi service = client.createService(NfInstanceIdDocumentApi.class);
Call<NFProfile> call = service.registerNFInstance(body, uuid, null, null);
//make call
Response<NFProfile> response = call.execute();
UPD
I found the problem. Server was running on Windows machine and firewall blocked incoming requests.

How to use Mockito to mock a request in Jersey client?

I have a class to post POJO to an external API. I want to test this method.
public int sendRequest(Event event) {
Client client = ClientBuilder.newClient();
WebTarget baseTarget = client.target(some url);
Invocation.Builder builder = baseTarget.request();
Response response = builder.post(Entity.entity(event, MediaType.APPLICATION_JSON));
int statusCode = response.getStatus();
String type = response.getHeaderString("Content-Type");
if (Status.Family.SUCCESSFUL == Status.Family.familyOf(statusCode)) {
m_log.debug("The event was successfully processed by t API %s", event);
}
else if (Status.Family.CLIENT_ERROR == Status.Family.familyOf(statusCode)) {
m_log.error("Status code : <%s> The request was not successfully processed by API. %s", statusCode, event);
}
return statusCode;
}
I wrote a unit test like this
#Test
public void sendRequest_postAuditEvent_returnOK() {
int statusCode = EventProcessor.sendRequest(event);
assertEquals(Status.OK.getStatusCode(), statusCode);
}
But this will send a real request to the API. I am new to Mockito. Can anyone help me how to mock this request?
Edit:
#Mock Client m_client;
#Mock WebTarget m_webTarget;
#Mock Invocation.Builder m_builder;
#Mock Response m_response;
#Test
public void sendRequest_postAuditEvent_returnOK() {
when(m_client.target(anyString())).thenReturn(m_webTarget);
when(m_webTarget.request()).thenReturn(m_builder);
when(m_builder.post(Entity.entity(m_AuditEvent, MediaType.APPLICATION_JSON))).thenReturn(m_response);
when(m_response.getStatus()).thenReturn(Response.Status.BAD_REQUEST.getStatusCode());
assertEquals(Status.BAD_REQUEST.getStatusCode(), m_AuditEventProcessor.sendRequest(m_AuditEvent));
}
I try to mock the methods but it doesn't work. Still call the real method.
Ideally, the class should take a Client in its constructor so you could replace the real client instance with a mock when testing it.
class EventProcessor {
private Client client;
public EventProcessor(Client client) {
this.client = client;
}
public int sendRequest(Event event) {
WebTarget baseTarget = client.target(some url);
...
}
}
You can use powerMockito like this post Mocking static methods with Mockito
If you can mock this returned object ClientBuilder.newClient() you can mock all the other objects in the call chain.
PowerMockito.mockStatic(ClientBuilder.class);
BDDMockito.given(ClientBuilder.newClient(...)).willReturn([a Mockito.mock()...]);

Client Response Application.Json

I´m trying to create a client for some Rest application. I tested the Rest application with Advanced REST client in Chrome.
I received:
{
"authorization": false,
"provider": "Provider"
}
That is okey.
but I would like obtain this in my client:
public class MainApp extends Application {
public static final String BASE_URI = "http://localhost:8000/test";
public static final String PATH_NAME= "/sytem/Consumer/r/Provider";
#Override
public void start(Stage stage) throws Exception {
}
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(BASE_URI).path(PATH_NAME);
Response response = target.request(MediaType.APPLICATION_JSON).get();
System.out.println(response);
client.close();
}
}
I only receive this in the terminal:
λ java -jar Client_consumer-1.0-SNAPSHOT.jar
org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine$1#6591f517
The class is :
#XmlRootElement
public class Auth_response implements Serializable {
private String Provider;
private boolean authorization;
public Auth_response() {
super();
}
public Auth_response(String Provider, boolean authorization) {
super();
this.Provider = Provider;
this.authorization = authorization;
}
public String getProvider() {
return Provider;
}
public boolean isAuthorization() {
return authorization;
}
public void setProvider(String Provider) {
this.Provider = Provider;
}
public void setAuthorization(boolean authorization) {
this.authorization = authorization;
}
#Override
public String toString() {
return "Auth_response{" + "Provider=" + Provider + ", authorization=" + authorization + '}';
}
}
I would like to know how to print properly the response, and how to convert to a java object again. I tried with some examples, but nothing works and I think that I need some guide.
EDIT:
I tried this for getting the object:
Auth_response r=
client.target("http://localhost:8000/test/system/Consumer/r/Provider")
.request(MediaType.APPLICATION_JSON_TYPE).
get(Auth_response.class);
System.out.println("funciona:");
System.out.println(r.getProvider());
System.out.println(r.isAuthorization());
But I obtain the next error:
Caused by: javax.ws.rs.ProcessingException: RESTEASY003145: Unable to find a MessageBodyReader of content-type application/json and type class ah.client_consumer.Auth_response
at org.jboss.resteasy.core.interception.ClientReaderInterceptorContext.throwReaderNotFound(ClientReaderInterceptorContext.java:42)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.getReader(AbstractReaderInterceptorContext.java:75)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:52)
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.aroundReadFrom(GZIPDecodingInterceptor.java:59)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:55)
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readFrom(ClientResponse.java:251)
at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.readEntity(ClientResponse.java:181)
at org.jboss.resteasy.specimpl.BuiltResponse.readEntity(BuiltResponse.java:213)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:105)
... 14 more
Exception running application ah.client_consumer.MainApp
Try changing below line :
Response response = target.request(MediaType.APPLICATION_JSON).get();
System.out.println(response);
To
Response response = target.request(MediaType.APPLICATION_JSON).get(String.class);
System.out.println(response.toString());
Because you have not specified what type of response you are accepting, you are getting object as response.
SOLUTION:
Add to the code:
ResteasyProviderFactory instance=ResteasyProviderFactory.getInstance();
RegisterBuiltin.register(instance);
instance.registerProvider(ResteasyJacksonProvider.class);
The solution was finding in : Unable to find a MessageBodyReader of content-type application/json and type class java.lang.String

How to pass multiple parameters to Jersey POST method

I am trying to pass multiple parameters to Jersey POST method . Currently I am following below steps to pass a single parameter to Jersey POST method.
Client client = ClientBuilder.newClient();
WebTarget target= client.target("http://localhost:8080/Rest/rest/subuser").path("/insertSubUser");
SubUserBean subUserBean=new SubUserBean();
subUserBean.setIdUser(1);
subUserBean.setIdSubUserType(1);
subUserBean.setIdSubUser(15);
subUserBean.setFirstName("Haritha");
subUserBean.setLastName("Wijerathna");
subUserBean.setNumberOfDaysToEditRecord(14);
subUserBean.setUserName("haritha");
subUserBean.setPassword("hariwi88");
subUserBean.setDateCreated(Common.getSQLCurrentTimeStamp());
subUserBean.setLastUpdated(Common.getSQLCurrentTimeStamp());
target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.entity(subUserBean, MediaType.APPLICATION_JSON_TYPE));
SubUserJSONService.java
#Path("/subuser")
public class SubUserJSONService {
#POST
#Path("/insertSubUser")
#Consumes(MediaType.APPLICATION_JSON)
public String updateSubUser(SubUserBean bean){
SubUserInterface table = new SubUserTable();
String result= table.insertSubUser(bean);
return result;
}
}
Now, I want to pass parameters to following method via Jersey POST method.
public String insertHistory(List<SocialHistoryBean> list, String comment){
//my stuffs
}
Have any ideas to do above work ?
Thank you.
You can try using MultivaluedMap.Add form data and send it to the server. An example below, code is not tested just for demo/logic flow.
WebTarget webTarget = client.target("http://www.example.com/some/resource");
MultivaluedMap<List, String> formData = new MultivaluedHashMap<List, String>();
formData.add(List, "list1");
formData.add("key2", "value2");
Response response = webTarget.request().post(Entity.form(formData));
Consume this on server side something like
#Path("/uripath")
#POST -- if this is post or #GET
#Consumes("application/x-www-form-urlencoded;charset=UTF-8") or json..
#Produces("application/json")
public void methodNameHere(#FormParam("list") List<String> list1, #FormParam("key2") String val2) {
System.out.println("Here are I am");
System.out.println("list1" + list1.size);
System.out.println("val2" + val2);
}
Read more here in docs..
In case you're using Jersey 1.x, check this example on how to post multiple objects as #FormParam
Client: (pure Java):
public Response testPost(String param1, String param2) {
// Build the request string in this format:
// String request = "param1=1&param2=2";
String request = "param1=" + param1+ "&param2=" + param2;
WebClient client = WebClient.create(...);
return client.path(CONTROLLER_BASE_URI + "/test")
.post(request);
}
Server:
#Path("/test")
#POST
#Produces(MediaType.APPLICATION_JSON)
public void test(#FormParam("param1") String param1, #FormParam("param2") String param2) {
...
}
JSON data cannot be passed to the server in a List. This means that you should create a wrapper around your SocialHistoryBean class (i.e around the list that holds your objects)
#XmlRootElement(name = "uw")
public class SocialHistoryBeanWrapper implements Serializable {
private List<SocialHistoryBean> sList ;//this will hold your SocialHistoryBean instances
public SocialHistoryBeanWrapper(){
sList = new ArrayList<User>();
}
public List<User> getUsrList(){
return sList;
}
}
Your server side code will be like
#POST
#Path("/history")
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.APPLICATION_JSON)
public String insertHistory( #QueryParam("comment") String comment, SocialHistoryBeanWrapper uw) {
do whatever you want with your history data
//userData.setUser(uw.getUsrList().get(0));
return comment; //just echo the string that we have sent from client
}
Note that comment is passed with #QueryParam (this means it's not part of the POST request (body) but is rather encoded in the URL string. For this to work, you can call your service as (the client code)
WebTarget target = client.target(UriBuilder.fromUri("http://localhost:8088/Rest/rest/subuser").build());
SocialHistoryBeanWrapper uw = new SocialHistoryBeanWrapper();
//just populate whatever fields you have;
uw.getUsrList().get(0).setName("Mark Foster");
uw.getUsrList().get(0).setProfession("writer");
uw.getUsrList().get(0).setId(55);
String s = target.path("history").queryParam("comment", "OK").request()
.accept(MediaType.TEXT_PLAIN).post(Entity.entity(uw, MediaType.APPLICATION_JSON), String.class);
System.out.println(s);//this prints OK

How to get the response header in a RestEasy client?

i´m implementing a Restful service using Jax-RS 2.0 (Resteasy 3.0.7.Final) and share the interface between client and service.
The return value is void because ClientResponse is deprecated since RestEasy introduced JAX-RS 2.0 in version 3+.
To return the location of the new created object i inject the response, using the #Context annotation, and add the Content-Location header.
For example:
Shared Interface:
#Path("/")
#Consumes("application/xml")
#Produces("application/xml")
interface Resource {
#Path("createSomething")
void createSomething(AnyObject object);
...
}
Implementation class (The Service):
class ResourceImpl {
...
#Context org.jboss.resteasy.spi.HttpResponse response;
...
#Override
void createSomething(AnyObject object) throws AnyException {
String id = service.create(object);
response.getOutputHeaders().putSingle("Content-Location",
"/createSomething/" + id);
response.setStatus(Response.Status.CREATED.getStatusCode());
}
}
The client (build with the Resteasy Proxy Framework):
...
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(baseUrl);
Resource resource = (Resource) target.proxy(Resource.class);
resource.createSomething(anyObject);
...
How can i retrieve Header information (and others, like Atom Links) which has been injected by the service?
Is it reasonable to use client side Filters and Interceptors?
Thank You
The best solution i found was to use a Filter to process the incoming response header.
public class HeaderFilter implements ClientResponseFilter {
private Map<String, String> headers = new HashMap<>();
private List<String> headerFilter = new ArrayList<>();
public final void addHeaderFilter(final String header) {
headerFilter.add(header);
}
public final void removeHeaderFilter(final String header) {
headerFilter.remove(header);
}
public final String getHeader(final String header) {
return headers.get(header);
}
#Override
public final void filter(final ClientRequestContext requestContext,
final ClientResponseContext responseContext)
throws IOException {
headers = new HashMap<>();
for (String headerToLookFor : headerFilter) {
String header = responseContext.getHeaderString(headerToLookFor);
if (header != null) {
headers.put(headerToLookFor, header);
} else {
...
}
}
}
}

Categories