Spring Rest - deserialize nested object by Jackson - java

we are using javascript library which send parameters like this:
datatable[pagination][page]: 1
datatable[pagination][pages]:
datatable[pagination][perpage]: 10
datatable[sort][sort]: asc
datatable[sort][field]: title
w_id: 6453111
here is full GET url"
http://localhost:8081/foo/bar?datatable%5Bpagination%5D%5Bpage%5D=-2&datatable%5Bpagination%5D%5Bpages%5D=&datatable%5Bpagination%5D%5Bperpage%5D=20&datatable%5Bsort%5D%5Bfield%5D=title&datatable%5Bsort%5D%5Bsort%5D=desc&datatable%5Bquery%5D=&pagination%5Bpage%5D=-2&pagination%5Bpages%5D=&pagination%5Bperpage%5D=20&sort%5Bfield%5D=title&sort%5Bsort%5D=desc&query=&w_id=6453111
encoded as query parameters. We are not able to modify it, so I want write DTO object to deserialize this parameters in elegant way. Is possible to do it in Jackson?
My Dto should lookes like that:
#Getter
#Setter
public class DataDto {
private Pageable pageable;
private String wId;
}

Related

How to encode url string with object in request parameters spring [duplicate]

This question already has answers here:
Using RestTemplate in Spring. Exception- Not enough variables available to expand
(6 answers)
Closed 3 years ago.
I.m trying to do request with the object as a request parameter in my Spring application.
new RestTemplate().getForObject("http://127.0.0.1:8080/items?filter={\"level\":\"BIG\"}", Item.class);
But get error:
As I discovered, the problem occurs when UriBuilder parses the string with url. I.e. new URI(...) gives the error. When I do the same request with Postman I get a desirable response. How I can properly encode url? I`m tried to use java.net.URLEncoder but this gives "IllegalArgumentException: URI is not absolute" error.
UPDATE:
Filter class in the request is used to do parameterized query ( Query() ) in mongodb in the remote server. Filter class:
#Getter
#NoArgsConstructor
public class Filter {
private Map<String, String> criteria;
#JsonAnySetter
public void add(String key, String value) {
if (criteria == null) {
criteria = new HashMap<>();
}
criteria.put(key, value);
}
}
Item object class:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Item {
private String id;
private String name;
private Instant timestamp;
}
i have problem like yours and i solve it using following snippet code
UriComponentsBuilder renewURIBuilder= UriComponentsBuilder.fromHttpUrl("http://127.0.0.1:8080").path("/items").queryParam("filter", "{'level':BIG}");
UriComponents uriComponent=renewURIBuilder.build(true);
URI uri=uriComponent.toUri();
then call your resttemplate like the following
new RestTemplate().getForObject(uri, Item.class);
hope it help you

Spring boot with Jersey - Filter request body properties

I would like to know if there is some way to filter the properties of an object that a resource receives.
Let me explain myself: lets say we have this object:
UserDTO
public final class IniciativaDocument {
private String id;
private String name;
private String surname;
private String address;
private Double balance;
}
And for a resource I only need the properties "name" and "surname" but for other I only need "address" and "id". Is there any way to make the unneeded variables null automatically with something like Jackson?
My goal for this is that if the client sends a request with a field that isn't needed that I don't have to make it null before saving it to the database because that field is not supposed to be initialized when registering.
Thanks.
EDIT 1
For more clarity: this is for a matter of security and easiness.
Imagine I am a hacker and somehow know the fields a DTO class has. I could easily send a POST request like this to a service which is to register users:
{
"id": "wrong",
"name": "Wrong",
"balance": 20000
}
For my service I would only need id and name but the hacker is sending a balance field too.
What I want to do is that as I receive this object, I can set my endpoint /api/v1/users (which is to register) to put any initialized field that isn't id or name to null.
You might say I could just make sure it's 0 or set it to null manually. Yeah, that's true, but I want to find out if there's an automatic and more comfortable way of doing this with annotations or something similar.
EDIT 2
Resource example:
#Component
#Path("iniciativas")
#Produces(MediaType.APPLICATION_JSON)
public final class IniciativasEndpoint {
#POST
public Response crearIniciativa(#Valid #NotNull(message = CONSTRAINT_BODY_NOT_NULL) #ConvertGroup(to = IniciativasGroup.Create.class)
final IniciativaDTO iniciativaDTO,
#Context UriInfo uriInfo) {
return Response.ok().build();
}
}
You can use Jackson's JsonIgnore Property for this like:
#JsonInclude(Include.NON_NULL)
public final class IniciativaDocument {
private String id;
private String name;
private String surname;
private String address;
}
So Basically what it does is, when it is mapping this class to Json it will ignore all fields with null value. And if you want it not to apply on whole class you can do it on fields as well.
AND If you want to achieve it through front-end then you can use this great api GraphQL, so basically in request you will specify what fields you require and it will return only those fields.
Use a post-matching filter:
You can implement ContainerRequestFilter and annotate your Filter with #PostMaching (javax.ws.rs.container.PreMatching) and manipulate the your request with its data there.
Define an #interface for your Filter:
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.TYPE, ElementType.METHOD })
public #interface AnnotationForYourFilter {}
Annotate the sub-resource you want with #AnnotationForYourFilter and you are done.

How to map a request in Spring MVC to a Java Object

I'm new to Spring, and since Spring provides many ways to map an HTTP request to Java objects, I'm hoping someone could advice me how to resolve this:
I have a client that sends a request having
ContentType: application/x-www-form-urlencoded
Some of the request parmeters have names such as
"form_data[orderStatus]", "form_data[orderNumber]", etc'
I have no control over this client!
I have a java class (#Component) called MyOrder which looks as follows:
#component
#Scope("prototpe")
public class MyOrder {
private String orderStatus;
private String orderNumber;
//etc'
public void setOrderStatus(String orderStatus) {
this.orderStatus = orderStatus;
}
//public setter for all other properties, as the above
}
What is the simplest way to create an instance of MyOrder
populated with all values of all "form_data[]", so that I can have a controller method having a signature that includes a MyOrder parameter, such as:
public ModelAndView saveNewOrder( #RequestParam("foo") String foo,
#ModelAttribute("myOrder") MyOrder anOrder) {
//... impl'n here
}
The best solution I could think of was to use a Web Filter which would flaten request params names such as "form_data[attrib1]" to "attrib1", and then Spring would do all the work of populating the MyOrder instance.
One disadvantage of this is that the request may have both "form_data[attrib1]" and "attrib1" parameters. For example:
form_data[orderStatus]=ok
orderStatus=fail
In this case i want MyOrder.orderStatus to have the value "ok".
Any good way of utilizing Spring create MyOrder from the request?
As an alternative, that does not use the class MyOrder, is there a way to have Spring map all the form_data[] parameters and their values to a map, so that i can have the controller method below?
public ModelAndView saveNewOrder( #RequestParam("foo") String foo,
<some annotation> #Map<String,String> formFieldsOfAnOrder) {
//... impl'n here
orderStatus = formFieldsOfAnOrder.get("orderStatus");
//or at least:
orderStatus = formFieldsOfAnOrder.get("form_data[orderStatus]");
}

How to tell Jersey Jackson to not serialize one resource?

I have a REST API implemented using Jersey, I am using the Jackson feature for automatically serialize objects to JSON, there is a special case where I need to return a JSON string that represents an script. As the script can have different unknown structures I cannot just serialize it to an Object, that script comes from a column in a db table. At the same time I have a full Script object that contains all the information of the DB including the script string as a String property.
What I want is to tell Jersey-Jackson not to serialize (skip) the endpoint GET /script/{scriptId}, look at the code:
#Path("script")
#Produces(MediaType.APPLICATION_JSON)
public class ScriptResource {
private ScriptService service;
#GET
#Path("{scriptId}")
public String getScript(#NotNull #PathParam("scriptId") Integer scriptId) {
return service.getScript(scriptId); // returns a a valid JSON String
}
#GET
#Path("full/{scriptId}")
public Script getFullScript(#NotNull #PathParam("scriptId") Integer scriptId) {
return service.getFullScript(scriptId); // returns a Script object
}
}
The #Produces annotation is the one that triggers the automatic transformation via Jackson, I would like to configure Jackson and exlude the resource endpoint that I don't want to be converted automatically.
I don't want to:
Use Response as a return type
Change the Produces annotation to avoid Jackson
Use a Map as a return type which I would feed by parsing the String
One more option which you can consider in addition to those mentioned by #wasabi, is having a wrapper class for your string which would customize the Jackson serialization so it would not be converted to JSON. That can be done by using the combination of the #JsonValue and #JsonRawValue annotations on the getter method.
Here is an example wrapper:
public class RawJsonString {
private final String json;
public RawJsonString(String json) {
this.json = json;
}
#JsonRawValue
#JsonValue
public String getJson() {
return json;
}
}
... then your modified resource method would look as follows:
#GET
#Path("{scriptId}")
public JsonRawString getScript(#NotNull #PathParam("scriptId") Integer scriptId) {
return new JsonRawString(service.getScript(scriptId)); // returns a a valid JSON String
}
If you just want to make sure that some fields in Script class would not be serialized by Jackson, you could easily do so by annotating such fields with #JsonIgnore.
If you would like to have more control over the generated JSON, I would implement a custom JsonSerializer, and refer to it using #JsonSerialize annotation in your Script class. See this post for an example.
If you cannot modify Script class, you could also implement a MessageBodyWriter. See this post for an example.

How to bind set object to controller in spring

I am trying to make a post call to a controller, but the object I am expecting contains a Set datatype and I am unsure how the post data should look.
Models:
public class Notebook{
private string name;
private Set<Todo> todos;
}
public class Todo{
private String name;
}
Controller
#RequestMapping(method = RequestMethod.POST)
public void createNotebook(Notebook q){
questionnaireService.saveOrUpdateNotebook(q);
}
Currently I have tried posting like the example below:
curl --data "name=some notebook&todos[0].name=todo1&todos[1].name=todo2" http://localhost:8080/api/notebook
Doesn't seem to work. Anyone have experience with Sets?
You should qualify Notebook q with #RequestBody annotation so that the request can be mapped to an object of type Notebook. More about the format of the input data and the converters in Spring MVC doc: Mapping the request body with the #RequestBody annotation.
We send data from the front-end in JSON format and use Jackson JSON to convert it to the Java object. If you go that route, you can directly declare the todos as Set<String> and the input would be
{
name: "some notebook",
todos: ["todo1", "todo2"]
}

Categories