I have been working with Spring MVC controllers and now I landed on a problem. So basically what I want to do is if I send a POST request with whatever the input is, I should get the exact same response what the input was.
I have just this one controller and tried to do the following:
import lombok.Data;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
#RestController
public class Controller {
#Data
public class DataField {
public String content;
}
#GetMapping("/echo")
public void sayHello() {
}
#PostMapping("/echo")
public String postHello(#RequestBody DataField data) {
System.out.println("post: " + data);
DataField content = data;
return content.content;
}
If I post something i.e
String inputJson = """
{"a":1,"b":2,"c":3}""";
how am I able to get the same response input back from the same address?
Current error:
Expected: "{\"a\":1,\"b\":2,\"c\":3}"
but: was ""
Related
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
I have a sample backend response coming as below:
When I try to map this response into the java object, I am getting following error.
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com.mc.membersphere.model.MemberSummaryLabel[] out of START_OBJECT token
Seems like the issue with the body tag coming from API. Which has array of objects. I need help, how to handle this body tag arrays value in Java mapping?
Backend API Response:
{
"body": [{
"pcp": "KASSAM, Far",
"er12M": "0",
"ipAdmits12M": "0",
"ipReAdmits12M": "0",
"rx12M": "0",
"pastMedicalHistory": " ",
"erCost12M": "0.0"
}
]
}
Java Program to get the Rest data into the Java objects is as below.
import java.util.Collections;
import java.util.Properties;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.mc.membersphere.model.MemberSummaryLabel;
import com.mc.membersphere.utility.PropertyUtil;
public class TestRestclient implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(TestApi.class, args); }
private static Properties prop = PropertyUtil.getProperties();
#Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String getMVPSummaryUrl = prop.getProperty("getmvpmembersummary.url");
String url = getMVPSummaryUrl+"/"+"CA";
ResponseEntity<MemberSummaryLabel[]> response = restTemplate.exchange(url, HttpMethod.GET,entity, MemberSummaryLabel[].class);
if(response.getStatusCode()== HttpStatus.OK) {
for(MemberSummaryLabel memberSummaryLabel : response.getBody())
{
System.out.println(memberSummaryLabel.pcp);
}
//System.out.println("Print response" + response);
}
else {
System.out.println("Error");
}
}
}
MemberSummaryLabel is as below.
import com.fasterxml.jackson.annotation.JsonProperty;
public class MemberSummaryLabel {
#JsonProperty("pcp")
public String pcp;
#JsonProperty("er12M")
public Integer er12M;
#JsonProperty("ipAdmits12M")
public Integer ipAdmits12M;
#JsonProperty("ipReAdmits12M")
public Integer ipReAdmits12M;
#JsonProperty("rx12M")
public Integer rx12M;
#JsonProperty("pastMedicalHistory")
public String pastMedicalHistory;
#JsonProperty("erCost12M")
public Double erCost12M;
}
I see, its an issue with your mapping. Your response is in "body" and body contains list of MemberSummaryLabel. So, you need to have one more class as mentioned below,
public class Body{
#JsonProperty("body")
public List<MemberSummaryLabel> memberSummaryLabelList;
}
And your exchange method should return NewClass.
ResponseEntity<Body> response = restTemplate.exchange(url, HttpMethod.GET,entity, Body.class);
And for, iteration use,
for(MemberSummaryLabel memberSummaryLabel : response.getBody().getMemberSummaryLabelList()){
}
I am trying to do a simple post request from React (client side) to Java server side. Here is my controller below.
package com.va.med.dashboard.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.va.med.dashboard.services.VistaServiceImpl;
import gov.va.med.exception.FoundationsException;
#RestController
#RequestMapping("/dashboard")
public class DashboardController {
#Autowired
private VistaServiceImpl vistaService;
#RequestMapping("/main")
String home() {
return "main route";
}
#RequestMapping("/rpc")
String test() throws FoundationsException {
vistaService.myAuth();
return "this is rpc route";
}
#RequestMapping(method = RequestMethod.POST, produces =
"application/json", value = "/vista")
#ResponseStatus(value = HttpStatus.ACCEPTED)
public String getVistaConnection(#RequestBody String ipString, #RequestBody String portString, #RequestBody String accessPin,
#RequestBody String verifyPin) {
System.out.println(ipString);
System.out.println(portString);
System.out.println(accessPin);
System.out.println(verifyPin);
vistaService.connect(ipString, portString, accessPin, verifyPin); // TO-DO populate with serialized vars
if (vistaService.connected) {
return "Connected";
} else {
return "Not Connected";
}
}
}
Below is my react axios post request
axios.post('/dashboard/vista', {
ipString: this.state.ipString,
portString: this.state.portString,
accessPin: this.state.accessPin,
verifyPin: this.state.verifyPin
})
.then(function (response){
console.log(response);
})
.catch(function (error){
console.log(error);
});
This is also the error that I am getting.
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing:
Can anyone please shed some light on this error message? I'm coming from a pure JavaScript background so a lot of things I just don't know for Java because it is automatically implemented inside of JavaScrips language.
Thanks again in advance!
You're doing it wrong.
Instead of
public String getVistaConnection(#RequestBody String ipString, #RequestBody String portString, #RequestBody String accessPin,RequestBody String verifyPin)
You should wrap those parameters in a class:
public class YourRequestClass {
private String ipString;
private String portString;
....
// Getter/setters here
}
and your controller method will look like:
public String getVistaConnection(#RequestBody YourRequestClass request)
From #Rajmani Arya:
Since RestContoller and #RequestBody suppose to read JSON body, so in your axios.post call you should put headers Content-Type: application/json
Try to replace all #RequestBody annotations with #RequestParam
public String getVistaConnection(#RequestParam String ipString, #RequestParam String portString, #RequestParam String accessPin, #RequestParam String verifyPin)
New to java programming and still learning. I've built a RESTful service and I'm trying to pass in a parameter for a GET routine and I'm getting back a state 400 saying that the "Request entity cannot be empty". When I call the non-parameterized GET, the data comes back just fine. I've stripped down all the functionality of the parameterized GET to just return a simple string and I'm still getting the same message. Searched all over and can't find anything that's very helpful.
Below is the code that I'm running for the service. The method "GetChildAllInfo" makes a call to a local mySQL instance and returns a list of objects; that one works just fine. The parameterized one returns nothing, not even an exception.
Any help would be tremendously appreciated. Even if it's a ridiculously simple solution like a syntax error that I may have missed. AND I'm willing to accept any other advice on what you see in the code as well. Thanks!
package allowanceManagerChild;
import java.util.Set;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
import javax.ws.rs.core.MediaType;
import com.google.gson.Gson;
#Path("allowanceManagerChild")
public class AllowanceManagerChild {
#Context
private UriInfo context;
/**
* Creates a new instance of AllowanceManagerChild
*/
public AllowanceManagerChild() {
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getJson() {
String response = "";
Set<Child> children = Child.GetAllChildInfo();
for (Child child : children){
Gson gson = new Gson();
String json = gson.toJson(child);
response = response + json;
}
return response;
}
#GET
#Path("/{childID}")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(int childID) {
String response = "";
try{
// Set<Child> children = Child.GetChildInfo(id);
// for (Child child : children){
// Gson gson = new Gson();
// String json = gson.toJson(child);
// response = response + json;
// }
response = "Made it here"; //Integer.toString(childID);
}
catch(Exception e){
response = e.toString();
}
return response;
}
/**
* PUT method for updating or creating an instance of AllowanceManagerChild
* #param content representation for the resource
*/
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public void putJson(String content) {
}
}
Adding the #PathParam annotation to the method parameter might help:
#GET
#Path("/{childID}")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(#PathParam("childID") int childID) {
See the RESTful Web Services Developer's Guide for more details.
I have a Play application with a POST route which will act as a RESTful API.
Whats the best way to get POST data within a controller? As you can see from my controller I have attempted this, however it doesn't appear to work correctly.
Routes:
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / controllers.Application.index()
GET /api/getMessages controllers.Application.getMessages()
POST /api/createMessage controllers.Application.createMessages()
Controller:
package controllers;
import play.*;
import play.mvc.*;
import static play.libs.Json.toJson;
import java.util.Map;
import models.*;
import views.html.*;
public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
public static Result createMessages(){
final Map<String, String[]> values = request().body().asFormUrlEncoded();
String from = values.get("from")[0];
String subject = values.get("subject")[0];
String message = values.get("message")[0];
Message.create(from, subject, message);
return ok(toJson("ok"));
}
public static Result getMessages(){
return ok(toJson(Message.all()));
}
}
Request:
Request Url: http://localhost:9000/api/createMessage
Request Method: POST
Status Code: 400
Params: {
"from": "hello#test.com",
"subject": "Hello",
"message": "World"
}
Try with DynamicForm:
public static Result createMessages(){
DynamicForm df = play.data.Form.form().bindFromRequest();
String from = df.get("from");
String subject = df.get("subject");
String message = df.get("message");
if(from != null && subject != null && message != null){
Message.create(from, subject, message);
return ok(toJson("ok"));
} else {
return ok(toJson("error"));
}
}
I'm pretty sure that author already found solution for those 2 years :), but today I was on same trouble and probably my nuance will help someone:
I used same methods to get POST parameters:
request().body().asFormUrlEncoded().get("from")[0];
And I got error too. But error was because of different POST type. So in my case I just was need to expect Multipart Form Data like in next variant:
request().body().asMultipartFormData().asFormUrlEncoded().get("from")[0];
So - just be a bit more careful with data that you are sending and data that you are expecting :)