Skip to content

Commit 2aca2b2

Browse files
committed
Avoid reflection in RepositoryRestMvcConfiguration.
We now completely avoid reflection in RepositoryRestMvcConfiguration by delaying all bean lookups that were previously declared through autowired fields. Fixes #2057.
1 parent 9cd9e1c commit 2aca2b2

File tree

1 file changed

+59
-41
lines changed

1 file changed

+59
-41
lines changed

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

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.springframework.beans.factory.BeanFactoryUtils;
3030
import org.springframework.beans.factory.ObjectFactory;
3131
import org.springframework.beans.factory.ObjectProvider;
32-
import org.springframework.beans.factory.annotation.Autowired;
3332
import org.springframework.beans.factory.annotation.Qualifier;
3433
import org.springframework.context.ApplicationContext;
3534
import org.springframework.context.annotation.Bean;
@@ -89,6 +88,7 @@
8988
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
9089
import org.springframework.data.util.AnnotatedTypeScanner;
9190
import org.springframework.data.util.Lazy;
91+
import org.springframework.data.util.StreamUtils;
9292
import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver;
9393
import org.springframework.data.web.HateoasSortHandlerMethodArgumentResolver;
9494
import org.springframework.data.web.config.EnableSpringDataWebSupport;
@@ -156,48 +156,43 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
156156
private static final boolean IS_JPA_AVAILABLE = ClassUtils.isPresent("javax.persistence.EntityManager",
157157
RepositoryRestMvcConfiguration.class.getClassLoader());
158158

159-
@Autowired ApplicationContext applicationContext;
159+
private final ApplicationContext applicationContext;
160+
private final ConversionService defaultConversionService;
160161

161-
@Autowired(required = false) List<EntityLookup<?>> lookups = Collections.emptyList();
162-
163-
@Autowired List<HttpMessageConverter<?>> defaultMessageConverters;
164-
165-
ObjectProvider<LinkRelationProvider> relProvider;
166-
ObjectProvider<CurieProvider> curieProvider;
167-
ObjectProvider<HalConfiguration> halConfiguration;
168-
ObjectProvider<ObjectMapper> objectMapper;
169-
ObjectProvider<RepresentationModelProcessorInvoker> invoker;
170-
ObjectProvider<MessageResolver> resolver;
171-
ObjectProvider<GeoModule> geoModule;
172-
ObjectProvider<AuditableBeanWrapperFactory> auditingBeanWrapperFactoryProvider;
173-
174-
ConversionService defaultConversionService;
162+
private final ObjectProvider<LinkRelationProvider> relProvider;
163+
private final ObjectProvider<CurieProvider> curieProvider;
164+
private final ObjectProvider<HalConfiguration> halConfiguration;
165+
private final ObjectProvider<ObjectMapper> objectMapper;
166+
private final ObjectProvider<RepresentationModelProcessorInvoker> invoker;
167+
private final ObjectProvider<MessageResolver> resolver;
168+
private final ObjectProvider<GeoModule> geoModule;
169+
private final ObjectProvider<PathPatternParser> parser;
175170

176171
private final Lazy<ObjectMapper> mapper;
177-
private final ObjectProvider<PathPatternParser> parser;
172+
private final Lazy<? extends List<EntityLookup<?>>> lookups;
173+
private final Lazy<? extends List<HttpMessageConverter<?>>> defaultMessageConverters;
174+
private final Lazy<RepositoryRestConfigurerDelegate> configurerDelegate;
175+
private final Lazy<SelfLinkProvider> selfLinkProvider;
176+
private final Lazy<PersistentEntityResourceHandlerMethodArgumentResolver> persistentEntityArgumentResolver;
177+
private final Lazy<RootResourceInformationHandlerMethodArgumentResolver> repoRequestArgumentResolver;
178+
private final Lazy<BaseUri> baseUri;
179+
private final Lazy<RepositoryResourceMappings> resourceMappings;
180+
private final Lazy<Repositories> repositories;
181+
private final Lazy<ResourceMetadataHandlerMethodArgumentResolver> resourceMetadataHandlerMethodArgumentResolver;
182+
private final Lazy<ExcerptProjector> excerptProjector;
183+
private final Lazy<PersistentEntities> persistentEntities;
184+
private final Lazy<BackendIdHandlerMethodArgumentResolver> backendIdHandlerMethodArgumentResolver;
185+
private final Lazy<Associations> associationLinks;
186+
private final Lazy<EnumTranslator> enumTranslator;
187+
private final Lazy<ServerHttpRequestMethodArgumentResolver> serverHttpRequestMethodArgumentResolver;
188+
private final Lazy<ETagArgumentResolver> eTagArgumentResolver;
189+
private final Lazy<RepositoryInvokerFactory> repositoryInvokerFactory;
190+
private final Lazy<RepositoryRestConfiguration> repositoryRestConfiguration;
191+
private final Lazy<HateoasPageableHandlerMethodArgumentResolver> pageableResolver;
192+
private final Lazy<HateoasSortHandlerMethodArgumentResolver> sortResolver;
178193

179194
private ClassLoader beanClassLoader;
180195

