Use #POST instead of #GET to get user input - java

I am a newbie to JSON. I wish to ask that how can I convert the following code from #GET to #POST so that I can retrieve the appdataid from user JSON input and not from the link.
AppDataService ads = new AppDataService();
#GET
#Path("/{appdataid}")
#Produces(MediaType.APPLICATION_JSON)
public AppData getAppData(#PathParam("appdataid")long appdataid){
return ads.getAppData(appdataid);
}
Code for AppDataService
public AppDataService(){
appdatas.put(1L, new AppData(1,"Success", " ", "123456"));
appdatas.put(2L, new AppData(2,"Failure", " ", "654321"));
}
public AppData getAppData(long id){
return appdatas.get(id);
}
Instead of user entering http://localhost:8080/gni/webapi/appdata/1 for the result
{
"id": 1,
"message": " ",
"status": "Success",
"token": "123456"
}
I hope that I can receive the user input with #POST and JSON format.
I have tried the following code but not working.
#POST
#Path("/{appdataid}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public AppData getAppData(#PathParam("appdataid")long appdataid){
return ads.getAppData(appdataid);
}
Thanks for everyone that willing to help me.

If you want to POST JSON to your resource, you need to define a POJO for it to deserialise the message body into, for example:
public class AppDataRequest {
#JsonProperty
private long id;
public long getId() {
return id;
}
}
The use this type for in the resource:
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public AppData getAppData(AppDataRequest appDataRequest){
return ads.getAppData(appDataRequest.getId());
}
Note, the #Path annotation no longer has appdataid templated, and the parameter does not have an annotation.
SIDE NOTE
I have to wonder what you are trying to achieve here. The HTTP methods can and should be used to help describe the behaviour of your system. A request to get data should use a GET resource. POST resources should be used for creating new data. Sometimes there are good reasons to break this convention (such as the lack of a message body in a GET request), but there are usually other ways around them. Everything about your example tells my it should be a GET request, but I do not know the specifics of you application, so feel free to ignore this if it does not apply.

I don't think you really need JSON for that. You can use #FormParam for such a simple payload (ID)
#POST
#Path("some_url")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)//optional
public AppData getAppData(#FormParam("appdataid")long appdataid){
return ads.getAppData(appdataid);
}
You can call your web service from a console (Jersey assumed)
WebTarget target = client.target(UriBuilder.fromUri("http://localhost:8088/Your_root_url").build());
try{
MultivaluedMap<String, Integer> formData = new MultivaluedHashMap<String, String>();
formData.add("appdataid", 1);
Response res= target.path("some_url").request().
post(Entity.entity(formData, MediaType.APPLICATION_FORM_URLENCODED));
AppData entity = (AppData) res.readEntity(AppData.class);
//System.out.println(entity);//if toString() is overriden
}catch(Exception e){
System.out.println(e);
return;
}
EDIT: The only reason I see for wanting to use a POST in this situation is securiry (and even that is arguable)

Related

Simple restful JSON POST with java as server and jquery as client

