From 16793411c089d0f7d75e1f88e9026cc9c71cb584 Mon Sep 17 00:00:00 2001 From: Azhwani <13301425+azhwani@users.noreply.github.com> Date: Sun, 27 Nov 2022 15:50:55 +0100 Subject: [PATCH] BAEL-5978: Case Insensitive Enum Mapping in Spring Boot (#13061) * BAEL-5978: Case Insensitive Enum Mapping in Spring Boot * Move code to a new module: spring-boot-request-params --- .../spring-boot-request-params/README.md | 5 ++ .../spring-boot-request-params/pom.xml | 28 ++++++++++ .../EnumMappingMainApplication.java | 13 +++++ .../enummapping/config/EnumMappingConfig.java | 17 ++++++ .../controllers/EnumMappingController.java | 30 +++++++++++ .../converters/StringToLevelConverter.java | 19 +++++++ .../enummapping/editors/LevelEditor.java | 22 ++++++++ .../com/baeldung/enummapping/enums/Level.java | 7 +++ .../EnumMappingIntegrationTest.java | 52 +++++++++++++++++++ ...StringToLevelConverterIntegrationTest.java | 37 +++++++++++++ .../editors/LevelEditorIntegrationTest.java | 34 ++++++++++++ 11 files changed, 264 insertions(+) create mode 100644 spring-boot-modules/spring-boot-request-params/README.md create mode 100644 spring-boot-modules/spring-boot-request-params/pom.xml create mode 100644 spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java diff --git a/spring-boot-modules/spring-boot-request-params/README.md b/spring-boot-modules/spring-boot-request-params/README.md new file mode 100644 index 0000000000..f3ced26455 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/README.md @@ -0,0 +1,5 @@ +## Spring Boot Request Params + +This module contains articles about Spring Boot Request Params + +### Relevant Articles: diff --git a/spring-boot-modules/spring-boot-request-params/pom.xml b/spring-boot-modules/spring-boot-request-params/pom.xml new file mode 100644 index 0000000000..526938860a --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + spring-boot-request-params + spring-boot-request-params + jar + Module For Spring Boot Request Params + + + com.baeldung.spring-boot-modules + spring-boot-modules + 1.0.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java new file mode 100644 index 0000000000..43145f13ad --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/EnumMappingMainApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.enummapping; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EnumMappingMainApplication { + + public static void main(String[] args) { + SpringApplication.run(EnumMappingMainApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java new file mode 100644 index 0000000000..8078a3cb47 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/config/EnumMappingConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.enummapping.config; + +import org.springframework.boot.convert.ApplicationConversionService; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import com.baeldung.enummapping.converters.StringToLevelConverter; + +@Configuration +public class EnumMappingConfig implements WebMvcConfigurer { + @Override + public void addFormatters(FormatterRegistry registry) { + ApplicationConversionService.configure(registry); + registry.addConverter(new StringToLevelConverter()); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java new file mode 100644 index 0000000000..d006b8f149 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/controllers/EnumMappingController.java @@ -0,0 +1,30 @@ +package com.baeldung.enummapping.controllers; + +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.enummapping.editors.LevelEditor; +import com.baeldung.enummapping.enums.Level; + +@RestController +@RequestMapping("enummapping") +public class EnumMappingController { + + @InitBinder + public void initBinder(WebDataBinder dataBinder) { + dataBinder.registerCustomEditor(Level.class, new LevelEditor()); + } + + @GetMapping("/get") + public String getByLevel(@RequestParam(required = false) Level level) { + if (level != null) { + return level.name(); + } + return "undefined"; + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java new file mode 100644 index 0000000000..8adee1c4e5 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/converters/StringToLevelConverter.java @@ -0,0 +1,19 @@ +package com.baeldung.enummapping.converters; + +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.convert.converter.Converter; + +import com.baeldung.enummapping.enums.Level; + +public class StringToLevelConverter implements Converter { + + @Override + public Level convert(String source) { + if (StringUtils.isBlank(source)) { + return null; + } + return EnumUtils.getEnum(Level.class, source.toUpperCase()); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java new file mode 100644 index 0000000000..d4f8e96ad8 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/editors/LevelEditor.java @@ -0,0 +1,22 @@ +package com.baeldung.enummapping.editors; + +import java.beans.PropertyEditorSupport; + +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; + +import com.baeldung.enummapping.enums.Level; + +public class LevelEditor extends PropertyEditorSupport { + + @Override + public void setAsText(String text) { + if (StringUtils.isBlank(text)) { + setValue(null); + } else { + setValue(EnumUtils.getEnum(Level.class, text.toUpperCase())); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java new file mode 100644 index 0000000000..471e9c2f5c --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/main/java/com/baeldung/enummapping/enums/Level.java @@ -0,0 +1,7 @@ +package com.baeldung.enummapping.enums; + +public enum Level { + + LOW, MEDIUM, HIGH + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java new file mode 100644 index 0000000000..0fd1ce72d7 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/EnumMappingIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.enummapping; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.enummapping.controllers.EnumMappingController; +import com.baeldung.enummapping.enums.Level; + +@RunWith(SpringRunner.class) +@WebMvcTest(EnumMappingController.class) +public class EnumMappingIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenPassingLowerCaseEnumConstant_thenConvert() throws Exception { + mockMvc.perform(get("/enummapping/get?level=medium")) + .andExpect(status().isOk()) + .andExpect(content().string(Level.MEDIUM.name())); + } + + @Test + public void whenPassingUnknownEnumConstant_thenReturnUndefined() throws Exception { + mockMvc.perform(get("/enummapping/get?level=unknown")) + .andExpect(status().isOk()) + .andExpect(content().string("undefined")); + } + + @Test + public void whenPassingEmptyParameter_thenReturnUndefined() throws Exception { + mockMvc.perform(get("/enummapping/get?level=")) + .andExpect(status().isOk()) + .andExpect(content().string("undefined")); + } + + @Test + public void whenPassingNoParameter_thenReturnUndefined() throws Exception { + mockMvc.perform(get("/enummapping/get")) + .andExpect(status().isOk()) + .andExpect(content().string("undefined")); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java new file mode 100644 index 0000000000..100f742f40 --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/converters/StringToLevelConverterIntegrationTest.java @@ -0,0 +1,37 @@ +package com.baeldung.enummapping.converters; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.convert.ConversionService; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.enummapping.EnumMappingMainApplication; +import com.baeldung.enummapping.enums.Level; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = EnumMappingMainApplication.class) +public class StringToLevelConverterIntegrationTest { + + @Autowired + ConversionService conversionService; + + @Test + public void whenConvertStringToLevelEnumUsingCustomConverter_thenSuccess() { + assertThat(conversionService.convert("low", Level.class)).isEqualTo(Level.LOW); + } + + @Test + public void whenStringIsEmpty_thenReturnNull() { + assertThat(conversionService.convert("", Level.class)).isNull(); + } + + @Test + public void whenStringIsNull_thenReturnNull() { + assertThat(conversionService.convert(null, Level.class)).isNull(); + } + +} diff --git a/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java new file mode 100644 index 0000000000..ab01cbc1ed --- /dev/null +++ b/spring-boot-modules/spring-boot-request-params/src/test/java/com/baeldung/enummapping/editors/LevelEditorIntegrationTest.java @@ -0,0 +1,34 @@ +package com.baeldung.enummapping.editors; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +import com.baeldung.enummapping.enums.Level; + +public class LevelEditorIntegrationTest { + + private final LevelEditor levelEditor = new LevelEditor(); + + @Test + public void whenConvertStringToLevelEnumUsingCustomPropertyEditor_thenSuccess() { + levelEditor.setAsText("lOw"); + + assertThat(levelEditor.getValue()).isEqualTo(Level.LOW); + } + + @Test + public void whenStringIsEmpty_thenReturnNull() { + levelEditor.setAsText(""); + + assertThat(levelEditor.getValue()).isNull(); + } + + @Test + public void whenStringIsNull_thenReturnNull() { + levelEditor.setAsText(null); + + assertThat(levelEditor.getValue()).isNull(); + } + +}