Error on creating Rest client using jersey - java

I have been creating a Rest client using jersey.
I am getting the following exception:
com.sun.jersey.api.client.ClientHandlerException: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:128)
at com.sun.jersey.api.client.Client.handle(Client.java:435)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:557)
at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:69)
at com.sun.jersey.api.client.WebResource$Builder.put(WebResource.java:475)
Below is my rest client:
public class RestClient {
private WebResource webResource;
private Client client;
private static String BASE_URI;
public RestClient(String url)
{
BASE_URI = url;
}
private void connect() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
client = Client.create(config);
client.setReadTimeout(50000);
webResource = client.resource(BASE_URI);
}
private void disconnect() {
client.destroy();
}
public TResponse topup(TRequest request) {
TResponse respone=null;
try{
System.out.println("::::::::::::::::start");
this.connect();
System.out.println("connected to base URL "+BASE_URI);
ClientResponse clientRequest = webResource.path("/topup").accept(MediaType.APPLICATION_XML).put(ClientResponse.class, request);
respone = (TopUpResponse)clientRequest.getEntity(TopUpResponse.class);
this.disconnect();
}
catch(Exception e){
e.printStackTrace();
}
System.out.println(":::::::::finish");
return respone;
}
}
Please help me to sort out this exception. Thanks in advance.

Do you have #XxmlRootElement annotation. Please read this article for more details

With jersey api all seems easy:
GET call.
Client client = Client.create();
WebResource webResource = client.resource("http://sample.com/rest_service");
MultivaluedMap queryParams = new MultivaluedMapImpl();
queryParams.add("PARAM1", param1);
queryParams.add("PARAM2", param2);
RESTResult s = webResource.queryParams(queryParams)
//Check the return type of the service
.accept(MediaType.APPLICATION_JSON)
//Put a object with XmlRootElement to map the result
.get(RESTResult .class);
println(s.status);
//Also you can return the result in a string
String s = webResource.queryParams(queryParams).get(String.class);
RESTResult code
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class RESTAuthorizationResult
{
public String status = "";
public String message = "";
}

Related

How to reset/remove/clear the request body in rest-assured

I have to pass form-parameter as the body to my request. When I try
Response post = request.urlEncodingEnabled(true).log().all().config(RestAssured.config()
.encoderConfig(EncoderConfig.encoderConfig()
.encodeContentTypeAs("x-www-form-urlencoded", ContentType.URLENC)))
I am getting the error message as "You can either send form parameters OR body content in POST, not both!"
When I checked the log, previous api's response passed as body to this request. How to remove/reset/clear the body and pass only the form-parameter.
You should always use a new RequestSpecification Instance for each request.
Before each new request call a function like:
public void beforeNewRequest(){
restUtils.resetRestAssured(); //reset existing instance
restUtils = RestUtils.getInstance(); //get new instance
}
RestUtil.java class
public class RestUtils {
private static RestUtils apiUtilsInstance = null;
private RequestSpecification httpRequest;
private RestUtils() {
httpRequest = RestAssured.given();
}
public static RestUtils getInstance() {
if (apiUtilsInstance == null)
apiUtilsInstance = new RestUtils();
return apiUtilsInstance;
}
public RequestSpecification getRequestSpecification() {
return httpRequest;
}
public void resetRestAssured() {
apiUtilsInstance = null;
}
}

java rest web service by post method

I am trying to do a java rest web service using "POST" method.But i am unable to access the passed parameter. Here is my client part to invoke the web service.
public static void main(String[] args) {
try {
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/wsRevDash/rest/post/testing");
Form form=new Form();
form.add("sc","pqr");
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class,form);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
And here is my java rest web service.
#POST
#Path("testing")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String createDataInJSON(#FormParam("sc") String data) {
System.out.println("Hello"+data);
JSONObject jObjDevice = new JSONObject();
jObjDevice.put("Hello",data);
return jObjDevice.toJSONString();
}
When i run on SoapUI,I am getting {"Hello":null}.
Please suggest me some way to cope with this.
Try changing form to a String:
String input = new Gson().toJson(form);
And pass in input to the response:
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class,input);
And amend your web service to something like:
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
public Response createDataInJSON(String data) {
String result = "Hello: " + data;
return Response.status(200).entity(result).build();
}
And you need to remove 'testing' from your initial path:
WebResource webResource = client.resource("http://localhost:8080/wsRevDash/rest/post/testing"); <---- here
And include a slash before it in the web service:
#Path("/testing")

Jersy REST service does not return object value from HashMap

