I have an API where I want to validate some String fields using a custom #Annotation. Validation should happen when the user sends the data. If validation fails, I want to throw an exception. Validation will be complex, as I want to check for SQL & HTML injections.
I got the following Request Object:
public class UserUpdateRequest extends BasicDataObject {
private static final long serialVersionUID = 1295104288600535600L;
// I would like to validate the firstName value upon receiving data
#CustomValidator
private String firstName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
This is my BasicDataObject :
#XmlRootElement
public abstract class BasicDataObject implements Serializable {
/**
* The generated serialVersionUID.
*/
private static final long serialVersionUID = 2876242398874879466L;
// some more stuff
}
How would I achieve this? I know that I can create custom annotation interfaces like this:
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(value = RetentionPolicy.RUNTIME)
public #interface CustomValidator {
String value();
}
But I do not know where to actually put my validation logic so that it is called on every field that I annotate with #CustomValidator. I do not use Spring. Any help is appreciated!
EDIT:
This is my web adapter using javax where I get the UserUpdateRequest:
#Path("/users")
#Produces("application/json")
#Consumes("application/json")
#GlobalSecurityResponse
public class UserAdapter {
#PUT
#JWTSecured(tokenType = UserTokenTypeEnum.AUTH, permissions = { UserEndpointPermissionsEnum.ACTIVE })
public Response updateUser(#Context SecurityContext securityContext, final UserUpdateRequest userUpdateRequest) {
Principal principal = securityContext.getUserPrincipal();
long userId = userBoundary.getPrincipalUserId(principal);
UserLoginResponse userLoginResponse = userBoundary.updateUser(userId, userUpdateRequest);
return Response.ok(userLoginResponse).build();
}
}
You created interface but does not created validator class which will be used by that interface.
Your validation logic will go inside isValid method of validator class.
You can find implementation here
Related
I am using Spring to develop new REST API, I have BaseResponse class which acts as base responses for all response. this class contains attribute String requestUuid; at some cases this requestUuid must be serialized with attribute name requestUuid , on other cases it must be seriliazed as request_uuid, i know i can use #JsonProperty as a field level annotation, but it will affect all responses. is there is any way to override attribute name specifically for each one of the derived classes.
You can use the #JsonProperty on the method level instead. That way, you can override the field's getter method in the subclass and annotate that.
For example:
class BaseResponse {
private String requestUuid;
public getRequestUuid() {
return requestUuid;
}
}
class OtherResponse extends BaseResponse {
#Override
#JsonProperty("request_uuid")
public getRequestUuid() {
return super.getRequestUuid();
}
}
You can send the field twice with different key names.
#JsonAnyGetter
public Map<String, Object> otherFields() {
Map<String, Object> otherFields = new HashMap<>();
otherFields.put("requestUuid", this.requestUuid);
otherFields.put("request_uuid", this.requestUuid);
return otherFields;
}
Also, ignore your actual field:
#JsonIgnore
private String requestUuid;
Expanding on #JoshA response, another alternative is to define a constructor and annotate it. This leads to a more concise code by avoiding the need to override the getter methods in derived classes.
class BaseResponse {
private String firstName;
private String lastName;
public BaseResponse(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public getFirstName() {
return firstName;
}
public getLastName() {
return lastName;
}
}
class OtherResponse extends BaseResponse {
public OtherResponse(#JsonProperty("given_name") String firstName, #JsonProperty("family_name") String lastName) {
super(firstName, lastName);
}
}
NO, its not possible, what is possible you can make new class for different type of requests.
I have a scenario where a property has a different validation applied depending on end-point. This is done via "groups" (code example below & reference to dropwizard doc: http://www.dropwizard.io/0.9.3/docs/manual/validation.html#validated). I implemented the DropWizard validations but the Swagger does not recognizing the "groups" and therefore doesn't provided correct model description. In addition Swagger doesn't seem to have any annotations that would accomplish the scenario. Can you please help? Thank you.
public interface Version1FirstName { }
public interface Version2FirstName { }
class Person {
#NotEmpty(groups = Version1FirstName .class)
#Length(max = 5, groups = Version2FirstName .class)
private firstName;
private lastName;
}
#POST
#Path("/v1")
public void addName(#Validated(Version1FirstName.class) Person person) {}
#POST
#Path("/v2")
public void retriveName(#Validated({Version2FirstName.class,
Version1FirstName.class}) Person person) {}
I'm using spring-data-rest to expose a database content via a spring servlet. Using #QuerydslPredicate for being able to send a filter via HTTP GET, like:
localhost:8080/persons?firstname=john&lastname=doe
Question: is it possible to tell the Predicate validation rules? Eg that the specific fields may not be null, eg lastname?
#RestController
public class PersonServlet {
#GetMapping("/persons")
public Iterable<Person> getPersons(
#QuerydslPredicate(root = Person.class) com.querydsl.core.types.Predicate predicate,
Pageable pageable) {
return dao.findAll(predicate, pageable);
}
#Entity
public class Person {
private String firstname;
private String lastname;
private String age;
//many more fields
}
}
There seems to be no way validating eg QPerson.lastname != null.
So I used the following approach adding #Valid Person as get parameter and adding validation constraints like #NotNull.
#RestController
public class PersonServlet {
#GetMapping("/persons")
public Iterable<Person> getPersons(
#QuerydslPredicate(root = Person.class) com.querydsl.core.types.Predicate predicate,
Pageable pageable,
#Valid Person p) {
return dao.findAll(predicate, pageable);
}
#Entity
public class Person {
private String firstname;
#NotNull
private String lastname;
private String age;
//many more fields
}
}
I am using Spring web services REST API that gives the JSON response.
The API usage:
#ResponseBody
#RequestMapping(value="/user", method = {RequestMethod.POST})
Details user(#RequestParam("username")
String username, #RequestParam("password") String password)
The JSON coming is:
{
"result":{
"details" : {
"firstName":"My",
"lastName":"God",
"enabled": false,
"id":927878192,
"language":"en_US",
}
}
}
I am having a Details class with the getter and setter methods for firstName, lastName, enabled, id and language.
The class is annotated with #JsonIgnoreProperties(ignoreUnknown = true).
However I don't want to show language and enabled in JSON response.
So in my java code, I did the following for language:
details.setLanguage(null);
That worked fine.
But I can't do details.setEnabled(null) because the enabled variable is primitive that can take true or false but not null. So my JSON response always has "enabled": false.
What can be done so that this field will not be a part of JSON response.
Try to use #JsonIgnore annotation on field level.
For example:
#JsonIgnore
private boolean isActive;
If you want to ignore the property only for selected response I suggest using #JsonView from com.fasterxml.jackson.annotation package but it could be an overkill.
First you need to create a class with an interface inside:
public class View {
public interface UserDetailed {}
}
After that you specify in your class which field should be visible only for specific 'profile':
public class User {
// Other fields
#JsonView(View.UserDetailed.class)
private List<Role> roleCollection = new ArrayList<Role>();
// Other fields, getters and setters
}
Then on the controller's method that needs to display that property you do:
#Controller
public class UserController{
#RequestMapping(value = "/userWithRoles", method = RequestMethod.GET)
#JsonView(View.UserDetailed.class)
public User getUserWithRoles() {…}
#RequestMapping(value = "/userWithoutRoles", method = RequestMethod.GET)
public User getUserWithoutRoles() {…}
}
The result is: only the controller methods that have the same #JsonView as the field will display it. Other will ignore it. It allows you to manage the visibility of the fields depending on the use case.
Here you can read more about it:
http://wiki.fasterxml.com/JacksonJsonViews
Put #JsonIgnore on the enabled getter method.
If you want to ignore it only during serialization but you need it when deserializing (if you need to edit that field from some method of the REST API), you can annotate with #JsonSetter("enabled") the enabled setter method.
Example:
public class Details {
....
private boolean enabled;
...
#JsonIgnore
public boolean isEnabled()
#JsonSetter
public void setEnabled(boolean enabled)
}
If you for some API method need enabled and for others no, the cleanest way to do so is to have two DTOs:
public class DetailsBasic {
private String firstName;
private String lastName;
private long id;
// getters and setters
}
public class Details extends DetailsBasic {
private boolean enabled;
private boolean language;
// getters and setters
}
And then in your controller:
#ResponseBody
#RequestMapping(value="/user", method = {RequestMethod.POST})
DetailsBasic user(#RequestParam("username")
String username, #RequestParam("password") String password) {
return ...
}
#ResponseBody
#RequestMapping(value="/otherMethod", method = {RequestMethod.POST})
Details otherMethod(#RequestParam("username")
String username, #RequestParam("password") String password) {
return ...
}
I'd like to make use of spring-security with ROLE_ADMIN and ROLE_USER roles.
I therefore try to create a typesafe enum class, but the #Secured annotation requires a constant String, which I cannot achieve by using an enum class.
What could I change in the following code?
public enum UserRole {
ADMIN("ROLE_ADMIN");
private String role;
public UserRole(String role) {
this.role = role;
}
}
//error: The value for annotation attribute Secured.value must be a constant expression
#Secured(USerRole.ADMIN.value())
public class SecuredView {
}
This question is a bit old, but this is my take on it:
public enum Role implements GrantedAuthority {
ROLE_USER, ROLE_ADMIN;
#Override
public String getAuthority() {
return name();
}
}
You can then use this together with #PreAuthorize and Spring Expression Language to authorize your methods and classes like so:
#PreAuthorize("hasRole(T(<package name>.Role).ROLE_ADMIN)")
public void doSomeThing() {
...
}
Note: The package name has to be the entire package name (org.company.project) and without the < and >.
As you can see, this isn't type safe per definition, as SpEL expressions are still strings, but IDEs like IntelliJ recognizes them, and will let you know of any errors.
You can use #PreAuthorize with multiple roles using hasAnyRole().
Of course, this may become a bit verbose with many roles, but you can make it prettier by creating your own annotation like this:
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#PreAuthorize("hasRole(T(<package name>.Role).ROLE_ADMIN)")
public #interface AdminAuthorization {
}
Following this, you can authorize your methods like so:
#AdminAuthorization
public void doSomething() {
...
}
Partial solution:
public enum Role implements GrantedAuthority {
ADMIN(Code.ADMIN),
USER(Code.USER);
private final String authority;
Role(String authority) {
this.authority = authority;
}
#Override
public String getAuthority() {
return authority;
}
public class Code {
public static final String ADMIN = "ROLE_ADMIN";
public static final String USER = "ROLE_USER";
}
}
Results in:
#Secured(Role.Code.ADMIN)
If you are using Lombok you can use the #FieldNameConstants annotation:
#FieldNameConstants
public class UserRoles {
private String ROLE_USER, ROLE_ADMIN;
}
And then use it like this:
#Secured(UserRoles.Fields.ROLE_ADMIN)
Maybe in the future, there will be the #EnumNameConstants annotation, which would fit even better.