How to retrieve the JSON message body in JAX-RS REST method? - java

I have the following JSON that will be passed as part of a HTTP request, in the message body.
{
"names": [
{
"id":"<number>",
"name":"<string>",
"type":"<string>",
}
]
}
My current REST handler is below. I am able to get the Id and `Version that is passed in as path params, but I am not sure how to retrieve the contents on the message body?
#PUT
#Path("/Id/{Id}/version/{version}/addPerson")
public Response addPerson(#PathParam("Id") String Id,
#PathParam("version") String version) {
if (isNull(Id) || isEmpty(version)) {
return ResponseBuilder.badRequest().build();
}
//HOW TO RECIEVE MESSAGE BODY?
//carry out PUT request and return DTO: code not shown to keep example simple
if (dto.isSuccess()) {
return Response.ok().build();
} else {
return Response.serverError().build();
}
}
Note: I am using the JAX-RS framework.

You just need to map your name json to a POJO and add #Consumes annotation to your put method, here is an example:
#PUT
#Consumes("application/json")
#Path("/Id/{Id}/version/{version}/addPerson")
public Response addPerson(#PathParam("Id") String Id,
#PathParam("version") String version,
List<NamObj> names) {
I assume you are trying to retrieve a list of elements if is not the case just use you POJO as it in the param.
Depending on what json library are you using in your server you may need to add #xml annotation to your POJO so the parser could know how to map the request, this is how the mapping for the example json should look like:
#XmlRootElement
public class NameObj {
#XmlElement public int id;
#XmlElement public String name;
#XmlElement public String type;
}
Jersey doc: https://jersey.java.net/documentation/latest/user-guide.html#json
#cosumes reference: http://docs.oracle.com/javaee/6/tutorial/doc/gilik.html#gipyt

Related

How to make json deserialization fail when detecting duplicate properties in API POST request body

I have a POST endpoint which accepts a JSON as request body.
#Path("/drink")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class DrinkResource {
#POST
public Drink getDrink(Fruit fruit) {
return new Drink(fruit.getName());
}
}
The request body is supposed to be deserialized into this POJO :
public class Fruit {
private final String name;
#JsonCreator
public Fruit(#JsonProperty("name") String name) {
this.name = name;
}
public String getName() {
return name;
}
}
I'm using Jackson for the deserialization.
Is it possible to make the deserialization fail when the JSON in the request body has duplicate keys ?
For example, if the request body looks like this : {"name" : "banana", "name" : "orange"}, I would like to get a 500 status code or another kind of error instead of having the json deserialized with the last property.
Basically, I'm looking for a solution with the same logic as the JsonParser.Feature.STRICT_DUPLICATE_DETECTION with the ObjectMapper but for a POST endpoint.
I'm also using quarkus so I don't know if there is a property for this. Something similar to quarkus.jackson.fail-on-unknown-properties=true but for the duplicate properties.
Add the following:
#Singleton
public class MyCustomizer implements ObjectMapperCustomizer {
#Override
public void customize(ObjectMapper objectMapper) {
objectMapper.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
}
}
If you do, the ObjectMapper that Quarkus uses will throw a JsonParseException thus leading to a HTTP 400 response.

How do I get the JSON body in Jersey?

Is there a #RequestBody equivalent in Jersey?
#POST()
#Path("/{itemId}")
#Consumes(MediaType.APPLICATION_JSON)
public void addVote(#PathParam("itemId") Integer itemId, #RequestBody body) {
voteDAO.create(new Vote(body));
}
I want to be able to fetch the POSTed JSON somehow.
You don't need any annotation. The only parameter without annotation will be a container for request body:
#POST()
#Path("/{itemId}")
#Consumes(MediaType.APPLICATION_JSON)
public void addVote(#PathParam("itemId") Integer itemId, String body) {
voteDAO.create(new Vote(body));
}
or you can get the body already parsed into object:
#POST()
#Path("/{itemId}")
#Consumes(MediaType.APPLICATION_JSON)
public void addVote(#PathParam("itemId") Integer itemId, Vote vote) {
voteDAO.create(vote);
}
#javax.ws.rs.Consumes(javax.ws.rs.core.MediaType.APPLICATION_JSON)
should already help you here and just that the rest of the parameters must be marked using annotations for them being different types of params -
#POST()
#Path("/{itemId}")
#Consumes(MediaType.APPLICATION_JSON)
public void addVote(#PathParam("itemId") Integer itemId, <DataType> body) {
voteDAO.create(new Vote(body));
}
if you want your json as an Vote object then simple use #RequestBody Vote body in your mathod argument , Spring will automatically convert your Json in Vote Object.

How to get JSON in Java REST / AngularJS frontend

Can someone please help me how to get a JSON String in a Webservice. I's sending JSON to my /api/register that looks like:
{"name":"MyName","surname":"MySurename","email":"mail#asd.de","street":"MyStreet","number":"3","zip":"12345","city":"myCity","pass":"myPassword"}
Here is my register.java file:
#Path("/register")
#Stateless
public class RegisterWS {
#EJB
UserBS userBS;
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void createUser(){
// code to get data from json
userBS.createUser(name, surename, email, adress, number, zip, city, password);
}
}
My AngularJS Controller and Service. The Data comes from a form, that is parsed to a JSON object.
app.service('RegisterService', function ($http) {
return {
registerUser : function(user) {
$http.post('http://localhost:8080/myApp/api/register')
.success(function (user) {
return user;
})
.error(function (data) {
// failed
});
}
}
});
app.controller('RegisterCtrl', function($scope, RegisterService) {
$scope.register = function(){
RegisterService.registerUser(angular.toJson($scope.user));
}
});
You should have a POJO, which maps to the received JSON object, for example a User class. In this case this would be a very simple Java Bean, with mostly String properties for each field in the JSON.
#XmlRootElement
public class User {
String name;
String surname;
String email;
String street;
Integer number;
String zip;
String city;
String pass;
}
Of course you would use private fields, with getters and setters, but I did not want to add clutter. By the way the #XmlRootElement is a JAXB annotation, and JAX-RS uses JAXB internally.
After you have this, you just need to change your method like this
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void createUser(User user) {
...
}
You should not need to change anything on the AngularJS side, as the default for the $http.post method is JSON communication.
For your Java code, you have to add a User POJO, I dont know if you will use some persistence API or not, so the user POJO must implement serializable to output user object as JSON.
Here's a an example of REST app with EJB ... : http://tomee.apache.org/examples-trunk/rest-on-ejb/README.html
For your client app, you need to specify the content type : "Content-Type" = "application/json"
See this questions: change Content-type to "application/json" POST method, RESTful API

How to parse JSON Response to POJO with AndroidAnnotations?

I'm using AndroidAnnotations to build a Rest for an Android Application.
On the Serverside im using PHP, which send a json looking like :
{"tag":"register","success":0,"error":2,"msg":"User already existed","body":[]}
I have two POJOS :
User.java:
public class User implements Serializable {
private String name;
private String email;
private String password;
//getter and setter Methods
}
Response.java:
public class RegistrationResponse implements Serializable {
private String tag;
private int success;
private int error;
private String msg;
private String body;
//getter and setter Methods
}
Rest Client:
#Rest(rootUrl = "http://my.domain.com", converters = {
MappingJacksonHttpMessageConverter.class,
StringHttpMessageConverter.class, GsonHttpMessageConverter.class }, interceptors = { MyInterceptor.class })
public interface RestClient extends RestClientErrorHandling {
#Post("/user/register/{name}/{email}/{pass}")
#Accept(MediaType.APPLICATION_JSON_VALUE)
Response sendUserRegistration(User user, String name, String email,
String pass);
RestTemplate getRestTemplate();
}
Activity.java:
//User and Response are POJOs
Response result = RestClient.sendUserRegistration(user,
user.getName(),user.getEmail(),user.getPassword());
But i got an Null Pointer Exception error on Activity.java. But if i change the return value of "sendUserRegistration" function to String all work. So my "Response" POJO seems not to be converted from AndroidAnnotations.
How can i convert the Rest Response to my "Response"-POJO using AndroidAnnotations?
You don't need to return the entire response object per rest call, just set the response to your custom object. Or you can also return a JsonObject also and use gson to convert it later on.
#Rest(rootUrl = "http://my.domain.com", converters = {
MappingJacksonHttpMessageConverter.class,
StringHttpMessageConverter.class, GsonHttpMessageConverter.class }, interceptors = { MyInterceptor.class })
public interface RestClient extends RestClientErrorHandling {
#Post("/user/register/{name}/{email}/{pass}")
#Accept(MediaType.APPLICATION_JSON_VALUE)
User sendUserRegistration(User user, String name, String email,
String pass);
RestTemplate getRestTemplate();
}
then just simply call
User newUser = RestClient.sendUserRegistration(user,
user.getName(),user.getEmail(),user.getPassword());
AA relies on Spring Android RestTemplate to make the rest call. And in order to build requests and handle responses this lib uses converters. And to know which converter the RestTemplate should use, it checks the content-type response header.
As MappingJacksonHttpMessageConverter and GsonHttpMessageConverter handles only http response with content-type=application/json and your result is converted to string, I'm pretty sure you forgot to set this header in your php server. So it send the default one (ie: text/plain) which is only handle by StringHttpMessageConverter.
Also, the body field is an object in your json example, but in your POJO you declared it as a String. So parsing will fail on this point.

Who initializes the arguments in method executed by #Post (or any jax rs annotations)?

I saw in the rest service the following code snippet
#POST
#Consumes("application/xml")
#Path("/ProjectConfiguration/{onetimetoken}")
public void createProjectConfiguration(#PathParam("onetimetoken") String oneTimeToken,
CreateProjectConfigurationRequest request) throws IntegratedAppFault {
// NOOPS
}
In this value of variable oneTimeToken is initialised by what comes in path. But my doubt is how request object of the type CreateProjectConfigurationRequest is initialized .How are we given freedom to have any parameter in these methods . How this works ? How is it guaranteed that this gets initialised .
The method above is expecting an HTTP POST request with an XML message in the body. You can tell because the method is annotated with #POST and #Consumes("application/xml"). Resteasy sees that you have a CreateProjectConfigurationRequest type in your method signature, which is annotated with JAXB annotations, and binds the body of your HTTP request to that object.
You can also inject instances of the following classes using the #Context annotation.
javax.ws.rs.core.HttpHeaders
javax.ws.rs.core.UriInfo
javax.ws.rs.core.Request
javax.servlet.HttpServletRequest
javax.servlet.HttpServletResponse
javax.servlet.ServletConfig
javax.servlet.ServletContext
javax.ws.rs.core.SecurityContext
There is standard support built into JAX-RS compliant frameworks for marshalling XML and Json request bodies into method arguments. If you need to read a custom message format then you would create a MessageBodyReader which would take the incoming http request body and bind it to a parameter just like XML or Json.
Example
The code below illustrates how to bind the request body to a java object in your method parameters.
Using your example above let's assume we have the following rest endpoint exposed by our service:
#POST
#Consumes("application/xml")
#Path("/ProjectConfiguration/{onetimetoken}")
public void createProjectConfiguration(#PathParam("onetimetoken") String oneTimeToken,
CreateProjectConfigurationRequest request) throws IntegratedAppFault
{
System.out.println(oneTimeToken);
System.out.println(request.toString());
}
This endpoint is expecting to receive an HTTP POST message containing an XML representation of CreateProjectConfigurationRequest.
We know this because:
The method is annotated with #POST indicating it is triggered by POST requests.
The method is annotated with #Consumes(application/xml) indicating that it is only triggered by requests with an HTTP Content-Type header of application/xml.
There is a method parameter of CreateProjectConfigurationRequest that is not annotated with #Form, #FormParam, #PathParam, #QueryParam, or #HeaderParam that would indicate it is coming from some other part of the request.
Now, let's assume that CreateProjectConfigurationRequest is defined as follows:
#XmlRootElement
public class CreateProjectConfigurationRequest
{
private int id;
private String name;
#XmlElement
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
#XmlElement
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
Now when we send an HTTP POST request to http://somehost/someapp/ProjectConfiguration/123abc with a Content-Type of application/xml and the following XML body our method will be invoked.
<CreateProjectConfigurationRequest>
<id>123</id>
<name>test</name>
</CreateProjectConfigurationRequest>
The Resteasy JAXB Provider will then take the incoming XML and create a CreateProjectConfigurationRequest object based on introspecting the object and the annotations that we added to it above.
Your method will then run and print the oneTimeToken (retrieved from the path using the #PathParam("onetimetoken") annotation) and request.

Categories