diff --git a/spring-boot-devtools/pom.xml b/spring-boot-devtools/pom.xml
index 838c1af0b03..927b5323b94 100644
--- a/spring-boot-devtools/pom.xml
+++ b/spring-boot-devtools/pom.xml
@@ -127,6 +127,11 @@
spring-websocket
test
+
+ org.springframework.hateoas
+ spring-hateoas
+ test
+
org.apache.tomcat.embed
tomcat-embed-websocket
diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisabler.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisabler.java
index eea57cfdc65..23a2714c9b9 100644
--- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisabler.java
+++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisabler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2015 the original author or authors.
+ * Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,9 @@ import java.lang.reflect.Field;
import javax.annotation.PostConstruct;
-import org.springframework.objenesis.ObjenesisStd;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -35,6 +37,9 @@ import org.springframework.util.ReflectionUtils;
*/
class HateoasObjenesisCacheDisabler {
+ private static final Log logger = LogFactory
+ .getLog(HateoasObjenesisCacheDisabler.class);
+
private static boolean cacheDisabled;
@PostConstruct
@@ -45,20 +50,36 @@ class HateoasObjenesisCacheDisabler {
}
}
- private void doDisableCaching() {
+ void doDisableCaching() {
try {
Class> type = ClassUtils.forName(
"org.springframework.hateoas.core.DummyInvocationUtils",
getClass().getClassLoader());
- Field objenesis = ReflectionUtils.findField(type, "OBJENESIS");
- if (objenesis != null) {
- ReflectionUtils.makeAccessible(objenesis);
- ReflectionUtils.setField(objenesis, null, new ObjenesisStd(false));
- }
+ removeObjenesisCache(type);
}
catch (Exception ex) {
// Assume that Spring HATEOAS is not on the classpath and continue
}
}
+ private void removeObjenesisCache(Class> dummyInvocationUtils) {
+ try {
+ Field objenesisField = ReflectionUtils.findField(dummyInvocationUtils,
+ "OBJENESIS");
+ if (objenesisField != null) {
+ ReflectionUtils.makeAccessible(objenesisField);
+ Object objenesis = ReflectionUtils.getField(objenesisField, null);
+ Field cacheField = ReflectionUtils.findField(objenesis.getClass(),
+ "cache");
+ ReflectionUtils.makeAccessible(cacheField);
+ ReflectionUtils.setField(cacheField, objenesis, null);
+ }
+ }
+ catch (Exception ex) {
+ logger.warn(
+ "Failed to disable Spring HATEOAS's Objenesis cache. ClassCastExceptions may occur",
+ ex);
+ }
+ }
+
}
diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisablerTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisablerTests.java
new file mode 100644
index 00000000000..f0066aa41d4
--- /dev/null
+++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/HateoasObjenesisCacheDisablerTests.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012-2017 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.devtools.autoconfigure;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.hateoas.core.DummyInvocationUtils;
+import org.springframework.objenesis.ObjenesisStd;
+import org.springframework.objenesis.instantiator.ObjectInstantiator;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link HateoasObjenesisCacheDisabler}.
+ *
+ * @author Andy Wilkinson
+ */
+public class HateoasObjenesisCacheDisablerTests {
+
+ private ObjenesisStd objenesis;
+
+ @Before
+ @After
+ public void resetCacheField() {
+ this.objenesis = (ObjenesisStd) ReflectionTestUtils
+ .getField(DummyInvocationUtils.class, "OBJENESIS");
+ ReflectionTestUtils.setField(this.objenesis, "cache",
+ new ConcurrentHashMap>());
+ }
+
+ @Test
+ public void cacheIsEnabledByDefault() {
+ assertThat(this.objenesis.getInstantiatorOf(TestObject.class))
+ .isSameAs(this.objenesis.getInstantiatorOf(TestObject.class));
+ }
+
+ @Test
+ public void cacheIsDisabled() {
+ new HateoasObjenesisCacheDisabler().doDisableCaching();
+ assertThat(this.objenesis.getInstantiatorOf(TestObject.class))
+ .isNotSameAs(this.objenesis.getInstantiatorOf(TestObject.class));
+ }
+
+ private static class TestObject {
+
+ }
+
+}