Using the validation from PlayFramework and the data binding, is it possible, via (maybe) a decorator, to avoid binding some fields?
For example, I have this model :
class User extends Model {
#Required
#Email
public String email;
// I'd like to avoid setting this
public String password;
}
and in my model :
Store store = new Store();
Binder.bindBean(params.getRootParamNode(), store, null);
validation.valid(store);
If the user POST email AND password, password will be also set, but I don't want to.
How can I do that?
If you don't want to persist the data, but you want it to be bound as part of the automatic binding, then you can use the #Transient annotation...
Example
class User extends Model {
#Required
#Email
public String email;
// I'd like to avoid setting this
#Transient
public String password;
}
If you don't want it to be bound at all, then use the NoBinding annotation
#play.data.binding.NoBinding
Example
public class User extends Model {
#NoBinding("profile") public boolean isAdmin;
#As("dd, MM yyyy") Date birthDate;
public String name;
}
Related
I have an API with validation on it.
public class ModelVo {
#NotBlank(message = "...")
private String name;
#Pattern(regex="...", message = "...")
private String lastName;
...
}
I use of it
#PostMapping("/path1")
public ResponseEntity<RestResponse<Object>> create(#Valid #RequestBody ModelVo modelvo){
Now I want use of this validation for other method( for instance update API) again but I don't like #Pattern annotation on lastName fild work for second method. Is it possible?
Assuming that for create() you want to validate lastName with #Pattern but for update() you don't want to validate lastName you can achieve this with validation groups.
Your Controller:
#PostMapping("/path1")
public ResponseEntity<RestResponse<Object>> create(#Validated #RequestBody
ModelVo modelvo){
#PutMapping("/path1")
public ResponseEntity<RestResponse<Object>> update(#Validated(BasicInfo.class) #RequestBody
ModelVo modelvo){
Your Model class:
public class ModelVo {
#NotBlank(message = "...", groups = BasicInfo.class)
private String name;
#Pattern(regex="...", message = "...")
private String lastName;
}
You also need to create the BasicInfo class but that has nothing special.
You may get more information from the following links:
https://www.baeldung.com/spring-valid-vs-validated
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/annotation/Validated.html
I am using java+Spring framework+Hibernate for creating rest api but I have stumbled upon retrieving details of a table using foreign key attributes.
I have the following tables::
https://i.stack.imgur.com/lG7UR.png
I am retrieving all the ratings given using product id and then mapping to DTO, now I also want to populate the username using idusers as this is my foreign key.
Same is the case when I try to retrieve ratings given by the users, instead of displaying idproducts I want to display the product name and product description as It is a foreign key.
Any advice on how to do so using DTO's.
This is a perfect use case for Blaze-Persistence Entity Views.
Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. I created Entity Views on top of it to allow easy mapping between JPA models and custom interface defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
Assuming you have an entity model like this
#Entity
public class User {
#Id
Integer id;
String role;
String username;
String password;
boolean enabled;
}
#Entity
public class Product {
#Id
Integer id;
String imageUrl;
String category;
int productPrice;
int productQuantity;
String productName;
String productDesc;
#OneToMany(mappedBy = "product")
Set<Rating> ratings;
}
#Entity
public class Rating {
#Id
Integer id;
int rating;
String review;
String ratingscol;
#ManyToOne(fetch = LAZY)
Product product;
#ManyToOne(fetch = LAZY)
User user;
}
A DTO mapping for your model could look as simple as the following
#EntityView(Rating.class)
interface RatingDto {
Integer getId();
UserDto getUser();
ProductDto getProduct();
}
#EntityView(User.class)
interface UserDto {
Integer getId();
String getUsername();
}
#EntityView(Rating.class)
interface ProductDto {
Integer getId();
String getProductName();
String getProductDesc();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
RatingDto dto = entityViewManager.find(entityManager, RatingDto.class, id);
But the Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
It will only fetch the mappings that you tell it to fetch
You can use ModelMapper when converting a DTO to an Entity bean and back from Entity bean to a DTO.
Add ModelMapper to your project
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
Define the ModelMapper bean in your Spring configuration
#Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
Assuming the following models based on the given ER diagram you have given
public class UserDto {
Integer userId;
String role;
String username;
String password;
boolean enabled;
...default and parameterized constructor
...getter and setter methods
}
public class ProductDto {
Integer productId;
String imageUrl;
String category;
int productPrice;
int productQuantity;
String productName;
String productDesc;
...default and parameterized constructor
...getter and setter methods
}
public class RatingDto {
#Id
Integer id;
int rating;
String review;
String ratingscol;
ProductDto productDto;
UserDto userDto;
...default and parameterized constructor
...getter and setter methods
}
You can retrieve the ratings of a product using product id along with the user details by using the following method
#Repository
public interface RatingRepository extends JpaRepository<Rating, Integer>{
List<Rating> findByProduct_ProductId(Integer productId);
}
Then mapping rating objects to DTO
RatingDto ratingDto = modelMapper.map(rating, RatingDto.class);
Now you can retrieve username as following
ratingsDto.getUserDto().getUserName()
The same way you can retrieve the ratings by userId and access product details
I have a user entity as
#Entity
public class User {
#Id
private Long id;
private String name;
private String address;
// getter / setter
}
And controller method like:
#PutMapping(value = "/user")
public ResponseEntity<?> updateUser(#RequestBody User user) {
userRepository.save(user);
// ...
}
Now What I am trying to do is finding the field that is being updated.
Example:
If the only name is present I need some message like "Updated field is name".
Is there any better way other than comparing the fields one by one with the database stored values.
you need getUser method. for example: userRepository.getUser(user.id)
then you return the result
I have a Spring Boot based application with Jackson for JSON serialization/deserizalization and JodaTime for LocalDate object.
I have a User class :
public class User {
private String firstname;
private String lastname;
private String email;
private LocalDate birthday;
// constructor, getter, setter...
}
I have two webservices which don't expose same fields.
For example:
WS1 will expose all fields and translate birthday in the "yyyy-MM-dd" format;
WS2 will expose only firstname, lastname and birthday fields and translate birthday in the "yyyy/MM/dd" format.
It will give me something like this:
public class View {
public interface Default {}
public interface All extends Default {}
}
public class User {
#JsonView(View.Default.class)
private String firstname;
#JsonView(View.Default.class)
private String lastname;
#JsonView(View.All.class)
private String email;
#JsonView(View.Default.class)
private LocalDate birthday;
}
#RestController
public class UserController {
#RequestMapping("/ws1/user")
#JsonView(View.All.class)
public User userSeenByWS1() {
return new User("john", "doe", "john.doe#unknown.com", LocalDate.now());
/*
Must return {"firstname":"john","lastname":"doe","email":"john.doe#unknown.com","birthday":"2017-07-27"}
*/
}
#RequestMapping("/ws2/user")
#JsonView(View.Default.class)
public User userSeenByWS2() {
return new User("john", "doe", "john.doe#unknown.com", LocalDate.now());
/*
Must return {"firstname":"john","lastname":"doe","birthday":"2017/07/27"}
*/
}
}
For now, I know that I can control fields serialization with #JsonView annotation and I can create two different ObjectMapper to control LocalDate serialization. But I don't know how to pass to the #JsonView the well defined objectMapper for each webservice.
I don't want to create 2 DTOs which represent each view of my User class. I want something that I can configure via annotation.
In my current implementation I have a User entity that implements org.springframework.security.core.userdetails.UserDetails interface.
#Entity
#Table(name = "users")
public class User extends BaseEntity implements UserDetails {
private static final long serialVersionUID = 8884184875433252086L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String username;
private String password;
....
During the OAuth2 authorization I manually create a new User object, populate its fields and store in my database.
According to the UserDetails contract - UserDetails.getUsername() method can't return null but I have no values retrieved from Social Networks that can be used as username.
What value in this case should be returned in the User.getUsername() method ?
Is it okay to return something like this ?
#Override
public String getUsername() {
return String.valueOf(id);
}
If you need to save this entity before you have a valid value for the name then I think that's a problem with the design. Having said that User.getUsername() is mainly used for display purposes, so I doubt it matters what the actual value is, as long as it can be matched to something in an authentication.