Jersey REST And PathParam Regular Expressions - java

I'm trying to use Jersey to develop a REST web service. My requirement is for me to be able to access the web service and return data, based on the passed PatParam parameters. My web service so far is as follows:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes({ "application/xml", "application/json", "application/x-www-form-urlencoded" })
#Path("/1.0/people{extension:(.json)*}/{personId:([^/]+?)?}{entityExtension:(.json)*}")
public String getLocation(#PathParam("extension") String extension, #PathParam("personId") String personId,#PathParam("entityExtension") String entityExtension)
{
if ((personId==null ||personId.equals("")) && (extension == null || extension.equals("")))
return "No Id, and no extension";
else
return "personId= "+personId + ", extension= " + extension+", entityExtension= "+entityExtension;
}
With the above code in mind, what I'm trying to achieve is the following:
http://localhost:8080/Jersey/RestService/1.0/people.json
Should return the list of all people in the "json" format (Hence the .json extension)
Now, I want to be able to get the information for a particular person by simply putting the person's ID, and return the person's information in json/xml based on the extension:
http://localhost:8080/Jersey/RestService/1.0/people/Mouhammed89.json
With the above URL, I should be returning the information for the personId: Mouhammed89, and returning the information in the json format.
I know that my problem is with the regular expressions that I'm using, so I would really appreciate the help in creating them.

IMHO container (List) and item (Person) URL should be handled separately.
And you don't require explicit .json prefix for returning JSON response, only the annotation at the API level should suffice.
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/1.0/people") //no need for .json suffix as API only return JSON format
public List<String> allLocations(..){ //jackson etc. will convert return type to json string
..
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/1.0/people/{personId: \\d+}")//digits only
public String getLocation(..){ //jackson etc. will convert return type to json string
..
}

Related

How to send Integer value in the form of JSON format and recieve in REST Controller?

I have one REST Controller where I have written this code
#PostMapping(value = "/otp")
public void otp(#RequestBody Integer mobile) {
System.out.println(" Mobile = "+mobile);
}
And I am calling this method from Postman with the following inputs
URL : localhost:8080/otp
Body :
{
"mobile":123456
}
But I am getting the following exception
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not deserialize instance of java.lang.Integer out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.Integer out of START_OBJECT token
If I am taking String as a parameter like this
#PostMapping(value = "/otp")
public void otp(#RequestBody String mobile) {
System.out.println(" Mobile = "+mobile);
}
And passing the inputs as
{
"mobile":123456
}
Now it is printing in the console as follows
Mobile = {
"mobile":"123456"
}
But I want only this value 123456. How to achieve my requirement?
NOTE: I don't want to create any additional POJO class or even I don't want to send the data using query/path parameter.
If you want to send your body like:
{
"mobile":123456
}
You will create another object to receive the value.
But if you only want to accept the integer value without any other object, you will not put json object in request body, but only the integer itself.
Body:
12345
You can use a class as request body:
class Request {
public Integer mobile;
}
and specify the parameter like this:
public void otp(#RequestBody Request mobile) {
...
Create a pojo class like below.
public class Mobile{
private Integer mobile;
//getter and setter
}
And then
public void otp(#RequestBody Mobile mobile)
to print value use
mobile.getMobile();
Converting process with json and #RequestBody is automatically and need you provide a class which contains proper field.If you insist to send data by request body,you could use String to receive json data as String.For example:
public void test(#RequestBody String request){
log.info(request);
}
In this way the request body you received is a String.You need some other tool to help you convert it.Like org.json,you could get more info from here HttpServletRequest get JSON POST data
But the easiest way is creating a new class to receive the data or changing #RequestBody to #RequestParam or #Pathvariable.
If you still want to use json as the request body,maybe you could create a common class A which contain lots of fields like name,phone number,email...Then after you send a request which only contains mobile,you just need to A.getMobile().In this way, even you get 100 request,you still need one POJO(but not recommend)
Just send the number in JSON.
12345
use #RequestBody to receive the int number.
it will work.
I use postman to send it in RAW JSON.
BTW, I am a beginner learning Spring Boot.
if you have org.json.JSONObject
#PostMapping(value = "/otp")
public void otp(#RequestBody String mobile) {
JSONObject obj = new JSONObejct(mobile);
System.out.print(obj.getInt("mobile"));
}

Encode Response in REST service

I use class javax.ws.rs.core.Response in my service method:
#GET
#Path("/object/{id}")
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response findObject(#Context HttpHeaders headers,
#PathParam("id") String objectId) {
Object object = getObject(objectId);
return createResponse(object, headers);
}
private Response createResponse(Object object, HttpHeaders headers) {
Response.ResponseBuilder responseBuilder = Response
.ok()
.entity(object)
.type(MediaType.APPLICATION_JSON_TYPE)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
.build();
}
And instance of Response contents hierarchy of my system which is contained in the instance object. This's object with all its children and their properties. And I want encoding values of properties in object. I need to give in response percent-encoding symbols instead of space in names for example. I need encoding whole my response including all fields. According to the UTF-8 encoding. For example, instead of value of some field 'His name: John' I need have 'His20%name%3A20%John' in my response. And similarly for all fields without exception in the whole hierarchy.
I didn't find anything better than how each field was handled manually using the method URLEncoder.encode(String s, String enc):
fieldValue = URLEncoder.encode(fieldValue, "UTF-8");
But in this case I need to manually go through all the fields that are in all the objects of my hierarchy coming in response. Maybe there is a more standard and correct way to do this?
And some fields are not string and have for example type BigDecimal. They can contain delimiters. How do I process them? Is there any way to encode the entire object response before return?
You can create separate fields/getter for encoded properties. In this way, the original values will be kept intact. You can also rely on reflection to fetch all fields and do it which will be messier than this.
class User {
private String firstName;
private String lastName;
private String encodedName;
public String getEncodedName(){
return URLEncoder.encode(this.firstName, "UTF-8”)+URLEncoder.encode(this.lastName, "UTF-8");
}
}

Cannot get JSON data from Jersey GET response

I was developing a restful web client and trying to get the JSON payload from the response of a GET method. I am using Jersey. But I just cannot read the JSON data using response.getEntity() method. I tried many methods including response.bufferEntity(), but the output always kept empty. Below is my code and output, and in addition I can see the JSON data right in the response packet captured in wireshark. I would really appreciate everyone trying to help figure out why or provide solution. Thank you!
Code:
public JSONObject Get(String requestPath){
ClientResponse response = webResource.path(requestPath)
.header("Content-Type", contTypeHeader )
.header("Accept",acceptHeader)
.header("Authorization", authZ )
.get(ClientResponse.class);
response.bufferEntity();
if (!(response.getStatus() == 201 || response.getStatus() == 200)) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
System.out.println(response.getEntity(JSONObject.class));
return null;
}
and the output is always like this: {}
You can't use JSONObject unless you have a MessageBodyReader for it. See more at JAX-RS Entity Providers. The provider you are currently using (probably Jackson) only supports JavaBean POJOs or collections of them. For example if you have this JSON
{ "property1" : "value1", "property2": "value2" }
Then you would need to have a POJO like
public class Bean {
private String property1;
private String property2;
// getters and setters
}
Then you can do getEntity(Bean.class). The reason you are getting an empty object, is that the deserialization works off the setters. It looks for properties on the JSON, that matches a setters, and uses it the set the property. The JSON object has no setters for your JSON properties.

Sending JSON to server is giving 415 Unsupported Media Type

I have the following angular code:
<button ng-click="ctrl.submit(light)">Switch</button>
and the button click is handled by:
self.submit = function(light) {
console.log("==============================");
console.log("clicked button: ", light);
console.log("==============================");
$http.post('/ARHomeAutomation/rest/light/state/', light).then(function(response) {
console.log('headers: ' , response.headers);
console.log('status: ', response.status);
console.log('config: ', response.config);
console.log('data: ', response.data);
self.state = response.data;
}, function(errResponse) {
console.error('Error while updating light state');
})
console.log('User clicked submit with: ', light.id );
console.log('response: ', self.light);
}
On the server side I have the following method that should respond to the request:
#POST
#Path("/state/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_HTML)
public String setStateOfLight(JSONObject aLight) {
if(aLight == null) {
return "It's a null";
} else {
System.out.println("content: " + aLight);
}
JSONObject jsonObject = new JSONObject();
//Update the state of the light with the given id
for(Light light: lightCollection) {
// .....
}
return getLightsStateAsJSON();
}
When I click my button I get the following message:
According to firefox I do send JSON in my request. At least it says so when I examine the send data.
This is my header request data:
What am I missing here?
"I downloaded Jersey 2.17 with all dependencies. AT least that what it says on their download site"
Yeah so the Jersey distribution (Jersey JAX-RS 2.0 RI bundle ) doesn't come bundled with an JSON conversion support, besides basic low level types, that can be converted from an InputStream. So without anything else beside the jars that come in that Jersey Bundle, the only type you have use are String, InputStream and byte[]. Doesn't really help much if you are trying to manipulate the JSON
How conversion works is through the use of MessageBodyReaders and MessageBodyWriters. I don't know what JSONObject is, but I'm guessing it's from here. In any case, you will need a MessageBodyReader for it to handle the incoming conversion. My guess is you don't have one. I personally don't know where to get one for that specific API.
I would instead make use of a library that can handle JSON to POJO mapping. Jackson is the one I would recommend. The basic are pretty easy to understand. Say this is your JSON
{"name":"your name", "id": "2"}
All you need to do is create a class with fields an properties, using JavaBean naming convention. So for the above JSON, we could use this
public class User {
private String name;
private String id;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
}
Now your method parameter can accept a User type.
To get this support, you need to add the Jackson provider. Download the below
jersey-media-json-jackson
Get all the one from the below image
I had an image from another post with v2.2.3- disregard the version. The version you want to get 2.3.2 for all of them. They can all be found at the above link, for the first dependency. Just search for them in the search bar. When you find it, select the version and download it.
After adding these jars. you should have JSON to POJO support.
It appears that the header content-type is set to text/html, even though the body is JSON. I imagine you will need to set the content-type to application/json somewhere in the post in the Angular code.

REST GET/POST how to send and receive complex parameters?

I am using Jersey and converting my existing data services into RESTful data services. Most simple GETs and PUTs I could successfully convert. But following are some I am not able to convert:
X Get (T) // for complex queries with complex result
X Post (T) // for creating with complex result
X PUT (T) // for updating with some success message object
where T and X are a complex objects
I have tried #queryparam, #pathparam with complex objects on GET with #consume & #produce and those didn't work. Also tried POST (though I really needed GET) with url encoded and that didn't work too.
Please Help. I am in need of sample code that does it.
REST isn't designed to handle complex queries as the query is actually the URL. When you retrieve a resource you specify the ID of the resource you want. This is simply a number or string and is easily represented in the URL for example;
http://host/employee/57
would get you employee 57. If your requirements are more complicated then you might want to use a search method, where you pass several parameters. You could use #QueryParam here but this isn't really REST in a pure form.
If you are POSTing or PUTting data then you use the same URL as you would if you were doing a GET, only this time you send data in the content body. As you are able to serialize the object in order to return it to a GET request your client should also be able to serialize it to send it to you in a PUT or POST.
Here's an example of a GET and POST;
#XmlType
public class Employee {
private int id;
private String name;
//getters and setters
}
#Path("/employee")
public class EmployeeService {
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_XML)
public Employee get(#PathParam("id") String id) {
Employee e = employeeDao.getEmployee(id);
if (e != null) {
return e;
} else {
throw new WebApplicationException(404);
}
}
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Employee post(Employee employee) {
return employeeDao.insertEmployee(employee); //Assumes your DAO sets the ID
}
}

Categories