How to control JSON serialization result from same POJO? - spring

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.

Related

Multiple Use of validations in Spring Boot

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

Why are nested objects retrieved from a OpenFeign request to a Spring Data Rest endpoint null?

I have the following domain classes in my client app:
#Value
public class Car {
private Long id;
private Model model;
}
#Value
public class Make {
private Long id;
private String name;
private Model model;
}
#Value
public class Model {
private Long id;
private String name;
}
My client app tries to get this data from a Spring Data Rest endpoint that return a HATEOAS response. The client does this via OpenFeign:
#FeignClient(name="car-service")
#Validated
public interface CarClient {
#GetMapping("/api/cars")
CollectionModel<Car> getAllCars();
}
But the each car has its make=null. How can I get make and model to be returned?

Ignoring Nested properties in Jackson OnDemand

I am working on a spring boot application with Hibernate as ORM and Jackson as JSON serialiser .
I have three model objects and CRUD operations for all three models.
Class Student{
private Teacher teacher; // Teacher of the student — to be fetched eagerly
+Getter/Setter
}
class Teacher {
private List<Subject> subject; // List of subjects associated to that user— to be fetched eagerly
+Getter/Setter
}
class Subject {
private long subjectId
//Other subject properties
+ Getter/Setter
}
Whenever I trigger a get request for student info I get the teacher info which is correct where as I also receive Subject info as well which is unnecessary for me. In the same time when I request for Teacher info, I need Subject info should be associated to that for sure. If I use #JsonBackReference for subject I am losing it all the time. I am not sure how to achieve this.
Thanks in advance for your help!!
You can also annotate like this
Class Student{
#JsonIgnoreProperties("subject")
private Teacher teacher; // Teacher of the student — to be fetched eagerly
}
You can use JSON Views
From the spring blog:
public class View {
interface Summary {}
}
public class User {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private String firstname;
#JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
public class Message {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private LocalDate created;
#JsonView(View.Summary.class)
private String title;
#JsonView(View.Summary.class)
private User author;
private List<User> recipients;
private String body;
}
and in the controller
#RestController
public class MessageController {
#Autowired
private MessageService messageService;
#JsonView(View.Summary.class)
#RequestMapping("/")
public List<Message> getAllMessages() {
return messageService.getAll();
}
#RequestMapping("/{id}")
public Message getMessage(#PathVariable Long id) {
return messageService.get(id);
}
}
PS: No link to http://fasterxml.com/ as it's currently down.

Returning returned model object to json String using spring data jpa with hibernate

I am using spring data jpa with hibernate
This is my dao interface
#Repository
public interface IUserDAO extends JpaRepository<User, Integer>{
User findByUsername( final String username );
}
This is my User class
Entity
#Table(name="USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="ID", nullable = false)
private int id;
#Column(name="USERNAME", nullable = false)
private String username;
#Column(name="NAME", nullable = false)
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This is my UserImplClass
This is my UserImplClass{
#Autowired
private IUserDAO iUserDAO;
public String findUserByUserName(String username) {
User user =iUserDAO.findByUsername(username);
Convert user to json object from framework level automatically
// i can add my one implemenation of converting user to json here ,but i want to achieve it from framework so that my code is not scattered on every service level
return "jsonStringOfUserObject"
}
Is it possible with spring data jpa with hibernate so that i do not have to write code for converting java object to json string in every service level?
I am using spring ,therefore i want to achieve it from spring .
You have two options to do what you want:
1) If you plan on returning this Object as an HTTP Response, and you use Spring MVC with Controllers you can annotate your controller method as follows:
public #ResponseBody User getUser(){
return userImplClass.findUserByUserName("yourusername");
}
2) If you want the UserImplClass itself to return a JSON String (which I do't recommend, but I leave you the decision), you can use Jackson Object Mapper to do it for you (you can inject it if you declare it as a bean on your configuration xml, or create a new instance of it, I personally prefer injecting it with #Autowired)
public String findUserByUserName(String username) {
User user =iUserDAO.findByUsername(username);
ObjectMapper mapper = new ObjectMapper(); // no need to do this if you inject via #Autowired
return mapper.writeValueAsString(user);
}

spring data mongodb MongoRepository.save(T entity) method not working?

The code is listed below:
#Document
#XmlRootElement
public class User {
#Indexed(unique=true)
private String username;
private String firstName;
private String lastName;
private String password;
...... omit setters and getters
}
public interface UserRepo extends MongoRepository<User, String>{
}
public User update(User user) {
User existingUser = userRepo.findByUsername(user.getUsername());
if (existingUser == null) {
return null;
}
existingUser.setFirstName(user.getFirstName());
existingUser.setLastName(user.getLastName());
return userRepo.save(existingUser);
}
when update method invoked, the finds the user based on username and finishes without any exceptions, the returned User obj has all updated value but the underlying mongodb document is not changed! Can anyone help? Thanks.
you need an Id field with #Id annotation

Resources