From 21a5ab7875e8b250d1839c5e9e45366359b93ca5 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 6 Jun 2017 21:35:33 +0100 Subject: [PATCH] Log a warning during tests when multiple JSONOjects on the class path Closes gh-9248 --- spring-boot-test/pom.xml | 15 ++++ ...ateJsonObjectContextCustomizerFactory.java | 90 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + ...onObjectContextCustomizerFactoryTests.java | 49 ++++++++++ 4 files changed, 155 insertions(+) create mode 100644 spring-boot-test/src/main/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactory.java create mode 100644 spring-boot-test/src/test/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactoryTests.java diff --git a/spring-boot-test/pom.xml b/spring-boot-test/pom.xml index 65634ee91b..127e7490d6 100644 --- a/spring-boot-test/pom.xml +++ b/spring-boot-test/pom.xml @@ -117,6 +117,11 @@ spring-boot-test-support test + + ch.qos.logback + logback-classic + test + org.apache.tomcat.embed tomcat-embed-core @@ -138,6 +143,16 @@ kotlin-runtime test + + org.slf4j + jcl-over-slf4j + test + + + org.slf4j + slf4j-api + test + org.spockframework spock-core diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactory.java b/spring-boot-test/src/main/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactory.java new file mode 100644 index 0000000000..d3846ab240 --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactory.java @@ -0,0 +1,90 @@ +/* + * 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.test.json; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.test.context.ContextConfigurationAttributes; +import org.springframework.test.context.ContextCustomizer; +import org.springframework.test.context.ContextCustomizerFactory; +import org.springframework.test.context.MergedContextConfiguration; + +/** + * A {@link ContextCustomizerFactory} that produces a {@link ContextCustomizer} that warns + * the user when multiple occurrences of {@code JSONObject} are found on the class path. + * + * @author Andy Wilkinson + */ +class DuplicateJsonObjectContextCustomizerFactory implements ContextCustomizerFactory { + + @Override + public ContextCustomizer createContextCustomizer(Class testClass, + List configAttributes) { + return new DuplicateJsonObjectContextCustomizer(); + } + + private static class DuplicateJsonObjectContextCustomizer + implements ContextCustomizer { + + private final Log logger = LogFactory + .getLog(DuplicateJsonObjectContextCustomizer.class); + + @Override + public void customizeContext(ConfigurableApplicationContext context, + MergedContextConfiguration mergedConfig) { + List jsonObjects = findJsonObjects(); + if (jsonObjects.size() > 1) { + logDuplicateJsonObjectsWarning(jsonObjects); + } + } + + private List findJsonObjects() { + List jsonObjects = new ArrayList(); + try { + Enumeration resources = getClass().getClassLoader() + .getResources("org/json/JSONObject.class"); + while (resources.hasMoreElements()) { + jsonObjects.add(resources.nextElement()); + } + } + catch (Exception ex) { + // Continue + } + return jsonObjects; + } + + private void logDuplicateJsonObjectsWarning(List jsonObjects) { + StringBuilder message = new StringBuilder("\n\nFound multiple occurrences of" + + " org.json.JSONObject on the class path:\n\n"); + for (URL jsonObject : jsonObjects) { + message.append("\t" + jsonObject + "\n"); + } + message.append("\nYou may wish to exclude one of them to ensure" + + " predictable runtime behaviour\n"); + this.logger.warn(message); + } + + } + +} diff --git a/spring-boot-test/src/main/resources/META-INF/spring.factories b/spring-boot-test/src/main/resources/META-INF/spring.factories index 10c125a43e..f5174a5f61 100644 --- a/spring-boot-test/src/main/resources/META-INF/spring.factories +++ b/spring-boot-test/src/main/resources/META-INF/spring.factories @@ -3,6 +3,7 @@ org.springframework.test.context.ContextCustomizerFactory=\ org.springframework.boot.test.context.ImportsContextCustomizerFactory,\ org.springframework.boot.test.context.SpringBootTestContextCustomizerFactory,\ org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizerFactory,\ +org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory,\ org.springframework.boot.test.mock.mockito.MockitoContextCustomizerFactory # Test Execution Listeners diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactoryTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactoryTests.java new file mode 100644 index 0000000000..53e5f4ed66 --- /dev/null +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactoryTests.java @@ -0,0 +1,49 @@ +/* + * 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.test.json; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.junit.runner.classpath.ClassPathOverrides; +import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner; +import org.springframework.boot.test.rule.OutputCapture; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link DuplicateJsonObjectContextCustomizerFactory}. + * + * @author Andy Wilkinson + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathOverrides("org.json:json:20140107") +public class DuplicateJsonObjectContextCustomizerFactoryTests { + + @Rule + public OutputCapture output = new OutputCapture(); + + @Test + public void warningForMultipleVersions() { + new DuplicateJsonObjectContextCustomizerFactory() + .createContextCustomizer(null, null).customizeContext(null, null); + assertThat(this.output.toString()).contains( + "Found multiple occurrences of org.json.JSONObject on the class path:"); + } + +}