argumentresolver example
This commit is contained in:
BIN
spring-boot/argumentresolver/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
spring-boot/argumentresolver/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
spring-boot/argumentresolver/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
spring-boot/argumentresolver/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
@@ -3,13 +3,12 @@ package io.reflectoring.argumentresolver;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.client.HttpStatusCodeException;
|
|
||||||
|
|
||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
class ErrorHandler {
|
class ErrorHandler {
|
||||||
|
|
||||||
@ExceptionHandler(HttpStatusCodeException.class)
|
@ExceptionHandler(NotFoundException.class)
|
||||||
ResponseEntity<?> handleHttpStatusCodeException(HttpStatusCodeException e) {
|
ResponseEntity<?> handleHttpStatusCodeException(NotFoundException e) {
|
||||||
return ResponseEntity.status(e.getStatusCode()).build();
|
return ResponseEntity.status(e.getStatusCode()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package io.reflectoring.argumentresolver;
|
|||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
public class Repository {
|
class Repository {
|
||||||
|
|
||||||
private final Long id;
|
private final Long id;
|
||||||
private final String slug;
|
private final String slug;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package io.reflectoring.argumentresolver;
|
package io.reflectoring.argumentresolver;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
@@ -14,8 +13,6 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
class RepositoryArgumentResolver implements HandlerMethodArgumentResolver {
|
class RepositoryArgumentResolver implements HandlerMethodArgumentResolver {
|
||||||
|
|
||||||
private static final Pattern SLUG_PATTERN = Pattern.compile("^/([^/]*).*$");
|
|
||||||
|
|
||||||
private final RepositoryFinder repositoryFinder;
|
private final RepositoryFinder repositoryFinder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -32,20 +29,9 @@ class RepositoryArgumentResolver implements HandlerMethodArgumentResolver {
|
|||||||
|
|
||||||
String requestPath = ((ServletWebRequest) webRequest).getRequest().getPathInfo();
|
String requestPath = ((ServletWebRequest) webRequest).getRequest().getPathInfo();
|
||||||
|
|
||||||
Matcher matcher = SLUG_PATTERN.matcher(requestPath);
|
String slug = requestPath
|
||||||
|
.substring(0, requestPath.indexOf("/", 1))
|
||||||
if (!matcher.matches()) {
|
.replaceAll("^/", "");
|
||||||
throw new IllegalArgumentException(String.format(
|
|
||||||
"Cannot resolve argument of type Site. Expecting the slug to be the first part of the request path (%s).",
|
|
||||||
requestPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
String slug = matcher.group(1);
|
|
||||||
if (slug == null || slug.isBlank()) {
|
|
||||||
throw new IllegalArgumentException(String.format(
|
|
||||||
"Cannot resolve argument of type Site. Slug is empty (request path: %s).",
|
|
||||||
requestPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<Repository> repository = repositoryFinder.findBySlug(slug);
|
Optional<Repository> repository = repositoryFinder.findBySlug(slug);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package io.reflectoring.argumentresolver;
|
||||||
|
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
class RepositoryId {
|
||||||
|
|
||||||
|
private final long value;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package io.reflectoring.argumentresolver;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class RepositoryIdConverter implements Converter<String, RepositoryId> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RepositoryId convert(String source) {
|
||||||
|
return new RepositoryId(Long.parseLong(source));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
|||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
@WebMvcTest(controllers = TestController.class)
|
@WebMvcTest(controllers = RepositoryArgumentResolverTestController.class)
|
||||||
class RepositoryArgumentResolverTest {
|
class RepositoryArgumentResolverTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -26,7 +26,7 @@ class RepositoryArgumentResolverTest {
|
|||||||
given(repositoryFinder.findBySlug("my-repo"))
|
given(repositoryFinder.findBySlug("my-repo"))
|
||||||
.willReturn(Optional.of(new Repository(1L, "my-repo")));
|
.willReturn(Optional.of(new Repository(1L, "my-repo")));
|
||||||
|
|
||||||
mockMvc.perform(get("/my-repo/foo"))
|
mockMvc.perform(get("/my-repo/listContributors"))
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ class RepositoryArgumentResolverTest {
|
|||||||
given(repositoryFinder.findBySlug("unknownSlug"))
|
given(repositoryFinder.findBySlug("unknownSlug"))
|
||||||
.willReturn(Optional.empty());
|
.willReturn(Optional.empty());
|
||||||
|
|
||||||
mockMvc.perform(get("/unknownSlug/foo"))
|
mockMvc.perform(get("/unknownSlug/listContributors"))
|
||||||
.andExpect(status().isNotFound());
|
.andExpect(status().isNotFound());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ package io.reflectoring.argumentresolver;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
class TestController {
|
@RequestMapping(path = "/{repositorySlug}")
|
||||||
|
class RepositoryArgumentResolverTestController {
|
||||||
|
|
||||||
@GetMapping("/{slug}/foo")
|
@GetMapping("/listContributors")
|
||||||
String getSomething(Repository repository) {
|
String listContributors(Repository repository) {
|
||||||
assertThat(repository.getId()).isEqualTo(1L);
|
assertThat(repository.getId()).isEqualTo(1L);
|
||||||
return "test";
|
return "test";
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package io.reflectoring.argumentresolver;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
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.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
@WebMvcTest(controllers = RepositoryIdConverterTestController.class)
|
||||||
|
class RepositoryIdConverterTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private RepositoryFinder repositoryFinder;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolvesRepositoryId() throws Exception {
|
||||||
|
mockMvc.perform(get("/repositories/42"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package io.reflectoring.argumentresolver;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
class RepositoryIdConverterTestController {
|
||||||
|
|
||||||
|
@GetMapping("/repositories/{repositoryId}")
|
||||||
|
String getRepository(@PathVariable("repositoryId") RepositoryId repositoryId) {
|
||||||
|
assertThat(repositoryId).isNotNull();
|
||||||
|
return "test";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user