Skip to content

Commit 8daacad

Browse files
yyvessodrotbohm
authored andcommitted
Add support for controller base path on BasePathAwareController / RepositoryRestController.
This commit introduces support for a common base path shared amongst all handler methods of a controller annotated with @BasePathAwareController / @RepositoryRestController. Related ticket: #2157 Original pull request: #2088.
1 parent 4bff95a commit 8daacad

File tree

5 files changed

+37
-17
lines changed

5 files changed

+37
-17
lines changed

spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaRepositoryConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ static class BooksHtmlController {
5858
void someMethod(@PathVariable String id) {}
5959
}
6060

61-
@RepositoryRestController
61+
@RepositoryRestController(path = {"orders", "orders/v2"})
6262
static class OrdersJsonController {
6363

64-
@RequestMapping(value = "/orders/search/sort", method = RequestMethod.POST, produces = "application/hal+json")
64+
@RequestMapping(value = {"/search/sort","/search/sorted"}, method = RequestMethod.POST, produces = "application/hal+json")
6565
void someMethodWithArgs(Sort sort, Pageable pageable, DefaultedPageable defaultedPageable) {}
6666
}
6767
}

spring-data-rest-tests/spring-data-rest-tests-jpa/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,10 +682,13 @@ void exectuesCustomQuerySearchThatTakesAMappedSortProperty() throws Exception {
682682
andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF));
683683
}
684684

685-
@Test // DATAREST-910
685+
@Test // DATAREST-910 DATAREST-2088
686686
void callUnmappedCustomRepositoryController() throws Exception {
687-
687+
mvc.perform(post("/orders/v3/search/sort")).andExpect(status().isNotFound());
688688
mvc.perform(post("/orders/search/sort")).andExpect(status().isOk());
689+
mvc.perform(post("/orders/search/sorted")).andExpect(status().isOk());
690+
mvc.perform(post("/orders/v2/search/sort")).andExpect(status().isOk());
691+
mvc.perform(post("/orders/v2/search/sorted")).andExpect(status().isOk());
689692
mvc.perform(post("/orders/search/sort?sort=type&page=1&size=10")).andExpect(status().isOk());
690693
}
691694

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/BasePathAwareController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.lang.annotation.RetentionPolicy;
2222
import java.lang.annotation.Target;
2323

24+
import org.springframework.core.annotation.AliasFor;
2425
import org.springframework.stereotype.Component;
2526

2627
/**
@@ -34,4 +35,9 @@
3435
@Retention(RetentionPolicy.RUNTIME)
3536
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
3637
public @interface BasePathAwareController {
38+
@AliasFor("path")
39+
String[] value() default {};
40+
41+
@AliasFor("value")
42+
String[] path() default {};
3743
}

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/BasePathAwareHandlerMapping.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@
2222
import java.util.ArrayList;
2323
import java.util.Collections;
2424
import java.util.Enumeration;
25-
import java.util.HashMap;
2625
import java.util.List;
27-
import java.util.Map;
2826
import java.util.Set;
29-
import java.util.function.Predicate;
3027

3128
import jakarta.servlet.http.HttpServletRequest;
3229
import jakarta.servlet.http.HttpServletRequestWrapper;
@@ -44,6 +41,8 @@
4441
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
4542
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
4643

44+
import static org.springframework.core.annotation.AnnotatedElementUtils.*;
45+
4746
/**
4847
* A {@link RequestMappingHandlerMapping} that augments the request mappings
4948
*
@@ -54,6 +53,8 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
5453
private static final String AT_REQUEST_MAPPING_ON_TYPE = "Spring Data REST controller %s must not use @RequestMapping on class level as this would cause double registration with Spring MVC";
5554
private final RepositoryRestConfiguration configuration;
5655

56+
private final String baseUri;
57+
5758
/**
5859
* Creates a new {@link BasePathAwareHandlerMapping} using the given {@link RepositoryRestConfiguration}.
5960
*
@@ -64,16 +65,7 @@ public BasePathAwareHandlerMapping(RepositoryRestConfiguration configuration) {
6465
Assert.notNull(configuration, "RepositoryRestConfiguration must not be null");
6566

6667
this.configuration = configuration;
67-
68-
String baseUri = configuration.getBasePath().toString();
69-
70-
if (StringUtils.hasText(baseUri)) {
71-
72-
Map<String, Predicate<Class<?>>> prefixes = new HashMap<>();
73-
prefixes.put(baseUri, it -> true);
74-
75-
this.setPathPrefixes(prefixes);
76-
}
68+
this.baseUri = configuration.getBasePath().toString();
7769
}
7870

7971
@Override
@@ -119,11 +111,24 @@ protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handler
119111
ProducesRequestCondition producesCondition = customize(info.getProducesCondition());
120112
Set<MediaType> mediaTypes = producesCondition.getProducibleMediaTypes();
121113

114+
BasePathAwareController mergedAnnotation = findMergedAnnotation(handlerType, BasePathAwareController.class);
115+
if (mergedAnnotation != null) {
116+
info = appendPathPrefix(info, mergedAnnotation.value());
117+
}
118+
info = appendPathPrefix(info, new String[]{this.baseUri});
122119
return info.mutate()
123120
.produces(mediaTypes.stream().map(MediaType::toString).toArray(String[]::new))
124121
.build();
125122
}
126123

124+
private RequestMappingInfo appendPathPrefix(RequestMappingInfo info, String[] pathPrefix) {
125+
if (pathPrefix.length > 0) {
126+
String[] paths = this.resolveEmbeddedValuesInPatterns(pathPrefix);
127+
return info.mutate().paths(paths).build().combine(info);
128+
}
129+
return info;
130+
}
131+
127132
/**
128133
* Customize the given {@link ProducesRequestCondition}. Default implementation returns the condition as is.
129134
*

spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.lang.annotation.RetentionPolicy;
2222
import java.lang.annotation.Target;
2323

24+
import org.springframework.core.annotation.AliasFor;
2425
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
2526
import org.springframework.stereotype.Component;
2627
import org.springframework.web.servlet.HandlerMapping;
@@ -46,4 +47,9 @@
4647
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
4748
@BasePathAwareController
4849
public @interface RepositoryRestController {
50+
@AliasFor("path")
51+
String[] value() default {};
52+
53+
@AliasFor("value")
54+
String[] path() default {};
4955
}

0 commit comments

Comments
 (0)