Restrict JSON attributes for #RequestBody - java

This may be a simple task, but I couldn't find a way to do it. Basically, I need to disallow some parameters at the time of using #RequestBody annotation in my controller.
Here is my model:
#Data
public class MyModel {
private int id;
private String name;
}
What I want to do is at the time of response, I want both of the properties to be serialized to JSON, but at the time of create or update, I prefer not to receive id as part of #RequestBody deserialization.
Right now, if I pass id in the JSON body, Spring initializes a MyModel object with its id set to the passed value.
Reason? The ID cannot be generated until the model is created, so the app shouldn't allow the ID to be set. On update, the ID needs to be passed in the URL itself e.g. (PUT /mymodels/43). This helps following the REST principles appropriately.
So, is there any way to achieve this functionality?
Update 1:
Right now, I am stuck with using a request wrapper. I created a new class MyModelRequestWrapper with only name as its property, and have used it with the #RequestBody annotation.

How you do this depends on what version of Jackson you are using. It's basically possible by a combination of the annotations #JsonIgnore and #JsonProperty on relevant fields/getters/setters.
Have a look at the answers here: Only using #JsonIgnore during serialization, but not deserialization

Related

Firestore - set a POJO field to the ID of the collection of a query

I know this is a very specific ask but I've got a situation where it would be very nice to have my custom class deserialized and have the collections parent ID set to a specific field. I know with the #DocumentId annotation we can do this for the documents own ID, is there some SDK method to extend this for my use case?
public class MyCustomClass {
#DocumentId public documentID;
...
#<insert magic here> public documentsCollectionsParentID
So for example, something like /users/<uid>/docs/<docid>, I already have the functionality for documentID to be set automatically to docID, but I'd like documentsCollectionsParentID set to uid. Is this in any way possible at the moment?
My current alternative is to deserialize, and the the object afterword:
MyCustomClass thing = (MyCustomClass)doc.toObject(MyCustomClass.class);
thing.setDocumentsCollectionsParentID(doc.getReference().getParent().getParent().getId())
Unfortunately, there is no method in Firebase that does that automatically. This is Java limitation and you are doing it correctly by deserializing the object.

Converting Request body to DTO with different fields structure in Spring Web app

Spring Web works perfectly in scenarios when rest controller takes a custom object, entity or dto, as parameter of handler method. You just need to annotate it with #RequestBody annotation. But how can I handle cases when the object has different field names or structure? I.e. for request json like
{"name":"FirstName", "address" : { "city" : "Rome" }}
to 'flattened' structure like
class Person { private String name; private String city; }
Is it possible to create a custom converter like HttpConverter, but for specific controller handler method only?
I think the easies way is to make a DTO matching the structure of the incomming json so Spring can map the json to this DTO. Then you can map this DTO to your Person class in your controller.
If your mapping is simple it is easiest to just write the mapping yourself. If not you can use a mapping tool like https://github.com/mapstruct/mapstruct or http://modelmapper.org/.
Please let me know if this is usefull.

Ignore fields from being passed on in Json Object

I have a POJO called User which is also being used for inserting documents in MongoDb.
#Data
#Document(collection = Constants.COLLECTION_USERS)
public class User {
public ObjectId _id;
public String userID;
public String email;
public String name;
public String sex;
public String dob;
public String photo;
//have more variables
}
I have a simple application where a user registers by giving in a subset of data listed in the User class. The signature of the register method in my controller is as follows.
public GenericResponse registerUser(#RequestBody User userRegistrationRequest)
It can be noticed that I am using the same POJO for the registration request. Until now everything is fine. I can persist the data user object just fine.
This registration API is just used to persist a small set of a user's data. There would be other information as well in the MongoDb document, which would be accessed/persisted from some other APIs.
Suppose a user has registered with the basic information and also has persisted other information via APIs other than the registration one.
How would I make an API which can just get me some selective data from the User document again using the same User Pojo? If I call the repository to give data for a specific userID, it will give me the whole document mapped to the User class. I don't want my API to give all the information stored in the document.
One approach is to make another POJO with the details I want, and map the information selectively using a Converter. But, I want to avoid this approach, as I want to use the same class.
Second approach: Modify the Mongo query to return data selectively as given in the docs. But here I would have to specify all the fields I want in the result set. This would again be a length query.
Is there a better way to filter out data from the object?
How would I make an API which can just get me some selective data from the User document again using the same User Pojo?
How would I go off-road with a car I would like to take me girl to the restaurant at the evening? I would not - if I would have the same car for everything I would look stupid next to the restaurant, coming out in a suite or I would stuck in a swamp.
The biggest Java advantage is object creation time - you should not be afraid of it. Just create another model for registration, another as DTO for saving data, another for front-end presentation etc
Never mix responsibility of objects. You will finish with something like
#Entity
class ThePileOfShit {
#Id
private Long id;
#my.audit.framework.Id
private String anotherId;
#JsonIgnore
// just a front-end flag ignore
private boolean flag;
#Column
// not a field but getter because of any-weird-issue-you-want-to-put-here
public String getWeirdStuff() { ... }
// Useless converters
public ModelA getAsModelA() { ... }
public ModelB getAsModelB() { ... }
// etc
// etc
}
Four frameworks, five technologies - nobody knows what's going on.
If you are afraid of converting stuff use ModelMapper or another tool but keep your POJOs as simple as possible
You can use Gson's #Expose annotation only on the fields you want to return in the API.
To serialize the data, use:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
String json = gson.toJson(userData);

Working with custom annotations in the Spring Boot app

I got the response body from the HttpServletResponse with ContentCachingResponseWrapper used.
Now, I introduced custom annotations for the entities fields in my app and I need response body returned without the fields that I have annotated.
I do not want to affect my application behavior.
For example:
#Entity
public class User implements Serializable{
....
#Column
private String firstname;
#MyCustomAnnotation
#Column
private String lastname;
...
The real response body for the client should look like:
{"firstname":"John", "lastname":"Smith"}
And response body that I need for my later work is:
{"firstname":"John", "lastname":"MyCustomAnnotation"}
or
{"firstname":"John"}
or similar.
I was wondering if it is possible to do such a thing? Can I get one version of the response(filtered) and send client real version of the response?
I would like to avoid changing of the application code (methods in the controllers, model etc.), if it's possible. I would like to do all my work in the class where I am dealing with the HttpServletResponse.
What you probably need are json views, or if you simply want to ignore a field in your response - then #JsonIgnore

Hiding sensitive information in response

I am currently working in a project where I have a User model and am using a REST API to fetch a list of users. (I have more entities.)
User has a password field. I do not want to include the password field in the result. So I excluded it in the DTO. But when I want to create a User, I want to include the password in the request. So Spring MVC gets the User entity (not the DTO).
I don't think it is good to do so.... For example, I have Event model which is connected to user with a many-to-many relationship. I don't want that in the request. I want only the user. So what do you suggest me to do? Have another kind-of DTO?
Use #JsonIgnore with Access.WRITE_ONLY for getter methods only.
Example
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
If you are using Jackson to serialize your response objects, you can annotate the property in question with #JsonIgnore and it will not be included in the response.
public User {
private String email;
#JsonIgnore
private String password
...getters and setters
}
It might also be a good idea to create separate response objects that only include the fields you want in case you add sensitive fields down the road and forget to hide them. Likewise, you would also have separate request objects for creating users that would include a password field. Business entities, like a User, are probably best to use only internally, so you can control what information goes public.
To avoid using #JsonIgnore, you can use json-view library.
For example, in your controller you can do something like this:
At first, declare this in your controller variable:
private JsonResult json = JsonResult.instance();
And then use this method:
#RequestMapping("/get/{id}")
public void getUserById(#PathVariable(value = "id") long id) {
User user = usersService.findOne(id);
json.use(JsonView.with(user)
.onClass(User.class, Match.match()
.exclude("password").exclude("yetAnothertopSecretField")));
}
It returns JSON without excluded fields.
The JsonView and JsonResult classes are imported from the json-view library.
I'm tried this JsonProperty.Access.WRITE_ONLY and it's working with me.
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
Make the field 'password' as null while sending the response and Jackson will not show that in response. Don't remove it completely from the model class.

Categories