We have created the Jersy REST service.
We are returning response object with 10 String fields and one Hash Map in format specified in below code snippet.
We could receive all the 10 string field values.
We can also see the HashMap with key/values when access it from client program.
CustomObject in HashMap became String when access it from client program.
so it throws exception
Listcom.tetherfi.restful.model.AppTypeData#2dc0f069
Test
err: java.lang.ClassCastException: java.lang.String cannot be cast to com.tetherfi.restful.model.AppTypeData.
We use Moxy to do the mapping. Please advise whether there is a way to retain the object value.
Response object from Jersy service
#XmlRootElement
public class ServiceRespParams {
private String param1;
private String param2;
private String param3;
private String param4;
private String param5;
private HashMap<String,ArrayList<AppTypeData>>hm;
public HashMap<String, ArrayList<AppTypeData>> getHm() {
return hm;
}
public void setHm(HashMap<String, ArrayList<AppTypeData>> hm) {
this.hm = hm;
}
Client code
public class Client {
public ServiceResponse postRequest(ServiceRequest request) {
Logger logger = Logger.getLogger("JerseyClient");
ServiceResponse serviceResponse = null;
WebTarget webTarget = null;
Response response = null;
// creating client with MOXy JSON
Client client = ClientBuilder.newClient();
try {
String url = "http://localhost:9080/Rest_ProxyLayer/webapi/doc01";
logger.info("Sending Request.... "+url);
webTarget = client.target(url).property(ClientProperties.CONNECT_TIMEOUT, 1000)
.property(ClientProperties.READ_TIMEOUT, 1000);
logger.info("Request Sent...");
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
response = invocationBuilder.get();
logger.info("Response Status :"+response.getStatus());
serviceResponse = response.readEntity(ServiceResponse.class);
System.out.println("Response from service"+ serviceResponse.getHm().get("CreditCard").get(0).getParam1());
} catch (Exception e) {
logger.error("Error!! Check connection..", e);
e.printStackTrace();
}
return serviceResponse;
}
}
It throws class cast exception when try to access the method.
System.out.println("Response from service"+ serviceResponse.getHm().get("CreditCard").get(0).getParam1());
Output from Rest service. Hashmap entries are below. It shows object but it seems to be converted to string.
HM: {CreditCard=[com.tetherfi.restful.model.AppTypeData#1b6c278e, com.tetherfi.restful.model.AppTypeData#208f5a00]}
Thanks
Vinoth

Adding authorization header to Jersey SSE Client request

I am using Jersey client to connect to an SSE stream. The server requires that I add a header to the http request for authorization, but I can't figure out how to add the header.
Here is my code:
Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
WebTarget target = client.target(baseurl + "/v1/devices/events/");
eventSource = EventSource.target(target).build();
eventSource.register(getEventListener());
eventSource.open();
Here is an example of the header I need to add:
Authorization: Bearer 38bb7b318cc6898c80317decb34525844bc9db55
It would be something like this for Basic Authentication:
Client client = ClientBuilder.newClient();
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder().build();
client.register(feature);
client.register(SseFeature.class);
WebTarget target = client.target(baseurl + "/v1/devices/events/")
.property(HttpAuthenticationFeature.HTTP_AUTHENTICATION_BASIC_USERNAME, "...")
.property(HttpAuthenticationFeature.HTTP_AUTHENTICATION_BASIC_PASSWORD, "...");
...
You already get the password encoded by Jersey.
And if it is a token:
Client client = ClientBuilder.newClient();
WebTarget target = client.target(baseurl + "/v1/devices/events/")
.request("...")
.header(HttpHeaders.AUTHORIZATION, "Bearer " + "... encoded token ...");
Hope it helps!
In case someone would want to add the bearer token header at the Client entity level itself, rather than at the Request entity level (in my case I had a factory method for returning preconfigured Client entities, so I had no way of adding the authorization header within the factory method, as .header(...) becomes available only after you go through the ClientBuilder.newBuilder().register(...).build().target(...).request(...) call chain, as of Jersey 2.x):
// client is a javax.ws.rs.client.Client entity
Feature feature = OAuth2ClientSupport.feature("YOUR_BEARER_TOKEN");
client.register(feature);
// now you can use client.target(...).request(...).post(...), without calling .header(...) after .request(...)
Unfortunately (as you may have guessed) this requires a new dependency: org.glassfish.jersey.security:oauth2-client
<dependency>
<groupId>org.glassfish.jersey.security</groupId>
<artifactId>oauth2-client</artifactId>
<version>2.15</version>
</dependency>
// Using SSL + Header Key
uri = UriBuilder.fromUri(sslUrl).port(sslServerPort).build();
sslConfig = SslConfigurator.newInstance().trustStoreFile(trustStoreFile).trustStorePassword(trustStorePassword);
sslContext = sslConfig.createSSLContext();
client = ClientBuilder.newBuilder().sslContext(sslContext).build();
target = client.target(uri).path(path);
Entity<?> entity = Entity.entity(Object, MediaType.APPLICATION_JSON);
response = target.request().header("key","value").post(entity);
// Using UserName & Password + Header Key
uri = UriBuilder.fromUri(url).port(serverPort).build();
basicAuth = HttpAuthenticationFeature.basic(username, userPassword);
client = ClientBuilder.newBuilder().register(basicAuth).build();
target = client.target(uri).path(path);
Entity<?> entity = Entity.entity(Object, MediaType.APPLICATION_JSON);
response = target.request().header("key","value").post(entity);
// Using only Header Key
uri = UriBuilder.fromUri(url).port(serverPort).build();
client = ClientBuilder.newBuilder().build();
target = client.target(uri).path(path);
Entity<?> entity = Entity.entity(Object, MediaType.APPLICATION_JSON);
response = target.request().header("key","value").post(entity);
Hope this helps you with your problem.
Here is the complete examples
ClientConfig clientConfig = new ClientConfig();
Client client = ClientBuilder.newClient(clientConfig);
WebTarget webTarget = client.target("http://localhost:8080/MyApp/customer/");
Invocation.Builder invocationBuilder =
webTarget.request(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, "your
secret key");
response = invocationBuilder.get();
output = response.readEntity(String.class);
Dependency for jersey client
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.25.1</version>
</dependency>
Try this:
Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, "Bearer38bb7b318cc6898c80317decb34525844bc9db55");
I realize this question is a year old but since there are not a lot to be found on that subject, I'll share my solution.
Based on suggested OAuth2Feature, I came up with this solution:
Create a custom feature. Feature will reference a custom filter
Create a custom filter of priority HEADER_DECORATOR
Create a HeaderProvider interface. Provider will be passed to the filter
Register the WebClient with the custom feature
Header provider interface
#FunctionalInterface
public interface ISseHeaderProvider {
Map<String, String> getHeaders();
}
Custom feature
public class SseHeaderSupportFeature implements Feature {
private final SseHeaderSupportFilter filter;
public SseHeaderSupportFeature(ISseHeaderProvider provider) {
this.filter = new SseHeaderSupportFilter(provider);
}
#Override
public boolean configure(FeatureContext context) {
context.register(filter);
return true;
}
}
Custom filter
#Priority(Priorities.HEADER_DECORATOR)
public class SseHeaderSupportFilter implements ClientRequestFilter {
private final ISseHeaderProvider provider;
public SseHeaderSupportFilter(#NotNull ISseHeaderProvider provider) {
this.provider = provider;
}
#Override
public void filter(ClientRequestContext request) throws IOException {
provider.getHeaders().forEach((k, v) -> request.getHeaders().add(k, v));
}
}
Usage
ISseHeaderProvider provider = () -> MapBuilder.<String, String>builder().add("Authorization", "Bearer ...").build();
Client client = ClientBuilder.newBuilder()
.register(SseFeature.class)
.register(new SseHeaderSupportFeature(provider))
.build();
WebTarget target = client.target(UriBuilder.fromPath(getUrl()));
//EventSource eventSource = ....
This solution is generic and allows you to easily add an Authorization header without having to add another dependency.
Following answer is useful:
Server Sent Event Client with additional Cookie
It use a customized WebTarget to add cookie and the same way on header also work.
public class AuthorizationHeaderWebTarget implements WebTarget {
private WebTarget base;
private String token;
public AuthorizationHeaderWebTarget(WebTarget base, String token) {
this.base = base;
this.token = token;
}
// Inject that cookie whenever someone requests a Builder (like EventSource does):
public Invocation.Builder request() {
return base.request().header(HttpHeaders.AUTHORIZATION, token);
}
public Invocation.Builder request(String... paramArrayOfString) {
return base.request(paramArrayOfString).header(HttpHeaders.AUTHORIZATION, token);
}
public Invocation.Builder request(MediaType... paramArrayOfMediaType) {
return base.request(paramArrayOfMediaType).header(HttpHeaders.AUTHORIZATION, token);
}
public Configuration getConfiguration() {
return base.getConfiguration();
}
//All other methods from WebTarget are delegated as-is:
public URI getUri() {
return base.getUri();
}
public UriBuilder getUriBuilder() {
return base.getUriBuilder();
}
public WebTarget path(String paramString) {
return base.path(paramString);
}
public WebTarget matrixParam(String paramString, Object... paramArrayOfObject) {
return base.matrixParam(paramString, paramArrayOfObject);
}
public WebTarget property(String paramString, Object paramObject) {
return base.property(paramString, paramObject);
}
public WebTarget queryParam(String paramString, Object... paramArrayOfObject) {
return base.queryParam(paramString, paramArrayOfObject);
}
public WebTarget register(Class<?> paramClass, Class<?>... paramArrayOfClass) {
return base.register(paramClass, paramArrayOfClass);
}
public WebTarget register(Class<?> paramClass, int paramInt) {
return base.register(paramClass, paramInt);
}
public WebTarget register(Class<?> paramClass, Map<Class<?>, Integer> paramMap) {
return base.register(paramClass, paramMap);
}
public WebTarget register(Class<?> paramClass) {
return base.register(paramClass);
}
public WebTarget register(Object paramObject, Class<?>... paramArrayOfClass) {
return base.register(paramObject, paramArrayOfClass);
}
public WebTarget register(Object paramObject, int paramInt) {
return base.register(paramObject, paramInt);
}
public WebTarget register(Object paramObject, Map<Class<?>, Integer> paramMap) {
return base.register(paramObject, paramMap);
}
public WebTarget register(Object paramObject) {
return base.register(paramObject);
}
public WebTarget resolveTemplate(String paramString, Object paramObject) {
return base.resolveTemplate(paramString, paramObject);
}
public WebTarget resolveTemplate(String paramString, Object paramObject, boolean paramBoolean) {
return base.resolveTemplate(paramString, paramObject, paramBoolean);
}
public WebTarget resolveTemplateFromEncoded(String paramString, Object paramObject) {
return base.resolveTemplateFromEncoded(paramString, paramObject);
}
public WebTarget resolveTemplates(Map<String, Object> paramMap) {
return base.resolveTemplates(paramMap);
}
public WebTarget resolveTemplates(Map<String, Object> paramMap, boolean paramBoolean) {
return base.resolveTemplates(paramMap, paramBoolean);
}
public WebTarget resolveTemplatesFromEncoded(Map<String, Object> paramMap) {
return base.resolveTemplatesFromEncoded(paramMap);
}
}
Following is the code to use it:
EventSource eventSource = new EventSource(new AuthorizationHeaderWebTarget(target, token));
eventSource.register(new EventListener() {
public void onEvent(final InboundEvent inboundEvent) {
//...
}
});
If you use jercy client using header in websource
Client client=Client.create();
WebResource webresource=client.resource(urlLink);
ClientResponse clientResponse=webresource.header("authorization", accessToken)
.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);

How to send requests and receive responses to/from an Apache CXF-based service?

I have several servlets, which
take JSON-encoded requests as inputs,
process them and
return responses to the client as JSON-encoded objects.
Up to now I used Android as client (sample Android code see below).
Now I want to write a plain old Java program, which would send requests and receive the responses (do the same as the Android code). For this purpose I wrote a Java test (code see below, section Java code) and ran it.
At the client side I get this error:
21:43:38.930 [main] ERROR r.a.c.t.TestAcceptanceProcedure1 -
java.io.IOException: Server returned HTTP response code: 405 for URL: http://myserver/myapp/rest/GetUserIdService
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441) ~[na:1.6.0_23]
at testclient.TestAcceptanceProcedure1.test(TestAcceptanceProcedure1.java:47) ~[test-classes/:na]
In the server log, I see this message:
WARNING: No operation matching request path "/myapp/rest/GetUserIdService" is found, Relative Path: /, HTTP Method: GET, ContentType: */*, Accept: text/html,image/gif,image/jpeg,*/*,*/*;q=.2,. Please enable FINE/TRACE log level for more details
Question: How should I change my Java test to fix this error?
Note that the server is up and running (when I execute the Android code, it works).
Android code:
Sending the request and receiving the response:
final GetSimulationStatusRequest request = new GetSimulationStatusRequest();
final String json = Utils.convertToJson(request, getClass());
final String serverUrl = Utils.getServerUrl(this, "GetSimulationStatusService");
final IGetSimulationStatusAsyncTask getSimulationStatusTask =
asyncTaskFactory.createGetSimulationStatusAsyncTask(getWebServiceHelper());
Utils.setRequestAndServerUrl(json, serverUrl, getSimulationStatusTask);
final GetSimulationStatusResponse simulationStatusReponse =
getSimulationStatusTask.get();
Utils.convertToJson:
public static String convertToJson(final Object aRequest, Class<? extends Activity> aClass) {
final ObjectMapper mapper = new ObjectMapper();
String json = null;
try {
json = mapper.writeValueAsString(aRequest);
} catch (final JsonProcessingException exception) {
Log.e(aClass.getSimpleName(), exception.getLocalizedMessage(),
exception);
}
return json;
}
Utils.setRequestAndServerUrl:
public static void setRequestAndServerUrl(final String aJson,
final String aServerUrl, final IAsyncTask aTask) {
aTask.addNameValuePair("request", aJson);
aTask.sendRequest(new String[] { aServerUrl });
}
GetSimulationStatusAsyncTask:
public class GetSimulationStatusAsyncTask
extends AsyncTask<String, String, GetSimulationStatusResponse>
implements IGetSimulationStatusAsyncTask {
private static final String TAG = GetSimulationStatusAsyncTask.class.getSimpleName();
private IWebServiceTaskHelper helper;
private ICcpResponseParser<GetSimulationStatusResponse> responseParser =
new CcpResponseParser<GetSimulationStatusResponse>();
public GetSimulationStatusAsyncTask(final IWebServiceTaskHelper aHelper) {
helper = aHelper;
}
#Override
public void addNameValuePair(final String aName, final String aValue) {
helper.addNameValuePair(aName, aValue);
}
#Override
protected GetSimulationStatusResponse doInBackground(String... aArgs) {
return (GetSimulationStatusResponse)Utils.processResponse(this.helper, TAG, responseParser,
GetSimulationStatusResponse.class, aArgs);
}
#Override
public void sendRequest(final String[] aArgs) {
execute(aArgs);
}
}
Java code:
#Test
public void test() throws JsonProcessingException, MalformedURLException {
final GetUserIdRequest request = new GetUserIdRequest();
request.setDeviceId("PC1");
final String requestAsString = convertToJson(request);
final String serverUrl = getServerUrl("GetUserIdService");
final URL url = new URL(serverUrl);
HttpURLConnection connection = null;
InputStream inputStream = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("request", requestAsString);
connection.connect();
inputStream = connection.getInputStream();
final String responseAsString = IOUtils.toString(inputStream);
LOGGER.debug("responseAsString: " + responseAsString);
} catch (final IOException exception) {
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
}
private String convertToJson(final GetUserIdRequest aRequest) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(aRequest);
}
private String getServerUrl(final String aServiceName)
{
return "http://myserver.com/myapp/rest/" + aServiceName;
}
Update 1 (09.10.2013 12:23 MSK):
#Path("/GetSimulationStatusService")
public class GetSimulationStatusService extends BaseCcpService {
private GetSimulationStatusRequestParser requestParser =
new GetSimulationStatusRequestParser();
#POST
#Produces("text/plain")
public String getSimulationStatus(#FormParam("request") final String aRequestJson)
throws JsonProcessingException
{
final GetSimulationStatusRequest request = requestParser.convert(aRequestJson);
final GetSimulationStatusResponse response = new GetSimulationStatusResponse();
response.setRequestId(request.getId());
response.setCycle(getPersistence().getCurrentCycle(request.getUserId()));
response.setLabourForce(getPersistence().getLabourForceSimulationParameter(
request.getUserId()));
return getObjectMapper().writeValueAsString(response);
}
}
Update 2 (09.10.2013 20:48 MSK): When I change the code like shown below, I get 500 HTTP response. At the server side, the aRequest argument of the method GetUserIdService.getUserId is null.
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("request", requestAsString);
connection.setRequestMethod("POST"); // Added this line
connection.connect();
Update 3 (09.10.2013 23:15): This one works:
#Test
public void test() throws JsonProcessingException, MalformedURLException
{
final GetUserIdRequest request = new GetUserIdRequest();
request.setDeviceId("PC1");
final String requestAsString = convertToJson(request);
final String serverUrl = getServerUrl("GetUserIdService");
final URL url = new URL(serverUrl);
HttpURLConnection connection = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.connect();
outputStream = connection.getOutputStream();
IOUtils.write("request=" + requestAsString, outputStream);
inputStream = connection.getInputStream();
final String responseAsString = IOUtils.toString(inputStream);
LOGGER.debug("responseAsString: " + responseAsString);
} catch (final IOException exception) {
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
The 405 HTTP error code means that given method (GET) is not supported by the endpoint. Probably instead of GET request you want to send POST. I don't know what kind of request is sent by Android client.
Do you have endpoint specification/documentation?
Here you'll find information how to invoke POST using plain Java API. If you can use external libraries in your test then it can be achieved a lot easier using RESTEasy.

Categories