Skip to content

Commit 24c63c9

Browse files
committed
Adopt RepositoryRestConfigurer and discourage subclassing
A RepositoryRestMvcConfiguration subclass provided by a user is problematic in a Spring Boot application as it causes RepositoryRestMvcConfiguration's bean declarations to be processed before any auto-configuration runs. One problem that this causes is that it switches off Boot's Jackson auto-configuration due to RepositoryRestMvcConfiguration having already declared multiple ObjectMapper beans. Unlike Boot's auto-configured ObjectMapper, none of these ObjectMappers are marked as @primary. This then leads to wiring failures due to multiple candidates being available. To address this problem a new RepositoryRestConfigurer abstract has been introduced in Spring Data Gosling. Its use is now strongly preferred over subclassing RepositoryRestMvcConfiguration. Note that our own RepositoryRestMvcConfiguration subclass remains. It is imported as part of auto-configuration (avoiding the ordering problems described above), and provides configuration properties binding for RepositoryRestConfiguration. However, the Jackson ObjectMapper configuration has been moved out into a new RepositoryRestConfigurer implementation. While SpringBootRepositoryRestMvcConfiguration remains, this commit makes it package private to discourage users from subclassing it. While this may break existing applications, it, coupled with the documentation updates, will hopefully guide them toward using RepositoryRestConfigurer. Closes gh-3439
1 parent 9cd3b20 commit 24c63c9

File tree

5 files changed

+58
-40
lines changed

5 files changed

+58
-40
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfiguration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2323
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
2424
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
25+
import org.springframework.context.annotation.Bean;
2526
import org.springframework.context.annotation.Configuration;
2627
import org.springframework.context.annotation.Import;
2728
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
@@ -49,4 +50,9 @@
4950
@Import(SpringBootRepositoryRestMvcConfiguration.class)
5051
public class RepositoryRestMvcAutoConfiguration {
5152

53+
@Bean
54+
public SpringBootRepositoryRestConfigurer springBootRepositoryRestConfigurer() {
55+
return new SpringBootRepositoryRestConfigurer();
56+
}
57+
5258
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2012-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.rest;
18+
19+
import org.springframework.beans.factory.annotation.Autowired;
20+
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
21+
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
22+
23+
import com.fasterxml.jackson.databind.ObjectMapper;
24+
25+
/**
26+
* A {@code RepositoryRestConfigurer} that applies our configuration to Spring Data REST.
27+
* Specifically, if a {@link Jackson2ObjectMapperBuilder} is available, it is used to
28+
* configure Spring Data REST's {@link ObjectMapper ObjectMappers}.
29+
*
30+
* @author Andy Wilkinson
31+
*/
32+
class SpringBootRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
33+
34+
@Autowired(required = false)
35+
private Jackson2ObjectMapperBuilder objectMapperBuilder;
36+
37+
@Override
38+
public void configureJacksonObjectMapper(ObjectMapper objectMapper) {
39+
if (this.objectMapperBuilder != null) {
40+
this.objectMapperBuilder.configure(objectMapper);
41+
}
42+
}
43+
44+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestMvcConfiguration.java

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,22 @@
1616

1717
package org.springframework.boot.autoconfigure.data.rest;
1818

19-
import org.springframework.beans.factory.annotation.Autowired;
2019
import org.springframework.boot.context.properties.ConfigurationProperties;
2120
import org.springframework.context.annotation.Bean;
2221
import org.springframework.context.annotation.Configuration;
2322
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
2423
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
25-
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
26-
27-
import com.fasterxml.jackson.databind.ObjectMapper;
2824

2925
/**
3026
* A specialized {@link RepositoryRestMvcConfiguration} that applies configuration items
31-
* from the {@code spring.data.rest} namespace. Also configures Jackson if it's available
27+
* from the {@code spring.data.rest} namespace.
3228
* <p>
33-
* Favor an extension of this class instead of extending directly from
34-
* {@link RepositoryRestMvcConfiguration}.
3529
*
3630
* @author Stephane Nicoll
3731
* @since 1.2.2
3832
*/
3933
@Configuration
40-
public class SpringBootRepositoryRestMvcConfiguration extends
41-
RepositoryRestMvcConfiguration {
42-
43-
@Autowired(required = false)
44-
private Jackson2ObjectMapperBuilder objectMapperBuilder;
34+
class SpringBootRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
4535

4636
@Bean
4737
@ConfigurationProperties(prefix = "spring.data.rest")
@@ -50,11 +40,4 @@ public RepositoryRestConfiguration config() {
5040
return super.config();
5141
}
5242

53-
@Override
54-
protected void configureJacksonObjectMapper(ObjectMapper objectMapper) {
55-
if (this.objectMapperBuilder != null) {
56-
this.objectMapperBuilder.configure(objectMapper);
57-
}
58-
}
59-
6043
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,6 @@ public void backOffWithCustomConfiguration() {
9191
bean.getBaseUri());
9292
}
9393

94-
@Test
95-
public void propertiesStillAppliedWithCustomBootConfig() {
96-
load(TestConfigurationWithRestMvcBootConfig.class,
97-
"spring.data.rest.base-path:foo");
98-
assertNotNull(this.context.getBean(RepositoryRestMvcConfiguration.class));
99-
RepositoryRestConfiguration bean = this.context
100-
.getBean(RepositoryRestConfiguration.class);
101-
assertEquals("Custom base URI should have been set", URI.create("/foo"),
102-
bean.getBaseUri());
103-
}
104-
10594
@Test
10695
public void objectMappersAreConfiguredUsingObjectMapperBuilder()
10796
throws JsonProcessingException {
@@ -144,11 +133,6 @@ protected static class TestConfigurationWithRestMvcConfig {
144133

145134
}
146135

147-
@Import({ TestConfiguration.class, SpringBootRepositoryRestMvcConfiguration.class })
148-
protected static class TestConfigurationWithRestMvcBootConfig {
149-
150-
}
151-
152136
@Configuration
153137
@TestAutoConfigurationPackage(City.class)
154138
@EnableWebMvc

spring-boot-docs/src/main/asciidoc/howto.adoc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,15 +1476,16 @@ respectively.
14761476

14771477
[[howto-use-exposing-spring-data-repositories-rest-endpoint]]
14781478
=== Expose Spring Data repositories as REST endpoint
1479+
14791480
Spring Data REST can expose the `Repository` implementations as REST endpoints for you as
14801481
long as Spring MVC has been enabled for the application.
14811482

14821483
Spring Boot exposes as set of useful properties from the `spring.data.rest` namespace that
1483-
customize the {spring-data-rest-javadoc}/core/config/RepositoryRestConfiguration.{dc-ext}[`RepositoryRestConfiguration`].
1484-
If you need to provide additional customization, you can create a `@Configuration` class
1485-
that extends `SpringBootRepositoryRestMvcConfiguration`. This class supports the same
1486-
functionality as `RepositoryRestMvcConfiguration`, but allows you to continue using
1487-
`spring.data.rest.*` properties.
1484+
customize the
1485+
{spring-data-rest-javadoc}/core/config/RepositoryRestConfiguration.{dc-ext}[`RepositoryRestConfiguration`].
1486+
If you need to provide additional customization, you should use a
1487+
{spring-data-rest-javadoc}/core/config/RepositoryRestConfigurer.{dc-ext}[`RepositoryRestConfigurer`]
1488+
bean.
14881489

14891490

14901491

0 commit comments

Comments
 (0)