How to use same java class in different api in Spring Boot

how to use jsonview.jpg

What problem are we solving?

Consider the below POJO (Plain Old Java Object) for an illustration purpose

package model;

public class Employee {  
private String name;  
private String id;  
private double sal;  
private String address;
private String specialization;
private String[] teachingSubjects;
}

Let us assume that a school management software uses the above Employee class. Let us also assume that the Employee class represents both teaching and non-teaching staff! Surprised? Well, if it could be done then we would have only one class and the model package would be clean. This way, we would not create two POJOs like below and increase confusion.

package model;

public class Teacher {  
private String name;  
private String id;  
private double sal;  
private String address;
private String specialization; // field only for teacher
private String[] teachingSubjects; // field only for teacher
}

package model;

public class NonTeachingStuff {  
private String name;  
private String id;  
private double sal;  
private String address;
}

Now you may think that we could create a POJO containing common fields from both classes. And then inherit that class in NonTeachingStuff class as below

package model;

public class EmployeeCommonProperties {  
private String name;  
private String id;  
private double sal;  
private String address;
}

// and then 
package model;

public class Teacher extends EmployeeCommonProperties {  
private String specialization; // field only for teacher
private String[] teachingSubjects; // field only for teacher
}

package model;

public class NonTeachingStuff extends EmployeeCommonProperties {  }

And my thought is, YES, you could. But simply this can not be done in every scenario. So let us confine ourselves where the extend/inherit does not seem to be the right thing to do.

Now come back to the problem we are solving. We want to use the Employee class alone and would represent both Teacher and NonTeachingStuff class.

The Solution using JSONView

The solution today in my mind is JsonView. 

To use this JsonView we have to make changes in 3 places.

  1. In controller
  2. Create a new class file to hold the views
  3. Model class

The trick is to create a label or a name that can identify the collection of fields from the POJO. That means we are representing a collection of fields by a name. Now let us find out how we can create the label or name.

Create a new class named JSONViewResponse  as below

package response;

public class JSONViewResponse{  
public static class Teacher { };
public static class NonTeachingStuff { };
}

Now our labels are ready, let us mark the fields that we want to come under that label. See the below labeling carefully. We added an annotation @JsonView on top of the fields that we want to come under the label, as below

package model;

public class Employee { 

@JsonView(JSONViewResponse.NonTeachingStuff.class) 
private String name;

@JsonView(JSONViewResponse.NonTeachingStuff.class)  
private String id;

@JsonView(JSONViewResponse.NonTeachingStuff.class)   
private double sal;

@JsonView(JSONViewResponse.NonTeachingStuff.class)   
private String address;

private String specialization; // field only for teacher
private String[] teachingSubjects; // field only for teacher
}

Now NonTeachingStuff class is ready and consists of only those fields that have @JsonView(JSONViewResponse.NonTeachingStuff.class) on top of it. To use it in the response of the controller call, we have to write this as below

package controller;

public class Controller{  

@JsonView(JSONViewResponse.NonTeachingStuff.class)
@PostMapping(value = "/getNonTeachingStuffDetailsById/{id}")
public ResponseEntity<Employee> getNonTeachingStuffDetailsById(@PathVariable(value = "id")){
        // service class we have not discussed here 
        return yourService.getNonTeachingStuffDetailsById(id);
}
}

What happened here? As we have already marked the fields that may be included in the NonTeachingStuff class, just mentioning the class name in the @JsonView  annotation is sufficient. But note that we return the whole Employee class inside the response entity. That means the final JSON response is being created after the controller function returns the whole Employee. 

Now you have learned how to return the NonTeachingStuff, let us find out how to use the same Employee class and JSONView to return the Teacher class. Below we create Teacher view

package model;

public class Employee { 

@JsonView(JSONViewResponse.Teacher.class) 
private String name;

@JsonView(JSONViewResponse.Teacher.class)  
private String id;

@JsonView(JSONViewResponse.Teacher.class)   
private double sal;

@JsonView(JSONViewResponse.Teacher.class)   
private String address;

@JsonView(JSONViewResponse.Teacher.class)
private String specialization; // field only for teacher

@JsonView(JSONViewResponse.Teacher.class)
private String[] teachingSubjects; // field only for teacher
}

The rest you can create in the same way as we created NonTeachingStuff in Controller. There is one catch here. How can we write more than one JSONView class name on top of one single field variable? The answer is as below


@JsonView({JSONViewResponse.Teacher.class, JSONViewResponse.NonTeachingStuff.class}) 
private String name;

That is all. If you feel any difficulties please let us know in the comment box.

[Acknowledgement: Photo by Markus Spiske: https://www.pexels.com/photo/javascript-code-1972464/]

 

Leave a Reply