Parsing polymorphic models in Spring boot

problem

You wish to build a web application that will be accepting HTTP POST requests with JSON objects in their request body to be parsed into your Java models. On top of that, the models will be using enums and inheritance.

SOLUTION

Spring boot to the rescue. Using IntelliJ IDEA ultimate edition and the embedded initializer to speed up things. Only two dependencies are added for this coding example. Lombok and Spring web. Also, I chose Java 8 and Maven build tool.

spring-lombok dependency
Choosing Lombok, the annotation library.
spring-web-dependency
Spring Web, the "fundamentals"
The app we are about to build will be able to accept Student and Tutor objects. Tutor will be inheriting from Student and both Tutor and Student will have an Enum field. Let’s create the Student model as follows:
Student.java
				
					package com.programmerabroad.parsing.model;

import lombok.*;

@Data
public class Student {
    private String name;
    private String surname;
    private StudyLevel studyLevel;
}
				
			

The StudyLevel Enum

StudyLevel.java
				
					package com.programmerabroad.parsing.model;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public enum StudyLevel {

    UNDERGRADUATE(0),
    POSTGRADUATE(1),
    DOCTORATE(2),
    POSTDOCTORATE(3);

    @Getter
    private final int studyLevel;
}
				
			

Now, let’s create the Tutor model:

Tutor.java
				
					package com.programmerabroad.parsing.model;

import lombok.Data;

@Data
public class Tutor extends Student {

    private TeachingLevel teachingLevel;
    private long experienceInHours;
}
				
			

It is using TeachingLevel enum which is defined as follows:

TeachingLevel.java
				
					package com.programmerabroad.parsing.model;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public enum TeachingLevel {

    ASSISTANT(0),
    ASSOCIATE(1),
    LECTURER(2),
    PROFESSOR(3);

    @Getter
    private final int teachingLevel;
}
				
			

Great. Now, let’s create a RestController that will be exposing two POST requests. One for accepting Student objects at /student and another one for accepting Tutor objects at /tutor.

At this moment, the controller is merely accepting these 2 objects as JSON, validating them and creating their respective Java model. The controller is defined as follows:

ParseController.java
				
					package com.programmerabroad.parsing.controller;

import com.programmerabroad.parsing.model.Student;
import com.programmerabroad.parsing.model.Tutor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ParseController {

    @PostMapping("/student")
    public String readStudent(@Validated @RequestBody Student student) {
        return student.toString();
    }

    @PostMapping("/tutor")
    public String readTutor(@Validated @RequestBody Tutor tutor) {
        return tutor.toString();
    }
}
				
			
As you can see from the return statements it is just returning the string representation of the Student and Tutor object. It is worth mentioning that the toString() method here is given behind the scenes by Lombok as both of the models are annotated by the @Data annotation. Let’s create the Main application so the web application can run.
running

The main application is as follows:

ParsingApplication.java
				
					package com.programmerabroad.parsing;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ParsingApplication {

    public static void main(String[] args) {
        SpringApplication.run(ParsingApplication.class, args);
    }
}
				
			

Running it via IntelliJ or the Maven build tool, it will be deployed by default on: http://localhost:8080/

TESTING

Let’s test the /tutor endpoint.

In IntelliJ -> Tools -> HttpClient you can easily send HTTP requests. IntelliJ has lots of examples to choose from too. In this case, it’s a simple POST as follows:

/tutor endpoint
Testing the /tutor endpoint

The response is:

				
					Tutor(teachingLevel=PROFESSOR, experienceInHours=2000)
				
			

If you wish to copy the request, here it’s the text format:

				
					POST http://localhost:8080/tutor
Content-Type: application/json

{
  "name": "A Tutor name",
  "surname": "TutorSurname",
  "teachingLevel": "PROFESSOR",
  "experienceInHours": 2000
}
				
			

Alternatively, using the curl and a terminal. In this case, I found the curlbuilder useful; it will create the curl command given its inputs.

So, posting a Tutor object in curl will be as follows:

				
					curl -v -XPOST -H "Content-type: application/json" -d '{
   "name": "A Tutor name",
   "surname": "TutorSurname",
   "teachingLevel": "PROFESSOR",
   "experienceInHours": 2000
 }' 'http://localhost:8080/tutor'
				
			

Nice! 50% tested. Now, let’s test the /student endpoint.

In IntelliJ’s HttpClient, will be as follows:

/student endpoint
testing the /student endpoint

The response is:

				
					Student(name=Ellion, surname=Sur, studyLevel=DOCTORATE)
				
			

And for copying it, here its equivalent text representation:

				
					POST http://localhost:8080/student
Content-Type: application/json

{
  "name": "Ellion",
  "surname": "Sur",
  "studyLevel": "DOCTORATE"
}
				
			

Alternatively, using curl, the command would be:

				
					curl -v -XPOST -H "Content-type: application/json" -d '{
   "name": "Ellion",
   "surname": "Sur",
   "studyLevel": "DOCTORATE"
 }' 'http://localhost:8080/student'
				
			

Great, it works!

But

What happens if an incorrect JSON object is posted? Let’s see some examples:

incorrect 1

Let’s try to post a Student object with an incorrect studyLevel value, for example:

				
					curl -v -XPOST -H "Content-type: application/json" -d '{
   "name": "Ellion",
   "surname": "Sur",
   "studyLevel": "DEAN"
 }' 'http://localhost:8080/student'
				
			

It’s responding with 400 status and the following message:

				
					{"timestamp":"2021-03-16T18:02:55.044+00:00","status":400,"error":"Bad Request","message":"","path":"\/student"}
				
			
incorrect 2

Another one incorrect example is with incorrect/ unknown field names. For example:

				
					curl -v -XPOST -H "Content-type: application/json" -d '{
   "name": "Ellion",
   "surname": "Sur",
   "studying": "DOCTORATE",
   "unknownField": 14.454
 }' 'http://localhost:8080/student'
				
			

The response is 200 and the message:

				
					Student(name=Ellion, surname=Sur, studyLevel=null)
				
			

In this case, Spring is simply ignoring unknown fields and adding null values to what is not provided, i.e. studyLevel.

conclusion

In this post we saw how easy it is to set up a web app that accepts JSON objects, validates them and parsing them into their respective Java models. Spring boot is a cool framework that can save us lots of time. Also Lombok helped us to avoid all that boilerplate code of setters/getters, constructors, etc.

References:

Share it!

Facebook
Twitter
LinkedIn
Reddit
Picture of Ellion

Ellion

Professional IT consultant, writer, programmer enthusiast interested in all sorts of coding.
Eats all cookies 🍪

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x