diff --git a/src/main/java/com/wilkins/showcase/DefaultProperties.java b/src/main/java/com/wilkins/showcase/DefaultProperties.java new file mode 100644 index 0000000..2f01924 --- /dev/null +++ b/src/main/java/com/wilkins/showcase/DefaultProperties.java @@ -0,0 +1,9 @@ +package com.wilkins.showcase; + +import com.wilkins.showcase.domain.Greeting; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "app.default") +public record DefaultProperties(Greeting greeting) { + +} diff --git a/src/main/java/com/wilkins/showcase/KebabProperties.java b/src/main/java/com/wilkins/showcase/KebabProperties.java new file mode 100644 index 0000000..5eca7e4 --- /dev/null +++ b/src/main/java/com/wilkins/showcase/KebabProperties.java @@ -0,0 +1,35 @@ +package com.wilkins.showcase; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Map; + +import static java.lang.Character.toUpperCase; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.IntStream.range; + +@ConfigurationProperties(prefix = "kebab") +public record KebabProperties(Map config) { + public KebabProperties(Map config) { + this.config = config.entrySet().stream() + .collect(toMap(e -> fromKebabToCamel(e.getKey()), Map.Entry::getValue)); + } + + private static String fromKebabToCamel(String key) { + var words = key.split("-"); + return range(0, words.length) + .mapToObj( + i -> { + String word = words[i]; + if (i == 0) { + return word.isEmpty() ? word : word.toLowerCase(); + } else { + return word.isEmpty() + ? word + : toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase(); + } + }) + .collect(joining()); + } +} diff --git a/src/main/java/com/wilkins/showcase/ShowcaseApplication.java b/src/main/java/com/wilkins/showcase/ShowcaseApplication.java index e2e2586..8b22183 100644 --- a/src/main/java/com/wilkins/showcase/ShowcaseApplication.java +++ b/src/main/java/com/wilkins/showcase/ShowcaseApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +@EnableConfigurationProperties(value = {KebabProperties.class, DefaultProperties.class}) @SpringBootApplication public class ShowcaseApplication { diff --git a/src/main/java/com/wilkins/showcase/controller/GreetingController.java b/src/main/java/com/wilkins/showcase/controller/GreetingController.java index 7e35380..91ce410 100644 --- a/src/main/java/com/wilkins/showcase/controller/GreetingController.java +++ b/src/main/java/com/wilkins/showcase/controller/GreetingController.java @@ -1,5 +1,6 @@ package com.wilkins.showcase.controller; +import com.wilkins.showcase.DefaultProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; @@ -7,19 +8,28 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import static java.util.Optional.ofNullable; + @RestController @RequestMapping("/greetings") public class GreetingController { private static final Logger log = LoggerFactory.getLogger(GreetingController.class); + private final DefaultProperties defaultProperties; + + public GreetingController(DefaultProperties defaultProperties) { + this.defaultProperties = defaultProperties; + } @GetMapping - public JsonGreeting getGreeting(@RequestParam(name = "salutation", required = false, defaultValue = "hello") String salutationParam, - @RequestParam(name = "name", required = false, defaultValue = "world") String nameParam) { + public JsonGreeting getGreeting(@RequestParam(name = "salutation", required = false) String salutationParam, + @RequestParam(name = "name", required = false) String nameParam) { log.info("A greeting was requested"); - var greeting = JsonGreeting.of(salutationParam, nameParam); + var greeting = JsonGreeting.of( + ofNullable(salutationParam).orElse(defaultProperties.greeting().salutation()), + ofNullable(nameParam).orElse(defaultProperties.greeting().name())); log.info("Greeting returned: {}", greeting); diff --git a/src/main/java/com/wilkins/showcase/domain/Greeting.java b/src/main/java/com/wilkins/showcase/domain/Greeting.java new file mode 100644 index 0000000..eef2cdd --- /dev/null +++ b/src/main/java/com/wilkins/showcase/domain/Greeting.java @@ -0,0 +1,7 @@ +package com.wilkins.showcase.domain; + +public record Greeting(String salutation, String name) { + public static Greeting of(String salutation, String name) { + return new Greeting(salutation, name); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..bee04bb --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,9 @@ +kebab: + config: + key-one: a + key-two: b +app: + default: + greeting: + salutation: hello + name: world \ No newline at end of file diff --git a/src/test/java/com/wilkins/showcase/controller/GreetingControllerTest.java b/src/test/java/com/wilkins/showcase/controller/GreetingControllerTest.java index 49b6a05..ba2368a 100644 --- a/src/test/java/com/wilkins/showcase/controller/GreetingControllerTest.java +++ b/src/test/java/com/wilkins/showcase/controller/GreetingControllerTest.java @@ -1,10 +1,16 @@ package com.wilkins.showcase.controller; +import com.wilkins.showcase.DefaultProperties; +import com.wilkins.showcase.KebabProperties; +import com.wilkins.showcase.domain.Greeting; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.web.servlet.MockMvc; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -16,12 +22,29 @@ public class GreetingControllerTest { @Autowired MockMvc mockMvc; + @Autowired + KebabProperties kebabProperties; + + @Autowired + DefaultProperties defaultProperties; + @Test void returnsGreeting() throws Exception { mockMvc.perform(get("/greetings")) .andExpect(status().isOk()) - .andExpect(jsonPath("$.salutation", is("hello"))) - .andExpect(jsonPath("$.name", is("world"))); + .andExpect(jsonPath("$.salutation", is("good morning"))) + .andExpect(jsonPath("$.name", is("Vietnam!"))); } + @Test + void propertiesAreLoaded() { + assertThat(kebabProperties.config()).containsEntry("keyOne", "a"); + assertThat(defaultProperties.greeting()).isEqualTo(Greeting.of("good morning", "Vietnam!")); + } + + @DynamicPropertySource + static void dynamicPropertySource(DynamicPropertyRegistry registry) { + registry.add("app.default.greeting.salutation", () -> "good morning"); + registry.add("app.default.greeting.name", () -> "Vietnam!"); + } }