Android: RESTfull API called from `retrofit 2` says `Method Not Allowed` - java

I have developed a web service using Java and Jersey. Now I am trying to connect into it, call its methods and get data, using android.
Below is the related part of the web service.
import bean.PatientBean;
import bean.UserBean;
import db.PatientImpl;
import db.PatientInterface;
import db.UserImpl;
import db.UserInterface;
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.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/patient")
public class PatientJSONService
{
#POST
#Path("/getPatientById/{Id}")
#Produces(MediaType.APPLICATION_JSON)
public PatientBean getPatientById(#PathParam("Id")String Id)
{
PatientInterface patinetInterface=new PatientImpl();
PatientBean patientById = patinetInterface.getPatientById(Id);
return patientById;
}
}
In my android application, I am using Retrofit 2 to call the above REST method.
private void restCall()
{
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
YourEndpoints request = retrofit.create(YourEndpoints.class);
Call<PatientBean> yourResult = request.getPatientById("ERTA001");
yourResult.enqueue(new Callback<PatientBean>() {
#Override
public void onResponse(Call<PatientBean> call, Response<PatientBean> response) {
try {
// Log.d("MainActivity", "RESPONSE_A: " + response.body().toString());
Log.d("MainActivity", "RESPONSE: " + response.errorBody().string());
}
catch(Exception e)
{
e.printStackTrace();
}
}
#Override
public void onFailure(Call<PatientBean> call, Throwable t) {
try {
t.printStackTrace();
Log.d("MainActivity", "RESPONSE: "+"FAILED");
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
}
Below is my EndPoint interface
public interface YourEndpoints {
#POST("patient/getPatientById/{Id}")
Call<PatientBean>getPatientById(#Body String Id);
}
However When I run the code, I get a HTML response from Apache Tomcat Server, which basically says HTTP Status 405 - Method Not Allowed.
How can I solve this issue?

Change your ws endpoint to #GET, and then change your rest client to below code:
#GET("patient/getPatientById/{Id}")
Call<PatientBean>getPatientById(#Path("Id") String Id);
GET should be used to retrieve data from the server.
POST should be used to send data to the server.

If you are using GSON along with RetroFit, you should not need your own implementation within getPatientById(). And, yes you should be using a GET method.
public interface PatientService {
#GET("patient/getPatientById/{Id}")
Call<PatientBean> getPatientById(#Path("Id") String id);
}
If your PatientBean is setup correctly, you should be able to call the following to get a fully formed instance of the class:
PatientService service = retrofit.create(PatientService.class);
Call<PatientBean> call = service.getPatientById("ERTA001");
call.enqueue(new Callback<PatientBean> {
#Override
public void onResponse(Call<PatientBean> call, Response<PatientBean> response) {
mPatientBean = response.body();
}
#Override
public void onFailure(Call<PatientBean> call, Throwable throwable) {
throwable.printStackTrace();
}
});

Related

Getting Bad Request from API Post Call using Retrofit

I have created the next savePartner() method inside PartnerController class like this:
public void savePartner(View partnerForm) {
context = partnerForm.getContext();
PartnerDto partner = createPartner(partnerForm);
String jsonPartner = convert(partner);
Call<String> call = appAPI.savePartner("application/json", jsonPartner);
Log.i(TAG, "getPartners submitted to API.");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
String responseCall = response.body();
} else {
System.out.println(response.errorBody());
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
TableRow rowHeader = new TableRow(context);
TextView name = new TextView(context);
name.setText(t.getMessage());
rowHeader.addView(name);
//partnerForm.addView(rowHeader);
t.printStackTrace();
}
});
}
And I have added the method savePartner to retrofit interface:
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface IApplicationApi {
#GET("Partner/")
//Call<List<PartnerDto>> loadPartners(#Header("Authorization") String authorization);
Call<List<PartnerDto>> loadPartners();
#POST("Partner/")
Call<String> savePartner(#Header("Content-Type") String content_type, #Body String partner);
}
When I execute the post call in postman works (code 200), but I debugged the previous in android-studio and I obtain the next error:
Response{protocol=http/1.1, code=400, message=Bad Request, url=https://localhost/Partner/}
And I can't obtain more info about the error. The request is the next:
Request{method=POST, url=https://localhost/Partner/, tags={class retrofit2.Invocation=administracion.MyProject.APIService.IApplicationApi.savePartner() [application/json, {"email":null,"id":4,"lastname":null,"name":"me","phonenumber":0,"productamount":0.0,"productquantity":0.0,"registereddate":"2021-02-10T00:00:00"}]}}
I put these values on postman, and it works like a charm. I don't know why this request is bad. Could someone give me some clue?
Thanks in advance for the help! ^^
Updated 01/03/2021
I can get the cause of the error using httplogginginterceptor, I share this in case someone more need it :)
https://howtodoinjava.com/retrofit2/logging-with-retrofit2/
you can use HttpLoggingInterceptor and log your request. I hope you are missing a field in your json body or request body
try replacing this #POST("Partner/")
with #POST("Partner")

How to handle `jsonParseException` from Jackson parser in Java

This is my first time writing code in Java I m running in to JsonParseException when I send invalid json data in my request body. I know I have to catch this error at the point where json body is getting parsed I don't have any idea how it works in my code. It would be great if someone can explain me how to catch the error and send the 400 response instead of the 500 which is being thrown as Uncaught server error and also how the request body is getting parsed.
I m using JAXRS: 2.0.1 and jackson for Json parsing it seems. I also added an exceptionMapper to handle these exceptions but it doesn't seem to work.
//./src/main/java/com.test.rest/Routes.java
package.com.test.rest;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
public class Routes implements Xyz{
#POST
#Path("test")
#Consumes({MediaType.APPLICATION_JSON})
#Produces(MediaType.APPLICATION_JSON)
public Response testJson(#Context HttpHeaders headers, #HeaderParam("abc") String abc, TestRequest request){
if(abc == null){
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid headers").build();
}else{
return Response.status(Response.Status.OK).entity(request.gettestData()).build();
}
}
}
./src/main/java/com.test.rest/TestRequest.java
package.com.test.rest;
public class TestRequest {
private String testData;
public TestRequest () {
}
public TestRequest(String testData){
setTestData(testData);
}
public String gettestData(){
return testData;
}
public void setTestData(String testData){
if(testData!=null){
testData = testData.toLowerCase();
}
this.testData =testData;
}
}
./src/main/java/com.test.rest/JsonParseExceptionMapper.java
package.com.test.rest;
import com.fasterxml.jackson.core.JsonParseException;
import javax.annotation.Priority;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.core.*;
#Provider
#Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
#Override
public Response toResponse(final JsonParseException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("Cannot parse JSON")
.type(MediaType.TEXT_PLAIN)
.build();
}
}
All the files are in same level and I m using gradle to build my code
this is my request body
{
"testData":
}
//com.fasterxml.jackson.core.JsonParseException: Unexpected character

How to get TWILIO CALL info using Java Rest Client

Having next code, which use RestEasy to get to a Twilio CALL info:
import java.util.Base64;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import com.twilio.rest.api.v2010.account.Call;
public class RestGetCallInfo1 {
public static void main(String[] args) {
try {
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget = client.target("https://api.twilio.com/2010-04-01/Accounts/AC99999999/Calls/CA77777777777.json");
String credentials = "AC99999999:888888888";
String base64encoded = Base64.getEncoder().encodeToString(credentials.getBytes());
Response response = target.request().header(HttpHeaders.AUTHORIZATION, "Basic " + base64encoded).get();
int status = response.getStatus();
if (status == 200) { //OK
Call call = response.readEntity(Call.class); //<------------- This fails!
System.out.println(call);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
}
I want to ask you:
What 'Rest' libraries/tools does twilio-7.47.2-jar-with-dependencies.jar use inside (in order to use that instead of RestEasy)?
How can I get the JSON call object properly? with the actual code I get:
javax.ws.rs.ProcessingException: Unable to find a MessageBodyReader of content-type application/json and type class com.twilio.rest.api.v2010.account.Call
EDIT: I am able to get the Call info in JSon format with:
String call = response.readEntity(String.class);

Get and save SOAP incoming request (XML) at the server request method ? without handler

I am going to create and install web service(org.apache.cxf) into Jboss fuse as blueprint bundle and this is how my web service implementation concrete class look likes.
I want to access SOAP message at the server request and save request XML (including header, body). Still, i am unable to access SOAP message. How can I achieve this without using handler or interceptor?
I am using org.apache.cxf.jaxws
SOAP message is type of org.apache.cxf.binding.soap.SoapMessage
package ats.emvo.callback;
import java.io.InputStream;
import javax.annotation.Resource;
import javax.xml.ws.WebServiceContext;
import javax.jws.WebService;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.io.CachedOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProductService implements IProductService {
private static final Logger _log = LoggerFactory.getLogger(ProductService.class);
#Resource
private WebServiceContext webServiceContext;
#Override
public void ConfirmProductMasterDataStatus() {
try {
if (webServiceContext != null) {
WrappedMessageContext mc = (WrappedMessageContext) webServiceContext.getMessageContext();
if (mc != null) {
SoapMessage soapMessage = (SoapMessage) mc.getWrappedMessage();
if(soapMessage != null) {
XMLStreamReader body = soapMessage.getContent(XMLStreamReader.class);
_log.info("soap message messConInputStream"+ body.toString());
}else {
_log.info("soapMessage is null");
}
}else {
_log.info("WrappedMessageContext is null");
}
}
} catch (Exception e) {
_log.error("Error", e);
}
}
No, you can't do it in your service class, as at that stage the SoapMessage already get consumed.
You have to use an interceptor at very early stage, some code like
public class SaveSoapInterceptor extends AbstractPhaseInterceptor<Message> {
public SaveSoapInterceptor() {
super(Phase.RECEIVE);
addBefore(LoggingInInterceptor.class.getName());
}
public void handleMessage(Message message) throws Fault {
InputStream is = message.getContent(InputStream.class);
if (is != null) {
CachedOutputStream bos = new CachedOutputStream();
try {
IOUtils.copy(is, bos);
bos.flush();
is.close();
message.setContent(InputStream.class, bos.getInputStream());
bos.close();
String soapMessage = new String(bos.getBytes());// here you get the soap message
}
}
}

GWT RequestBuilder - Cross Site Requests

I'm trying to make Cross Site Request using GWT Request builder, which i couldn't get it to work yet. As you can see, this is much of a Sample GWT Project and i have gone through https://developers.google.com/web-toolkit/doc/latest/tutorial/Xsite . But still i'm missing something.
I'm Posting the code here. What am i missing ..?
package com.gwt.reqbuilder.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
public class GWTRequestBuilder implements EntryPoint
{
private static final String JSON_URL = "http://localhost:8000/?q=ABC&callback=callback125";
public void onModuleLoad()
{
GWTPOSTHTTP();
}
public void GWTPOSTHTTP()
{
String postUrl="http://localhost:8000";
String requestData="q=ABC&callback=callback125";
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, postUrl);
try {
builder.sendRequest(requestData.toString(), new RequestCallback()
{
public void onError(Request request, Throwable e)
{
Window.alert(e.getMessage());
}
public void onResponseReceived(Request request, Response response)
{
if (200 == response.getStatusCode())
{
Window.alert(response.getText());
} else {
Window.alert("Received HTTP status code other than 200 : "+ response.getStatusText());
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
Window.alert(e.getMessage());
}
}
}
Actually we can make Cross Site Requests from GWT RequestBuilder if we can set in Servlet Response Header
Response.setHeader("Access-Control-Allow-Origin","http://myhttpserver");
It's working Cool , if anyone need the GWT Project and Python Servlet, please do let me know, i can upload the files.
GWT Client Code : https://github.com/manikandaraj/MLabs/tree/master/GWT/GWTClient
You've missed to finish reading the tutorial.
Direct quote from the tutorial :
The RequestBuilder code is replaced by a call to the getJson method. So you no longer need the following code in the refreshWatchList method:
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Couldn't retrieve JSON");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError("Couldn't retrieve JSON (" + response.getStatusText()
+ ")");
}
}
});
} catch (RequestException e) {
displayError("Couldn't retrieve JSON");
}
Which is broadly what you've got, and should be replaced by a JSNI function given in the tutorial a few lines below :
/**
* Make call to remote server.
*/
public native static void getJson(int requestId, String url,
StockWatcher handler) /*-{
var callback = "callback" + requestId;
// [1] Create a script element.
var script = document.createElement("script");
script.setAttribute("src", url+callback);
script.setAttribute("type", "text/javascript");
// [2] Define the callback function on the window object.
window[callback] = function(jsonObj) {
// [3]
handler.#com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
window[callback + "done"] = true;
}
...

Categories

Resources