How to get #PathParam and request body in same web-services? - java

I am calling services and want to map the data from path param and from request body. web-services call is type of POST.
Problem here is if i use #Form then I am getting only path param
Here are the scenario.
Case1 Url :- Response updateDepartment(#Form #Valid Department departmentObject)
I am getting path param value as departmentNumber, departmentSNumber and departmentName
but not getting request body which contain addRequest[{ }] and removeRequest[{ }]
In case If i use only #Valid then
Case 2 Url :- Response updateDepartment(#Valid Department departmentObject)
In this case, I am getting addRequest[{ }] and removeRequest[{ }] values.
but Object but now missing with departmentNumber, departmentSNumber and departmentName
Department.java
public class Department
{
#PathParam(DEPTNUMBER_PARAM)
private String deptNumber;
#PathParam(DEPT_S_PARAM)
private String deptSNumber;
#PathParam(DEPARTMENT_NAME)
private String departmentName;
private List<String> addRole;
private List<String> removeRole;
}
How to map both the values form #PathParam as well as request body values.
Here is the call
http://localhost:8080/myweb/departments/1234/4321/finance
{
"addRole": [
101,
181
],
"removeRole": [
42,
12
]
}

Why don't you use this:
Response updateDepartment(#Valid Department departmentObject, #PathParam("departmentNumber") String departmentNumber....)
What you want it will not work. I will try to explain.
First of all, I think you are using resteasy not JAX-RS reference, correct?
In RestEasy for #Form annotation it said:
This can be used as a value object for incoming/outgoing request/responses. You can re-use #*Param annotations on fields/methods of the parameter to unmarshall from the request or marshall to the response depending if you're using server-side JAX-RS or the Resteasy client framework
In your case, you use #PathParam on the fields of the parameter, that is why was populated.
When you do not use #Form, whatever type you specify for the parameter it tries to match with request body, which, in your case contain only the two arrays and not the PathParam. It will not look into the path params for anything else, thus ignoring your annotation.

Related

Parsing a request body containing a quoted string as JSON in Spring Boot 2

I have an application which exposes an endpoint accepting PUT requests as a JSON-formatted string, e.g.:
PUT /my/endpoint
"some string"
My endpoint method signature is something like:
#RequestMapping(
path = "/my/endpoint",
consumes = "application/vnd.mycompany.myservice-v1.hal+json"
)
public ResponseEntity<MyResponse> myEndpoint(
#RequestBody final String myString
) {
...
}
Using Spring Boot 1 (1.5.22.RELEASE), the value of myString given the PUT example above would be the literal text some string, but under Spring Boot 2 (2.3.6.RELEASE), it's now the literal text "some string" - i.e. it seems that the input isn't strictly being parsed as JSON because the quotes are not removed.
I believe that quoted strings are valid JSON (and that unquoted strings are not), just as an object (in { and }) and a list (in [ and ]) would be.
I've taken out some extraneous detail that I don't think matters for the problem at hand (e.g. we're using CompletableFuture as a return value, I've got a #PathVariable in there as well and there's some annotation-driven validation going on), but I've left in that we're using a custom media-type in case that has something to do with it.
Any ideas how I can convince Spring Boot 2 to treat my request body as JSON properly? Unfortunately, I can't redefine the API because we already have live customers using it.
This might not be the best option but if nothing else helps at start. Instead of String let Spring handle RequestBody as an Object. So like:
public ResponseEntity<String> myEndpoint(#RequestBody final Object myString)
When using String Spring might not even use Jackson for parsing but handle the body as a String that should have all the characters in the body even content type is set to JSON.
If you do the following:
String myString2 = new ObjectMapper().readValue(myString, String.class);
you can see it resulting into myString2 having not those surrounding double quotes.
For Object Spring seems to handle it differently. It makes it to a String but seems to consider it as a JSON value (and as a String value because having surrounding double quotes) it should not have surrounding double quotes.
If you use Object and then log myString.getClass() you will see it is actually a java.lang.String
You Can create the request object
public class MyObject{
private String myStr;
}
Use the MyObject class as RequestBody object with mediaType="application/json"
In your controller
#RequestMapping(
value= "/my/endpoint", method= RequestMethod.PUT
)
public ResponseEntity<MyResponse> myEndpoint(
#RequestBody final MyObject myObj
)

SpringBoot: requestParam value validation when required=false

Here is my method code:
#RequestMapping(value="/api/restcall", method=GET)
public response methodcall (#RequestParam (value="testId", required=false) String testId, #RequestParam (value="requestId", required=false) String requestId){
//some code
}
I want to validate the request params. Not the value but the field itself.
API call:
localhost:8080/api/restcall?requestId=abcd&testId=xyz
I want to validate that "requestId" and "testId" are sent correctly if sent. Not the value, but the key itself. NOTE: The requestParams are not mandatory fields.
So if below API call is made:
localhost:8080/api/restcall?request=abcd&test=xyz
I want the code to validate that the requestparams are not correct. I tried the #Validate annotation and #Valid annotation. Both did not work.
When incorrect call is made like above, the code is going through as the fields are not mandatory.
I want to know what params are coming in if testId and requestId are not sent in. If I have this information, I can do the validation.
The validation of REST invocations doesn't work in this way.
This validates the values of the sent parameters, not the names of them.
So as the required attribute is set to false for the parameters, no violation constraint occurs.
The invalid names of the sent parameters are probably ignored by the Jackson processing.
If you want to perform such a validation, you should use a custom validator or a custom validation.
For example :
String errorMsg = "";
if (StringsUtil.isEmpty(testId)){
errorMsg+="testId param name missing";
}
if (StringsUtil.isEmpty(requestId)){
errorMsg+="requestId param name missing";
}
if (!errorMsg.equals("")){
throw new ValidationException(errorMsg);
}
You can get a map with all params fields and values with: #RequestParam Map<String,String> allRequestParams. Then you can use containsKey to check for a field.

Receiving unknown parameter name on POST request in Java (JAX-RS)

I have the following POST response in JAX-RS.
#POST
#Path("/save")
public Response saveS(#FormParam(key) String value) throws SQLException {
return Response.ok("TODO", MediaType.APPLICATION_JSON).build();
}
The parameter that is received could be called name or age or many other things. I have identified it as key in the code (obviously it doesn't work).
How can I retrieve the name of that parameter?
Thanks
The parameter that is received could be called name or age or many other things. I have identified it as key in the code (obviously it doesn't work).
As you already found out it doesn't work that way because the #FormParam is expecting the name of a form parameter as it is defined in the corresponding HTML form. That means you should know which form parameter you want to assign to the param (value in this case) of the method.
Here is the definition of the #FormParam annotation extracted from the JAX-RS specification:
FormParam Parameter
Specifies that the value of a method parameter is to be extracted from a form parameter in a request entity body. The value of the annotation identifies the name of a form parameter. Note that whilst the annotation target allows use on fields and methods, the specification only requires support for use on resource method parameters.
And in addition to that you should add the #Consumesannotation to your resource method as follows:
#POST
#Path("/save")
#Consumes("application/x-www-form-urlencoded")
public Response saveS(#FormParam(key) String value) throws SQLException {
return Response.ok("TODO", MediaType.APPLICATION_JSON).build();
}
Update:
I haven't tried myself, but you can try and tell me if it works. Here you should get all the params so that you can parse all the form fields:
#POST
#Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap<String, String> formParams) {
// parse the map here
}

Jersey, JSR 303 validation - custom "path" and "invalidValue" in ValidationError

I am using Jersey (JAX-RS) and I'm trying to implement a validation. I have a problem with a response returned by my application when a validation error occurs. Now the response looks like this:
[{
"message": "Custom message",
"messageTemplate": "{custom.message.template}",
"path": "SomeJerseyResource.resourceMethod.arg0.names[0]",
"invalidValue":"[value1, value2]"
}]
where "SomeJerseyResourceClass.resourceMethod" is a JAX-RS resource:
public class SomeJerseyResource {
#POST
#Path("/path")
public Response resourceMethod(#Valid RequestModel request) {
/** method body **/
}
}
and validation constraint is assigned to a getter in RequestModel:
public class RequestModel {
private List<String> names = new ArrayList<>();
#MyConstraint
public List<String> getNames() {
return tags;
}
}
I have a custom ConstraintValidator, where I validate each element of that List.
Problem
I don't want to include resource and method name in "path" field of the response. Instead of
SomeJerseyResource.resourceMethod.arg0.names[0] I want arg0.names[0] only. Client doesn't know about server classes and methods, and he wouldn't be able to properly assign errors to fields when he receives response like that.
I want to customize "invalidValue" field of a response. More specifically, to have only invalid element value, not the whole list in that field.
I didn't find any easy way to do that. Do you have any ideas?
You can just write an ExceptionMapper<ConstraintViolationException> to return the Response of your liking. Jersey uses an ExceptionMapper<ViolationException>. ConstraintViolationException extends from ViolationException, so you're mapper is more specific, and would take precedence in the choosing of the mapper. Jersey's mapper, returns the response as a ValidationError, that's why the body is how it is. But you can make it whatever you want.
If you just want the invalidValue list, then just iterate through the ConstraintViolations from ContraintViolationException.getConstraintViolations(), and get the invalidValue from the ConstraintViolation.

Can I use number as property name in Jackson mapper?

I am using Spring MVC3.2 and Jackson for JSON mapping. I want to serialize and deserialize property name with just number. Here is my class:
public Usage implement Serializable {
private String imei;
#JsonIgnore
#JsonProperty("4")
private long j2j;
#JsonIgnore
#JsonProperty("8")
private long call;
//Getters and setters
}
JSON:
{"imei":"352985052917115", "4":20, "8":10}
Controller:
#ResponseBody
#RequestMapping(value="/alert")
public JsonResult<Void> handleOverUsageAlertByDevice(#RequestBody Usage usage){
//Do something
}
But when I send the JSON to the controller, 404 Bad request error happens, saying:
The request sent by the client was syntactically incorrect.
Can I use number as Json property name?
Your answer would be appreciated.
Yes, "numeric Strings" are perfectly legal JSON names, and Jackson supports them.
So problem should not be with that but something else in request handling.
Please try by setting the content type when sending the request.
The content type should be set as "application/json".

Categories

Resources