#1831 - Reset dummy invocation cache on request completion.
This commit is contained in:
@@ -19,6 +19,9 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
@@ -26,6 +29,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.hateoas.server.RepresentationModelProcessor;
|
||||
import org.springframework.hateoas.server.core.DummyInvocationUtils;
|
||||
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorHandlerMethodReturnValueHandler;
|
||||
import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoker;
|
||||
import org.springframework.hateoas.server.mvc.UriComponentsContributor;
|
||||
@@ -33,6 +37,8 @@ import org.springframework.hateoas.server.mvc.WebMvcLinkBuilderFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
|
||||
@@ -93,6 +99,15 @@ class WebMvcHateoasConfiguration {
|
||||
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
hypermediaConverters.augmentServer(converters);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurer#addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry)
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(DummyInvocationUtilsCacheClearer.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,4 +147,25 @@ class WebMvcHateoasConfiguration {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link HandlerInterceptor} to clear the cache in {@link DummyInvocationUtils}.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
enum DummyInvocationUtilsCacheClearer implements HandlerInterceptor {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
|
||||
*/
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
|
||||
throws Exception {
|
||||
|
||||
DummyInvocationUtils.resetCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +180,10 @@ public class DummyInvocationUtils {
|
||||
return new DefaultMethodInvocation(type, method, parameters);
|
||||
}
|
||||
|
||||
public static void resetCache() {
|
||||
CACHE.remove();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T getProxyWithInterceptor(Class<?> type, InvocationRecordingMethodInterceptor interceptor,
|
||||
ClassLoader classLoader) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
|
||||
import org.springframework.hateoas.mediatype.hal.forms.Jackson2HalFormsModule;
|
||||
import org.springframework.hateoas.mediatype.uber.Jackson2UberModule;
|
||||
import org.springframework.hateoas.server.SimpleRepresentationModelAssembler;
|
||||
import org.springframework.hateoas.server.core.DummyInvocationUtils;
|
||||
import org.springframework.hateoas.support.Employee;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -51,7 +52,9 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.util.ConcurrentLruCache;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -263,6 +266,20 @@ class HypermediaWebMvcConfigurerTest {
|
||||
.andExpect(status().isIAmATeapot());
|
||||
}
|
||||
|
||||
@Test // #1831
|
||||
void wipesDummyInvocationsCachePerRequest() throws Exception {
|
||||
|
||||
setUp(HalWebMvcConfig.class);
|
||||
|
||||
this.mockMvc.perform(get("/dynamicLink"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
ThreadLocal<ConcurrentLruCache<?, ?>> cache = (ThreadLocal<ConcurrentLruCache<?, ?>>) ReflectionTestUtils.getField(
|
||||
null, DummyInvocationUtils.class, "CACHE");
|
||||
|
||||
assertThat(cache.get().size()).isZero();
|
||||
}
|
||||
|
||||
private void verifyRootUriServesHypermedia(MediaType mediaType) throws Exception {
|
||||
verifyRootUriServesHypermedia(mediaType, mediaType);
|
||||
}
|
||||
@@ -468,6 +485,12 @@ class HypermediaWebMvcConfigurerTest {
|
||||
|
||||
return this.assembler.toModel(newEmployee);
|
||||
}
|
||||
|
||||
@GetMapping("/dynamicLink")
|
||||
EntityModel<Employee> dynamicLink() {
|
||||
return EntityModel.of(employees.get(0)) //
|
||||
.add(linkTo(methodOn(TestController.class).employee("1")).withSelfRel());
|
||||
}
|
||||
}
|
||||
|
||||
static class EmployeeResourceAssembler implements SimpleRepresentationModelAssembler<Employee> {
|
||||
|
||||
Reference in New Issue
Block a user