From 7ad1e5692b284e4602c99e6f5c02c8f1952f8123 Mon Sep 17 00:00:00 2001 From: Yasin Bhojawala Date: Sat, 28 Oct 2017 20:41:20 +0530 Subject: [PATCH 1/6] BAEL-1217 Guide to Spring Type Conversions --- spring-boot/.gitignore | 1 - .../java/org/baeldung/config/WebConfig.java | 11 +++++ .../converter/GenericBigDecimalConverter.java | 36 +++++++++++++++ .../converter/StringToEmployeeConverter.java | 14 ++++++ .../converter/CustomConverterTest.java | 45 +++++++++++++++++++ 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java create mode 100644 spring-boot/src/main/java/org/baeldung/converter/StringToEmployeeConverter.java create mode 100644 spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java diff --git a/spring-boot/.gitignore b/spring-boot/.gitignore index a64317df5e..e26d6af438 100644 --- a/spring-boot/.gitignore +++ b/spring-boot/.gitignore @@ -2,4 +2,3 @@ .settings/ .classpath .project -/.apt_generated/ diff --git a/spring-boot/src/main/java/org/baeldung/config/WebConfig.java b/spring-boot/src/main/java/org/baeldung/config/WebConfig.java index 4ef407823e..6609791c69 100644 --- a/spring-boot/src/main/java/org/baeldung/config/WebConfig.java +++ b/spring-boot/src/main/java/org/baeldung/config/WebConfig.java @@ -1,7 +1,11 @@ package org.baeldung.config; +import org.baeldung.converter.GenericBigDecimalConverter; +import org.baeldung.converter.StringToEnumConverterFactory; +import org.baeldung.converter.StringToEmployeeConverter; import org.baeldung.web.resolver.HeaderVersionArgumentResolver; import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @@ -14,4 +18,11 @@ public class WebConfig extends WebMvcConfigurerAdapter { public void addArgumentResolvers(final List argumentResolvers) { argumentResolvers.add(new HeaderVersionArgumentResolver()); } + + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new StringToEmployeeConverter()); + registry.addConverterFactory(new StringToEnumConverterFactory()); + registry.addConverter(new GenericBigDecimalConverter()); + } } diff --git a/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java b/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java new file mode 100644 index 0000000000..da46c43dad --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java @@ -0,0 +1,36 @@ +package org.baeldung.converter; + +import com.google.common.collect.ImmutableSet; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.GenericConverter; + +import java.math.BigDecimal; +import java.util.Set; + +public class GenericBigDecimalConverter implements GenericConverter { + @Override + public Set getConvertibleTypes () { + + ConvertiblePair[] pairs = new ConvertiblePair[] { + new ConvertiblePair(Number.class, BigDecimal.class), + new ConvertiblePair(String.class, BigDecimal.class)}; + + return ImmutableSet.copyOf(pairs); + } + + @Override + public Object convert (Object source, TypeDescriptor sourceType, + TypeDescriptor targetType) { + if (sourceType.getType() == BigDecimal.class) { + return source; + } + + if(sourceType.getType() == String.class) { + String number = (String) source; + return new BigDecimal(number); + } else { + Number number = (Number) source; + return new BigDecimal(number.doubleValue()); + } + } +} diff --git a/spring-boot/src/main/java/org/baeldung/converter/StringToEmployeeConverter.java b/spring-boot/src/main/java/org/baeldung/converter/StringToEmployeeConverter.java new file mode 100644 index 0000000000..d7356323ee --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/converter/StringToEmployeeConverter.java @@ -0,0 +1,14 @@ +package org.baeldung.converter; + + +import com.baeldung.toggle.Employee; +import org.springframework.core.convert.converter.Converter; + +public class StringToEmployeeConverter implements Converter { + + @Override + public Employee convert(String from) { + String[] data = from.split(","); + return new Employee(Long.parseLong(data[0]), Double.parseDouble(data[1])); + } +} diff --git a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java new file mode 100644 index 0000000000..eda05a8441 --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java @@ -0,0 +1,45 @@ +package org.baeldung.converter; + +import com.baeldung.toggle.Employee; +import org.baeldung.Application; +import org.baeldung.domain.Modes; +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.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import java.math.BigDecimal; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = Application.class) +@WebAppConfiguration +public class CustomConverterTest { + + @Autowired + ConversionService conversionService; + + @Test + public void whenConvertStringToIntegerUsingDefaultConverter_thenSuccess() { + System.out.println(conversionService.convert("25", Integer.class)); + } + + @Test + public void whenConvertStringToEmployee_thenSuccess() { + System.out.println(conversionService.convert("1,50000.00", Employee.class)); + } + + @Test + public void whenConvertStringToEnum_thenSuccess() { + System.out.println(conversionService.convert("ALPHA", Modes.class)); + } + + @Test + public void whenConvertingToBigDecimalUsingGenericConverter_thenSuccess() { + System.out.println(conversionService.convert(Integer.valueOf(11), BigDecimal.class)); + System.out.println(conversionService.convert(Double.valueOf(25.23), BigDecimal.class)); + System.out.println(conversionService.convert("2.32", BigDecimal.class)); + } +} From 89f9e2fed6fd2f15a26a84edf4e5045caf0cc2e5 Mon Sep 17 00:00:00 2001 From: Yasin Bhojawala Date: Sat, 28 Oct 2017 20:43:39 +0530 Subject: [PATCH 2/6] reverting .gitignore changes --- spring-boot/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-boot/.gitignore b/spring-boot/.gitignore index e26d6af438..ebf3ee7f16 100644 --- a/spring-boot/.gitignore +++ b/spring-boot/.gitignore @@ -2,3 +2,4 @@ .settings/ .classpath .project +/.apt_generated/ \ No newline at end of file From e56da99216d9e63bc8b7c9b61569f9fe35e0fc63 Mon Sep 17 00:00:00 2001 From: Yasin Bhojawala Date: Sun, 29 Oct 2017 17:20:47 +0530 Subject: [PATCH 3/6] BAEL-1217 Guide to Spring Type Conversions Review comments --- .../converter/GenericBigDecimalConverter.java | 5 ++- .../StringToEmployeeConverterController.java | 21 ++++++++++ .../converter/CustomConverterTest.java | 20 +++++++--- ...ringToEmployeeConverterControllerTest.java | 39 +++++++++++++++++++ 4 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java create mode 100644 spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java diff --git a/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java b/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java index da46c43dad..e96dbeaf47 100644 --- a/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java +++ b/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java @@ -5,6 +5,7 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.GenericConverter; import java.math.BigDecimal; +import java.math.MathContext; import java.util.Set; public class GenericBigDecimalConverter implements GenericConverter { @@ -30,7 +31,9 @@ public class GenericBigDecimalConverter implements GenericConverter { return new BigDecimal(number); } else { Number number = (Number) source; - return new BigDecimal(number.doubleValue()); + BigDecimal converted = new BigDecimal(number.doubleValue()); + converted.setScale(2, BigDecimal.ROUND_HALF_EVEN); + return converted; } } } diff --git a/spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java b/spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java new file mode 100644 index 0000000000..f08bd9149e --- /dev/null +++ b/spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java @@ -0,0 +1,21 @@ +package org.baeldung.converter.controller; + +import com.baeldung.toggle.Employee; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/string-to-employee") +public class StringToEmployeeConverterController { + + @GetMapping + public ResponseEntity getStringToEmployee(@RequestParam("employee") Employee employee) { + return ResponseEntity.ok(employee); + } + + @PostMapping(consumes = {MediaType.TEXT_PLAIN_VALUE}) + public ResponseEntity postStringToEmployee(@RequestBody Employee employee) { + return ResponseEntity.ok(employee); + } +} diff --git a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java index eda05a8441..8446196758 100644 --- a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java +++ b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java @@ -13,6 +13,8 @@ import org.springframework.test.context.web.WebAppConfiguration; import java.math.BigDecimal; +import static org.assertj.core.api.Assertions.assertThat; + @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) @WebAppConfiguration @@ -23,23 +25,29 @@ public class CustomConverterTest { @Test public void whenConvertStringToIntegerUsingDefaultConverter_thenSuccess() { - System.out.println(conversionService.convert("25", Integer.class)); + assertThat(conversionService.convert("25", Integer.class)).isEqualTo(25); } @Test public void whenConvertStringToEmployee_thenSuccess() { - System.out.println(conversionService.convert("1,50000.00", Employee.class)); + Employee employee = conversionService.convert("1,50000.00", Employee.class); + Employee actualEmployee = new Employee(1, 50000.00); + assertThat(conversionService.convert("1,50000.00", Employee.class)) + .isEqualToComparingFieldByField(actualEmployee); } @Test public void whenConvertStringToEnum_thenSuccess() { - System.out.println(conversionService.convert("ALPHA", Modes.class)); + assertThat(conversionService.convert("ALPHA", Modes.class)).isEqualTo(Modes.ALPHA); } @Test public void whenConvertingToBigDecimalUsingGenericConverter_thenSuccess() { - System.out.println(conversionService.convert(Integer.valueOf(11), BigDecimal.class)); - System.out.println(conversionService.convert(Double.valueOf(25.23), BigDecimal.class)); - System.out.println(conversionService.convert("2.32", BigDecimal.class)); + assertThat(conversionService.convert(Integer.valueOf(11), BigDecimal.class)). + isEqualTo(BigDecimal.valueOf(11)); + assertThat(conversionService.convert(Double.valueOf(25.23), BigDecimal.class)) + .isEqualByComparingTo(BigDecimal.valueOf(Double.valueOf(25.23))); + assertThat(conversionService.convert("2.32", BigDecimal.class)) + .isEqualTo(BigDecimal.valueOf(2.32)); } } diff --git a/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java b/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java new file mode 100644 index 0000000000..5e005af0ea --- /dev/null +++ b/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java @@ -0,0 +1,39 @@ +package org.baeldung.converter.controller; + +import org.baeldung.Application; +import org.baeldung.boot.DemoApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.hamcrest.CoreMatchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class) +@AutoConfigureMockMvc +//@AutoConfigureTestDatabase +public class StringToEmployeeConverterControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void getStringToEmployeeTest() throws Exception { + mockMvc.perform(get("/string-to-employee?employee=1,2000")) + .andDo(print()) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.salary", is(2000.0))) + .andExpect(status().isOk()); + } +} \ No newline at end of file From 9fee77a9d94a3547f6198647bd94f97612fb6aaa Mon Sep 17 00:00:00 2001 From: Yasin Bhojawala Date: Sun, 29 Oct 2017 17:24:59 +0530 Subject: [PATCH 4/6] reverting unnecessary files --- .../StringToEmployeeConverterController.java | 21 ---------- ...ringToEmployeeConverterControllerTest.java | 39 ------------------- 2 files changed, 60 deletions(-) delete mode 100644 spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java delete mode 100644 spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java diff --git a/spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java b/spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java deleted file mode 100644 index f08bd9149e..0000000000 --- a/spring-boot/src/main/java/org/baeldung/converter/controller/StringToEmployeeConverterController.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.baeldung.converter.controller; - -import com.baeldung.toggle.Employee; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/string-to-employee") -public class StringToEmployeeConverterController { - - @GetMapping - public ResponseEntity getStringToEmployee(@RequestParam("employee") Employee employee) { - return ResponseEntity.ok(employee); - } - - @PostMapping(consumes = {MediaType.TEXT_PLAIN_VALUE}) - public ResponseEntity postStringToEmployee(@RequestBody Employee employee) { - return ResponseEntity.ok(employee); - } -} diff --git a/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java b/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java deleted file mode 100644 index 5e005af0ea..0000000000 --- a/spring-boot/src/test/java/org/baeldung/converter/controller/StringToEmployeeConverterControllerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.baeldung.converter.controller; - -import org.baeldung.Application; -import org.baeldung.boot.DemoApplication; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.hamcrest.CoreMatchers.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class) -@AutoConfigureMockMvc -//@AutoConfigureTestDatabase -public class StringToEmployeeConverterControllerTest { - - @Autowired - private MockMvc mockMvc; - - @Test - public void getStringToEmployeeTest() throws Exception { - mockMvc.perform(get("/string-to-employee?employee=1,2000")) - .andDo(print()) - .andExpect(jsonPath("$.id", is(1))) - .andExpect(jsonPath("$.salary", is(2000.0))) - .andExpect(status().isOk()); - } -} \ No newline at end of file From 729c392019658fad952734acd0faf2a5ec0c58c6 Mon Sep 17 00:00:00 2001 From: Yasin Bhojawala Date: Sun, 29 Oct 2017 19:16:42 +0530 Subject: [PATCH 5/6] BAEL-1217 fixed failing tests --- .../org/baeldung/converter/GenericBigDecimalConverter.java | 3 +-- .../test/java/org/baeldung/converter/CustomConverterTest.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java b/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java index e96dbeaf47..7be038910b 100644 --- a/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java +++ b/spring-boot/src/main/java/org/baeldung/converter/GenericBigDecimalConverter.java @@ -32,8 +32,7 @@ public class GenericBigDecimalConverter implements GenericConverter { } else { Number number = (Number) source; BigDecimal converted = new BigDecimal(number.doubleValue()); - converted.setScale(2, BigDecimal.ROUND_HALF_EVEN); - return converted; + return converted.setScale(2, BigDecimal.ROUND_HALF_EVEN); } } } diff --git a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java index 8446196758..faa6baffbb 100644 --- a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java +++ b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java @@ -44,7 +44,7 @@ public class CustomConverterTest { @Test public void whenConvertingToBigDecimalUsingGenericConverter_thenSuccess() { assertThat(conversionService.convert(Integer.valueOf(11), BigDecimal.class)). - isEqualTo(BigDecimal.valueOf(11)); + isEqualTo(BigDecimal.valueOf(11.00).setScale(2, BigDecimal.ROUND_HALF_EVEN)); assertThat(conversionService.convert(Double.valueOf(25.23), BigDecimal.class)) .isEqualByComparingTo(BigDecimal.valueOf(Double.valueOf(25.23))); assertThat(conversionService.convert("2.32", BigDecimal.class)) From 7c2b4e6f881da4a6296183b456be99a39157df48 Mon Sep 17 00:00:00 2001 From: Yasin Bhojawala Date: Sun, 29 Oct 2017 19:20:54 +0530 Subject: [PATCH 6/6] format code --- .../test/java/org/baeldung/converter/CustomConverterTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java index faa6baffbb..0fd181c1de 100644 --- a/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java +++ b/spring-boot/src/test/java/org/baeldung/converter/CustomConverterTest.java @@ -43,8 +43,8 @@ public class CustomConverterTest { @Test public void whenConvertingToBigDecimalUsingGenericConverter_thenSuccess() { - assertThat(conversionService.convert(Integer.valueOf(11), BigDecimal.class)). - isEqualTo(BigDecimal.valueOf(11.00).setScale(2, BigDecimal.ROUND_HALF_EVEN)); + assertThat(conversionService.convert(Integer.valueOf(11), BigDecimal.class)) + .isEqualTo(BigDecimal.valueOf(11.00).setScale(2, BigDecimal.ROUND_HALF_EVEN)); assertThat(conversionService.convert(Double.valueOf(25.23), BigDecimal.class)) .isEqualByComparingTo(BigDecimal.valueOf(Double.valueOf(25.23))); assertThat(conversionService.convert("2.32", BigDecimal.class))