181-
private Lazy<RepositoryRestConfigurerDelegate> configurerDelegate;
182-
private Lazy<SelfLinkProvider> selfLinkProvider;
183-
private Lazy<PersistentEntityResourceHandlerMethodArgumentResolver> persistentEntityArgumentResolver;
184-
private Lazy<RootResourceInformationHandlerMethodArgumentResolver> repoRequestArgumentResolver;
185-
private Lazy<BaseUri> baseUri;
186-
private Lazy<RepositoryResourceMappings> resourceMappings;
187-
private Lazy<Repositories> repositories;
188-
private Lazy<ResourceMetadataHandlerMethodArgumentResolver> resourceMetadataHandlerMethodArgumentResolver;
189-
private Lazy<ExcerptProjector> excerptProjector;
190-
private Lazy<PersistentEntities> persistentEntities;
191-
private Lazy<BackendIdHandlerMethodArgumentResolver> backendIdHandlerMethodArgumentResolver;
192-
private Lazy<Associations> associationLinks;
193-
private Lazy<EnumTranslator> enumTranslator;
194-
private Lazy<ServerHttpRequestMethodArgumentResolver> serverHttpRequestMethodArgumentResolver;
195-
private Lazy<ETagArgumentResolver> eTagArgumentResolver;
196-
private Lazy<RepositoryInvokerFactory> repositoryInvokerFactory;
197-
private Lazy<RepositoryRestConfiguration> repositoryRestConfiguration;
198-
private Lazy<HateoasPageableHandlerMethodArgumentResolver> pageableResolver;
199-
private Lazy<HateoasSortHandlerMethodArgumentResolver> sortResolver;
200-
201196
public RepositoryRestMvcConfiguration( //
202197
ApplicationContext context, //
203198
@Qualifier("mvcConversionService") ObjectFactory<ConversionService> conversionService, //
@@ -212,6 +207,7 @@ public RepositoryRestMvcConfiguration( //
212207

213208
super(context, conversionService);
214209

210+
this.applicationContext = context;
215211
this.relProvider = relProvider;
216212
this.curieProvider = curieProvider;
217213
this.halConfiguration = halConfiguration;
@@ -220,6 +216,7 @@ public RepositoryRestMvcConfiguration( //
220216
this.resolver = resolver;
221217
this.geoModule = geoModule;
222218
this.parser = parser;
219+
this.defaultConversionService = new DefaultFormattingConversionService();
223220

224221
this.mapper = Lazy.of(() -> {
225222

@@ -255,11 +252,10 @@ public RepositoryRestMvcConfiguration( //
255252
this.serverHttpRequestMethodArgumentResolver = Lazy
256253
.of(() -> context.getBean(ServerHttpRequestMethodArgumentResolver.class));
257254
this.eTagArgumentResolver = Lazy.of(() -> context.getBean(ETagArgumentResolver.class));
255+
258256
this.repositoryInvokerFactory = Lazy.of(() -> new UnwrappingRepositoryInvokerFactory(
259257
new DefaultRepositoryInvokerFactory(repositories.get(), defaultConversionService), getEntityLookups()));
260258

261-
this.defaultConversionService = new DefaultFormattingConversionService();
262-
263259
this.configurerDelegate = Lazy.of(() -> {
264260

265261
return new RepositoryRestConfigurerDelegate(context.getBeanProvider(RepositoryRestConfigurer.class)
@@ -270,6 +266,11 @@ public RepositoryRestMvcConfiguration( //
270266
this.repositoryRestConfiguration = Lazy.of(() -> context.getBean(RepositoryRestConfiguration.class));
271267
this.pageableResolver = Lazy.of(() -> context.getBean(HateoasPageableHandlerMethodArgumentResolver.class));
272268
this.sortResolver = Lazy.of(() -> context.getBean(HateoasSortHandlerMethodArgumentResolver.class));
269+
270+
// Resolution via ResolvableType needed to make the wildcard assignment work
271+
272+
this.lookups = beansOfType(context, EntityLookup.class);
273+
this.defaultMessageConverters = beansOfType(context, HttpMessageConverter.class);
273274
}
274275

275276
/*
@@ -751,7 +752,7 @@ public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> excep
751752
ExceptionHandlerExceptionResolver er = new ExceptionHandlerExceptionResolver();
752753
er.setCustomArgumentResolvers(defaultMethodArgumentResolvers(selfLinkProvider.get(),
753754
persistentEntityArgumentResolver.get(), repoRequestArgumentResolver.get()));
754-
er.setMessageConverters(defaultMessageConverters);
755+
er.setMessageConverters(defaultMessageConverters.get());
755756

756757
configurerDelegate.get().configureExceptionHandlerExceptionResolver(er);
757758

@@ -886,7 +887,7 @@ protected List<EntityLookup<?>> getEntityLookups() {
886887

887888
List<EntityLookup<?>> lookups = new ArrayList<>();
888889
lookups.addAll(repositoryRestConfiguration.get().getEntityLookups(repositories.get()));
889-
lookups.addAll(this.lookups);
890+
lookups.addAll(this.lookups.get());
890891

891892
return lookups;
892893
}
@@ -997,6 +998,23 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
997998
.forEach(it -> it.customizeResources(registry, repositoryRestConfiguration.get()));
998999
}
9991000

1001+
/**
1002+
* Helper to be able to obtain a {@link List} of generic types. Otherwise the assignment from {@code Foo} to
1003+
* {@code Foo<?>} doesn't work.
1004+
*
1005+
* @param <S>
1006+
* @param context
1007+
* @param type
1008+
* @return
1009+
*/
1010+
@SuppressWarnings("unchecked")
1011+
private static <S> Lazy<List<S>> beansOfType(ApplicationContext context, Class<?> type) {
1012+
1013+
return Lazy.of(() -> (List<S>) context.getBeanProvider(type)
1014+
.orderedStream()
1015+
.collect(StreamUtils.toUnmodifiableList()));
1016+
}
1017+
10001018
private static class ResourceSupportHttpMessageConverter extends TypeConstrainedMappingJackson2HttpMessageConverter
10011019
implements Ordered {
10021020

0 commit comments

Comments
 (0)