Skip to content

Commit c73d381

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: #2087 Original pull request: #2088.
1 parent 71ae981 commit c73d381

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
@@ -702,10 +702,13 @@ void exectuesCustomQuerySearchThatTakesAMappedSortProperty() throws Exception {
702702
andExpect(client.hasLinkWithRel(IanaLinkRelations.SELF));
703703
}
704704

705-
@Test // DATAREST-910
705+
@Test // DATAREST-910 DATAREST-2088
706706
void callUnmappedCustomRepositoryController() throws Exception {
707-
707+
mvc.perform(post("/orders/v3/search/sort")).andExpect(status().isNotFound());
708708
mvc.perform(post("/orders/search/sort")).andExpect(status().isOk());
709+
mvc.perform(post("/orders/search/sorted")).andExpect(status().isOk());
710+
mvc.perform(post("/orders/v2/search/sort")).andExpect(status().isOk());
711+
mvc.perform(post("/orders/v2/search/sorted")).andExpect(status().isOk());
709712
mvc.perform(post("/orders/search/sort?sort=type&page=1&size=10")).andExpect(status().isOk());
710713
}
711714

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
@@ -19,11 +19,8 @@
1919
import java.util.ArrayList;
2020
import java.util.Collections;
2121
import java.util.Enumeration;
22-
import java.util.HashMap;
2322
import java.util.List;
24-
import java.util.Map;
2523
import java.util.Set;
26-
import java.util.function.Predicate;
2724

2825
import javax.servlet.http.HttpServletRequest;
2926
import javax.servlet.http.HttpServletRequestWrapper;
@@ -41,6 +38,8 @@
4138
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
4239
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
4340

41+
import static org.springframework.core.annotation.AnnotatedElementUtils.*;
42+
4443
/**
4544
* A {@link RequestMappingHandlerMapping} that augments the request mappings
4645
*
@@ -51,6 +50,8 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
5150
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!";
5251
private final RepositoryRestConfiguration configuration;
5352

53+
private final String baseUri;
54+
5455
/**
5556
* Creates a new {@link BasePathAwareHandlerMapping} using the given {@link RepositoryRestConfiguration}.
5657
*
@@ -61,16 +62,7 @@ public BasePathAwareHandlerMapping(RepositoryRestConfiguration configuration) {
6162
Assert.notNull(configuration, "RepositoryRestConfiguration must not be null!");
6263

6364
this.configuration = configuration;
64-
65-
String baseUri = configuration.getBasePath().toString();
66-
67-
if (StringUtils.hasText(baseUri)) {
68-
69-
Map<String, Predicate<Class<?>>> prefixes = new HashMap<>();
70-
prefixes.put(baseUri, it -> true);
71-
72-
this.setPathPrefixes(prefixes);
73-
}
65+
this.baseUri = configuration.getBasePath().toString();
7466
}
7567

7668
/*
@@ -128,11 +120,24 @@ protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handler
128120
ProducesRequestCondition producesCondition = customize(info.getProducesCondition());
129121
Set<MediaType> mediaTypes = producesCondition.getProducibleMediaTypes();
130122

123+
BasePathAwareController mergedAnnotation = findMergedAnnotation(handlerType, BasePathAwareController.class);
124+
if (mergedAnnotation != null) {
125+
info = appendPathPrefix(info, mergedAnnotation.value());
126+
}
127+
info = appendPathPrefix(info, new String[]{this.baseUri});
131128
return info.mutate()
132129
.produces(mediaTypes.stream().map(MediaType::toString).toArray(String[]::new))
133130
.build();
134131
}
135132

133+
private RequestMappingInfo appendPathPrefix(RequestMappingInfo info, String[] pathPrefix) {
134+
if (pathPrefix.length > 0) {
135+
String[] paths = this.resolveEmbeddedValuesInPatterns(pathPrefix);
136+
return info.mutate().paths(paths).build().combine(info);
137+
}
138+
return info;
139+
}
140+
136141
/**
137142
* Customize the given {@link ProducesRequestCondition}. Default implementation returns the condition as is.
138143
*

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)