Enums as Request Parameters in Spring Boot Rest

By Dhiraj Ray, 20 February,2017  

In many enterprise application categorical variable is often required to restrict the user request. In java, we achieve it by using enums. Most of the time we define enums in model classes and expect users to provide the exact enums in the request. This also adds one level of validation in any incoming request to the server. But while using Spring controllers to expose REST endpoints, these enums are not matched directly in the method input as a request parameters because the request we get is in plain String but our controller method is expecting an enum.

In this article, we will take a look into how to accept and parse those String as enum in requet parameters while using Spring REST. We will expose a sample REST endpoint that accepts enum type as a request parameter. We will be using spring boot features to build this app. Though the enums will be defind in capitals, the request String will be in lowercase.

How to Convert String in Request Parameters to Enum

Since, our controller method in Spring REST expects enum as an input parameter instead of a plain String, we need to come up with an idea to convert that String in the request parameter to enums before the controller method handles the request and start executing. Hence, if we want enums as request parameters in spring REST, we need to convert the String in the request to correpsonding enums before the annotated method starts its execution.

Spring provides @InitBinder annotation that identifies methods which initializes the WebDataBinder and this WebDataBinder populates the arguments to the annotated methods. Hence, the easy way is to register some custom editors in Spring which will convert those Strings to enums as request parameter. Now let us see how we can achieve it in spring.We will be exposing a REST endpoint which accepts type of question in the path parameter and return response based on the question type. The question type will be an enum in java.

Maven Dependency

pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.devglan</groupId> <artifactId>spring-mvc-enum-example</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> </dependencies> </project>

Now let us define our Application.java to take advantage of spring boot features.

@SpringBootApplication Equivalent to using @Configuration, @EnableAutoConfiguration and @ComponentScan with their default attributes:

Application.java
package com.devglan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

Now let us define our enum.

QuestionCategory.java
package com.devglan.model; import java.util.Arrays; public enum QuestionCategory { CSE("cse"),ECE("ece"); private String value; private QuestionCategory(String value) { this.value = value; } public static QuestionCategory fromValue(String value) { for (QuestionCategory category : values()) { if (category.value.equalsIgnoreCase(value)) { return category; } } throw new IllegalArgumentException( "Unknown enum type " + value + ", Allowed values are " + Arrays.toString(values())); } }

Following is the model class which has enum defined above as a private member variable.

Question.java
package com.devglan.model; public class Question { private QuestionCategory type; private String question; private String answer; public QuestionCategory getType() { return type; } public void setType(QuestionCategory type) { this.type = type; } public String getQuestion() { return question; } public void setQuestion(String question) { this.question = question; } public String getAnswer() { return answer; } public void setAnswer(String answer) { this.answer = answer; } }

Now its time to define our controller - QuestionController.java. The get() method accepts question type as a path param and the question type is an enum. It also registers custom editor annotated with @InitBinder as discussed above at the start of the article. Everytime this api is called, our custom converter will execute and the String in the request parameter will be converted to corresponding enum.

QuestionController.java
package com.devglan.controller; import java.util.ArrayList; import java.util.List; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.devglan.model.Question; import com.devglan.model.QuestionCategory; import com.devglan.model.QuestionCategoryConverter; @RestController public class QuestionController { @RequestMapping(value = "/{type}", method = RequestMethod.GET) public List get(@PathVariable(value = "type") QuestionCategory category) { return getQuestionsByCategory(category); } private List getQuestionsByCategory(QuestionCategory category) { List questions = new ArrayList(); Question question = new Question(); question.setType(category); if(category == QuestionCategory.CSE){ question.setQuestion("What is Operating System."); question.setAnswer("This is the answer of what is os."); } else if(category == QuestionCategory.ECE){ question.setQuestion("What is a transistor."); question.setAnswer("This is the answer of what is transistor."); } questions.add(question); return questions; } @InitBinder public void initBinder(final WebDataBinder webdataBinder) { webdataBinder.registerCustomEditor(QuestionCategory.class, new QuestionCategoryConverter()); } }

Following is the converter class.

QuestionCategoryConverter.java
package com.devglan.model; import java.beans.PropertyEditorSupport; public class QuestionCategoryConverter extends PropertyEditorSupport{ public void setAsText(final String text) throws IllegalArgumentException { setValue(QuestionCategory.fromValue(text)); } }

Run Application

1. Run Application.java as a java application

2. Hit the url localhost://8080/ece. You can expect following result with questionType as ECE

enum-request-in-spring-rest

3. Simlarly you can try a request for localhost://8080/cse. You can see the QuestionType as CSE this time.

Conclusion

I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Download the source

References

@InitBinder Spring Docs

Suggest more topics in suggestion section or write your own article and share with your colleagues.

Is this page helpful to you? Please give us your feedback below. We would love to hear your thoughts on these articles, it will help us improve further our learning process.

Further Reading: