From a247b83cd9c9aefd3c329d493c5ce7cd11d0cdfa Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Wed, 22 Sep 2021 16:22:27 +0200 Subject: [PATCH] Ensure projects can be imported into Eclipse IDE with JDK 17 Prior to this commit, the Spring Framework projects could not be imported into Eclipse IDE when using JDK 17 to build the projects. The primary obstacle is the fact that Eclipse enforces a strict "no split packages between the unnamed module and a system module" rule when building with a "modular JDK" (such as JDK 17). Resources: - https://bugs.eclipse.org/bugs/show_bug.cgi?id=536928 - https://bugs.openjdk.java.net/browse/JDK-8215739 - http://mail.openjdk.java.net/pipermail/jigsaw-dev/2018-December/014077.html - https://stackoverflow.com/questions/51094274/eclipse-cant-find-xml-related-classes-after-switching-build-path-to-jdk-10/53824670#53824670 Since the bug (JDK-8215739) has not been fixed in OpenJDK, the strict "no split packages" rule does not apply to the Java compiler used in Spring Framework's Gradle build or the compiler in IntelliJ IDEA. Hence, this issue only arrises when building the framework in Eclipse IDE. This commit addresses this issue in the following affected projects. - spring-oxm: removal of the dependency on XPP3 which publishes javax.xml.namespace.QName as part of the JAR. The QName type is also published by the java.xml JDK 17 system module. To make the tests pass, we have switched to using the DomDriver instead of the XppDriver in our XStream tests. - spring-test: HtmlUnit has a transitive dependency on xml-apis which publishes several packages also published by java.xml JDK 17 system module. Thus, we have explicitly excluded the transitive dependency on xml-apis for our `optional` configuration. See gh-27407 --- gradle/ide.gradle | 4 ++-- import-into-eclipse.md | 6 +++++- spring-oxm/spring-oxm.gradle | 1 - .../oxm/xstream/XStreamMarshallerTests.java | 15 +++++++++------ .../oxm/xstream/XStreamUnmarshallerTests.java | 3 +++ spring-test/spring-test.gradle | 9 +++++++++ 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/gradle/ide.gradle b/gradle/ide.gradle index d5215f2875f..9d3db102381 100644 --- a/gradle/ide.gradle +++ b/gradle/ide.gradle @@ -4,8 +4,8 @@ import org.gradle.plugins.ide.eclipse.model.SourceFolder apply plugin: 'eclipse' eclipse.jdt { - sourceCompatibility = 1.8 - targetCompatibility = 1.8 + sourceCompatibility = 17 + targetCompatibility = 17 } // Replace classpath entries with project dependencies (GRADLE-1116) diff --git a/import-into-eclipse.md b/import-into-eclipse.md index fc3d36a8854..1ab36c1fcfd 100644 --- a/import-into-eclipse.md +++ b/import-into-eclipse.md @@ -3,7 +3,7 @@ This document will guide you through the process of importing the Spring Framework projects into Eclipse or the Spring Tool Suite (_STS_). It is recommended that you have a recent version of Eclipse. As a bare minimum you will need Eclipse with full Java -8 support, Eclipse Buildship, and the Groovy plugin. +17 support, Eclipse Buildship, and the Groovy plugin. The following instructions have been tested against [STS](https://spring.io/tools) 4.12.0 ([download](https://github.com/spring-projects/sts4/wiki/Previous-Versions#spring-tools-4120-changelog)) @@ -12,6 +12,10 @@ The instructions should work with the latest Eclipse distribution as long as you [Buildship](https://marketplace.eclipse.org/content/buildship-gradle-integration). Note that STS 4 comes with Buildship preinstalled. +If you are using Eclipse 4.21, you will need to install +[Java 17 Support for Eclipse 2021-09 (4.21)](https://marketplace.eclipse.org/content/java-17-support-eclipse-2021-09-421) +from the Eclipse Marketplace. + ## Steps _When instructed to execute `./gradlew` from the command line, be sure to execute it within your locally cloned `spring-framework` working directory._ diff --git a/spring-oxm/spring-oxm.gradle b/spring-oxm/spring-oxm.gradle index bce9c151769..0778059690c 100644 --- a/spring-oxm/spring-oxm.gradle +++ b/spring-oxm/spring-oxm.gradle @@ -22,7 +22,6 @@ dependencies { optional("com.thoughtworks.xstream:xstream") testImplementation(project(":spring-context")) testImplementation(testFixtures(project(":spring-core"))) - testImplementation("org.ogce:xpp3") testImplementation("org.codehaus.jettison:jettison") { exclude group: "stax", module: "stax-api" } diff --git a/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java b/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java index 304d3fcc771..ece6236ecd7 100644 --- a/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java +++ b/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamMarshallerTests.java @@ -43,6 +43,8 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver; import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver; import com.thoughtworks.xstream.io.json.JsonWriter; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; import com.thoughtworks.xstream.security.AnyTypePermission; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -84,6 +86,7 @@ class XStreamMarshallerTests { marshaller = new XStreamMarshaller(); marshaller.setTypePermissions(AnyTypePermission.ANY); marshaller.setAliases(Collections.singletonMap("flight", Flight.class.getName())); + marshaller.setStreamDriver(new DomDriver("UTF-8", new XmlFriendlyNameCoder())); flight.setFlightNumber(42L); } @@ -139,7 +142,7 @@ class XStreamMarshallerTests { StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); marshaller.marshal(flight, result); - assertThat(XmlContent.from(writer)).isSimilarTo(EXPECTED_STRING); + assertThat(XmlContent.from(writer)).isSimilarToIgnoringWhitespace(EXPECTED_STRING); } @Test @@ -148,7 +151,7 @@ class XStreamMarshallerTests { StreamResult result = new StreamResult(os); marshaller.marshal(flight, result); String s = os.toString("UTF-8"); - assertThat(XmlContent.of(s)).isSimilarTo(EXPECTED_STRING); + assertThat(XmlContent.of(s)).isSimilarToIgnoringWhitespace(EXPECTED_STRING); } @Test @@ -254,7 +257,7 @@ class XStreamMarshallerTests { Writer writer = new StringWriter(); marshaller.marshal(flight, new StreamResult(writer)); - assertThat(XmlContent.from(writer)).isSimilarTo(EXPECTED_STRING); + assertThat(XmlContent.from(writer)).isSimilarToIgnoringWhitespace(EXPECTED_STRING); } @Test @@ -267,7 +270,7 @@ class XStreamMarshallerTests { Writer writer = new StringWriter(); marshaller.marshal(flight, new StreamResult(writer)); - assertThat(XmlContent.from(writer)).isSimilarTo(EXPECTED_STRING); + assertThat(XmlContent.from(writer)).isSimilarToIgnoringWhitespace(EXPECTED_STRING); } @Test @@ -276,7 +279,7 @@ class XStreamMarshallerTests { Writer writer = new StringWriter(); marshaller.marshal(flight, new StreamResult(writer)); String expected = "42"; - assertThat(XmlContent.from(writer)).isSimilarTo(expected); + assertThat(XmlContent.from(writer)).isSimilarToIgnoringWhitespace(expected); } @Test @@ -351,7 +354,7 @@ class XStreamMarshallerTests { flight.setFlightNumber(42); marshaller.marshal(flight, result); String expected = "42"; - assertThat(XmlContent.from(writer)).isSimilarTo(expected); + assertThat(XmlContent.from(writer)).isSimilarToIgnoringWhitespace(expected); } diff --git a/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTests.java b/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTests.java index 7c87eda2253..9d8d61b7bea 100644 --- a/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTests.java +++ b/spring-oxm/src/test/java/org/springframework/oxm/xstream/XStreamUnmarshallerTests.java @@ -30,6 +30,8 @@ import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder; import com.thoughtworks.xstream.security.AnyTypePermission; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -55,6 +57,7 @@ public class XStreamUnmarshallerTests { public void createUnmarshaller() { unmarshaller = new XStreamMarshaller(); unmarshaller.setTypePermissions(AnyTypePermission.ANY); + unmarshaller.setStreamDriver(new DomDriver("UTF-8", new XmlFriendlyNameCoder())); Map> aliases = new HashMap<>(); aliases.put("flight", Flight.class); unmarshaller.setAliases(aliases); diff --git a/spring-test/spring-test.gradle b/spring-test/spring-test.gradle index ea64eb6f276..1cb742f451a 100644 --- a/spring-test/spring-test.gradle +++ b/spring-test/spring-test.gradle @@ -79,6 +79,15 @@ dependencies { testRuntimeOnly("com.sun.xml.bind:jaxb-impl") } +// Prevent xml-apis from being used so that the corresponding XML APIs from +// the JDK's `java.xml` module are used instead. This allows spring-test to +// build in Eclipse IDE which fails to compile if there is a split package +// between a JDK system module and the unnamed module (for JARs on the +// classpath). +configurations.optional { + exclude group: "xml-apis", module: "xml-apis" +} + test { description = "Runs JUnit 4, JUnit Jupiter, and TestNG tests." useJUnitPlatform {