Before I ask my question I have to say that I have read more than 20 questions and articles about this problem and none of them could solve it.
My problem is I have a restful server in java like this:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(#RequestBody final String stringRequest, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
And I have tried different ways to send a json to this server with jquery (but all of them create errors):
$.ajax({
url:"/downloadByCode",
type:"POST",
data: JSON.stringify({"name":"value"}) });
415 "errors message" : "Content type 'application/x-www-form
urlencoded;charset=UTF-8' not supported", "type" :
"HttpMediaTypeNotSupportedError"
So I tried to fix it by adding contentType:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
400 "errors message" : "Could not instantiate JAXBContext for class
[class java.lang.String]: null; nested exception is
javax.xml.bind.JAXBException\n - with linked
exception:\n[java.lang.NullPointerException", "type"
:"HttpMessageConversionError"
I tried to send json object directly instead of JSON.stringify and it gives the same 400 error.
I tried to add different consumes to the #requestMapping but still no luck.
I tried to define my own class instead of JsonNode but it does not change anything.
Any ideas?
Please try to create new class :
public class InputData{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
Then
public void downloadByCode(#RequestBody InputData stringRequest, final HttpServletResponse response)
And
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
try #RequestBody final Map<String, String> stringRequest
also you will need consumes = "application/json" on the #RequestMapping because you have that in your AJAX call
You will get 400 if spring doesn't like the format in which you send your ajax - I've had so much trouble with this in the past and it seems better to just ignore header types and content types unless necessary
You might try sending your response back as a ResponseEntity instead of using the HttpServletResponse directly. My hunch is that second argument, the HttpServletRequest argument, is what is causing the problem. I've never used that. I've always send my response back using the spring mvc api.
With Jersey api you can try just:
#POST
public void downloadByCode(String stringRequest)
and I think you'll find the body of your post in stringRequest.
You can take request body as string with usage of org.springframework.http.HttpEntity<String> as request type, here is example with your code as base:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(final HttpEntity<String> request, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
But maybe it will be better to use also String as return type, if you are planning to return result as string value, like this:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public String downloadByCode(HttpEntity<String> request) {
String requestBody = request.getBody();
String result;
// ...
// some processings here to create the result text
// ....
return result;
}
I made simple application using Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven and JDK >= 1.7.
#clonning repository with sample
git clone git#github.com:mind-blowing/samples.git
#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text
#running application using maven spring-boot plugin
mvn spring-boot:run
After application will be started you can open http://localhost:8080 and you will see html page with simple usage of JQuery to send POST requests, text of request and response will visible on html page, in controller I added two handlers, first with usage of HttpEntity and second with usage of POJO.
Controller: SampleRestController.java
HTML page: index.html
Project: https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text
First of all If you are using maven you should add dependency for jackson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
or you can download the jar and put it in our project class path (you can use other mapper as well)
then you should create a model or DTO class where you can map your json
public class Data{
private String name;
pubilc Data(){}
//getter and setter
}
THEN you controller
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public Data downloadByCode(#RequestBody final Data data, final HttpServletResponse response)
{
//your code
return data;
}
AJAX CALL
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
(Optional)You can override behavior by telling object mapper not to fail on missing properties by defining the bean as follows:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return converter;
}
http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/
Looking at your errors, it's clear that you have configured 'Jaxb2RootElementHttpMessageConverter' or similar XML converter in your spring configuration. And since you have registerned an XML converter, the #RequestBody and #ResponseBody work based on the registered message converters.
So, to solve your problem, go with a JSON message converter such as 'MappingJacksonHttpMessageConverter'. Once you register a JSON message converter, create a bean class to hold your json data and use it with RequestBody as below:
// It has to meet the json structure you are mapping it with
public class YourInputData {
//properties with getters and setters
}
Update 1:
Since you have defined multiple message converters, Spring tries to use the first one available by default. In order to use specific message converter(in this case Jackson converter), you should specify 'Accept' header from client like below:
$.ajax({
headers: {
"Accept" : "application/json; charset=utf-8",
"Content-Type": "application/json; charset=utf-8"
}
data: "data",
success : function(response) {
...
} })
The final answer is a combination of a number of answers/comments in this question that I am going to summarize them here:
1- You have to make sure you have an appropriate json converter in your spring config such as MappingJacksonHttpMessageConverter (credits to #java Anto)
2- You have to create a POJO class with same structure as your json object (see #Vinh Vo answer)
3- Your POJO class cannot be an inline class unless it is a static class. It means it should have its own java file or it should be static. (credits to #NTyler)
4- Your POJO class can miss parts of your json object if you set it appropriately in your object mapper (see #Aman Tuladhar answer)
5- Your ajax call requires contentType:"application/json", and you should send your data with JSON.stringify
Here is the Final code that is working perfectly:
public static class InputData
{
private String name
public String getName()
{
return name;
}
public void setName(final String name
{
this.name = name;
}
}
#RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(#RequestBody final InputData request, final HttpServletResponse response)
{
try
{
String codes = request.getName();
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
And it is the jquery Ajax request:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
Delete the #ResponseBody on your downloadByCode method
Change your method downloadByCode() return type to String and then return the String
Response body will automatically convert the returned String to JSON and then use the data appropriately
I am not that well versed with java but as much as I know your java code must be something like this.
public class downloadByCode{
#GET
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response downloadByCode(#QueryParam("paramater1") final String parameter 1, #Context HttpServletRequest httpRequest) {
If this not helps you can keep you code somewhere and share it.

405 error returned when using POST method in Jersey

I'm using Jersey and have had no problem with GET and PUT calls but for some reason POST refuses to work; I keep getting a 405 returned.
I've tried multiple permutations for the signature on my method and I'm starting to wonder if there is something else I'm missing.
Here's an example of what won't work:
Server-side:
#Path("/tmm")
public class TmmRes {
#POST
#Path("/mypost")
#Consumes(MediaType.APPLICATION_JSON)
public Response postTest(String input) {
System.out.println("Made it to POST: "+input);
return Response.status(201).entity(input).build();
}
}
Client-side:
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8888/api/v1").path("tmm").path("mypost");
String input = "{\"address\":\"myaddress\",\"user\":4}";
ClientResponse response = webResource.type(MediaType.APPLICATION_JSON).post(ClientResponse.class, input);
I realize that using JSON I should have an object that the input binds to, but I've reduced the complexity to simply get the thing working.
Anybody have any insight? By the way, I'm using Tomcat (6.0.43).
I think you have to create a POJO like this:
public class User {
private String address;
private Integer user;
// getters and setters
}
and then change
#POST
#Path("/mypost")
#Consumes(MediaType.APPLICATION_JSON)
public Response postTest(String input) {
System.out.println("Made it to POST: "+input);
return Response.status(201).entity(input).build();
}
to:
#POST
#Path("/mypost")
#Consumes(MediaType.APPLICATION_JSON)
public Response postTest(User input) {
System.out.println("Made it to POST: "+input);
return Response.status(201).entity(input).build();
}
OK, with the help of a friend, I was able to figure this out. My URL was hitting a redirect. This was causing my POST to turn into a GET. Thanks for the help everyone. Your confirmations eliminated possibilities and helped guide me to the answer.
I solved this in IntelliJ.
Go to the menu: BUILD ->BUILD ARTIFACTS -> BUILD or REBUILD and that's it.

Accepting request in Jersey webservice

Let us assume ,for my Jersey project somebody is trying to send a request in the form of a string(String is obtained by converting some json details like username and password).Is my java code capable to accept it?
#Path("/customers")
public class Authentication {
#POST
#Path("/get")
#Consumes(MediaType.APPLICATION_JSON)
public Response getRequestUrl(String JSON_DATA) {
System.out.println("inside Authentication");
// String output = s.toString();
return Response.status(201).entity(JSON_DATA).build();
}
If not how to accept a request for further processing.Can anybody gives its explanation(Especially about get and post method).Advance thanks
Yeah you should test it.
This is a working example from my testproject:
#POST
#Path("/post2")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public Response addPerson(MultivaluedMap<String, String> map) {
// Dummy data
fillList();
Person person = new Person("Sample", 44);
// Get persons name and age from input fields
int age = Integer.parseInt(map.getFirst("age"));
String name = map.getFirst("name");
person = new Person(name, age);
lijst.add(person);
return Response.ok(person.toString()).build();
}
The service was online and I made an Android project to add a person to this list. It worked perfect :-)

How to consume json parameter in java restful service

How can i consume json parameter in my webservice, I can able to get the parameters using #PathParam but to get the json data as parameter have no clue what to do.
#GET
#Path("/GetHrMsg/json_data")
#Consumes({ MediaType.APPLICATION_JSON })
#Produces(MediaType.APPLICATION_JSON)
public String gethrmessage(#PathParam("emp_id") String empid) {
}
What to use in place of #PathParam and how to parse it later.
I assume that you are talking about consuming a JSON message body sent with the request.
If so, please note that while not forbidden outright, there is a general consensus that GET requests should not have request bodies. See the "HTTP GET with request body" question for explanations why.
I mention this only because your example shows a GET request. If you are doing a POST or PUT, keep on reading, but if you are really doing a GET request in your project, I recommend that you instead follow kondu's solution.
With that said, to consume a JSON or XML message body, include an (unannotated) method parameter that is itself a JAXB bean representing the message.
So, if your message body looks like this:
{"hello":"world","foo":"bar","count":123}
Then you will create a corresponding class that looks like this:
#XmlRootElement
public class RequestBody {
#XmlElement String hello;
#XmlElement String foo;
#XmlElement Integer count;
}
And your service method would look like this:
#POST
#Path("/GetHrMsg/json_data")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public void gethrmessage(RequestBody requestBody) {
System.out.println(requestBody.hello);
System.out.println(requestBody.foo);
System.out.println(requestBody.count);
}
Which would output:
world
bar
123
For more information about using the different kinds of HTTP data using JAXB, I'd recommend you check out the question "How to access parameters in a RESTful POST method", which has some fantastic info.
Bertag is right about the comment on the GET. But if you want to do POST request that consumes json data, then you can refer to the code below:
#POST
#Path("/GetHrMsg/json_data")
#Consumes(MediaType.APPLICATION_JSON)
public Response gethrmessage(InputStream incomingData) {
StringBuilder crunchifyBuilder = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incomingData));
String line = null;
while ((line = in.readLine()) != null) {
crunchifyBuilder.append(line);
}
} catch (Exception e) {
System.out.println("Error Parsing: - ");
}
System.out.println("Data Received: " + crunchifyBuilder.toString());
// return HTTP response 200 in case of success
return Response.status(200).entity(crunchifyBuilder.toString()).build();
}
For referencing please click here
#PathParam is used to match a part of the URL as a parameter. For example in an url of the form http:/example.com/books/{bookid}, you can use #PathParam("bookid") to get the id of a book to a method.
#QueryParam is used to access key/value pairs in the query string of the URL (the part after the ?). For example in the url http:/example.com?bookid=1, you can use #QueryParam("bookid") to get the value of `bookid.
Both these are used when the request url contains some info regarding the parameters and you can use the data directly in your methods.
Please specify the problem in detail if this post doesn't help you.

How do I map JSON parameters to Jersey parameters?

I've been struggling all day, trying to bind a very simple JSON request to a method using Jersey. I can't seem to find what's wrong, any help is very appreciated.
My JSON request is as simple as this:
{"user":"xyz","pwd":"123"}
My Jersey class looks like this:
#Path("/rest")
public class JerseyService {
#POST
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
#Consumes(MediaType.APPLICATION_JSON)
#Path("authenticate.svc")
#Transactional(readOnly = true)
public Response authenticate(
String user,
String pwd) throws IOException {
Response.ResponseBuilder responseBuilder = Response.ok();
responseBuilder.entity(JsonSerializer.serialize(Status.SUCCESS));
return responseBuilder.build();
}
}
When I send the JSON request to the service as it is, the "user" parameter is set with the entire JSON request as a String (user = "{\"user\":\"xyz\",\"pwd\":\"123\"}"), while pwd remains null.
I've tried using #QueryParam, #FormParam among another annotations with both "user" and "pwd", but I can't find a way for Jersey to bind the JSON values to the Java parameters.
Any ideas of what I'm doing wrong?
Thanks!
You could use low level JSONObject or create your own Class to accept the json parameter.
The following is the example with JSONObject.
```
#Path("/rest")
public class JerseyService {
#POST
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
#Consumes(MediaType.APPLICATION_JSON)
#Path("authenticate.svc")
#Transactional(readOnly = true)
public Response authenticate(final JSONObject login) throws IOException {
System.out.println(login.getString("user"));
System.out.println(login.getString("pwd"));
//^^^^^^^^^^^^^^^^^
Response.ResponseBuilder responseBuilder = Response.ok();
responseBuilder.entity(JsonSerializer.serialize(Status.SUCCESS));
return responseBuilder.build();
}
}
```

Categories

Resources