You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by ya...@apache.org on 2018/11/19 07:05:05 UTC

[struts] branch master updated: [WW-4981] Adds support for JDK11 (#270)

This is an automated email from the ASF dual-hosted git repository.

yasserzamani pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/master by this push:
     new 2a60c1e  [WW-4981] Adds support for JDK11  (#270)
2a60c1e is described below

commit 2a60c1eee69f976a6e20f20add04cdc39b757ead
Author: Lukasz Lenart <lu...@gmail.com>
AuthorDate: Mon Nov 19 08:05:01 2018 +0100

    [WW-4981] Adds support for JDK11  (#270)
    
    * Upgrades test dependencies
    
    * Drops unused lib
    
    * Uses AssertJ instead of FestAssert
    
    * Upgrades Surefire Maven Plugin to 2.22.1
    
    * Downgrades to AssertJ 2.x to support JDK7
    
    * decouple tests from java version
    
    Refactor a java 9 conditional test to work always with any java version
    
    See also WW-4845
    
    * fix NullPointerException in NotURLClassLoader tests
    
    Also includes a few improvements
    
    See also WW-4845
    
    * do not specify threadCount & forkMode which breaks tests in java 9
    
    See also WW-4845
    
    * pass all current tests with java 11
    
    See also WW-4981
    
    * fix an odd path problem in java 9
    
    See also WW-4845
    
    * gitignore test-output
    
    See also WW-4981
    
    * ask travis an oracle jdk 11 build
    
    See also WW-4981
    
    * ask travis to report coverage only in latest working jdk, jdk8
    
    See also WW-4845
---
 .gitignore                                         |   1 +
 .travis.yml                                        |   8 +-
 assembly/src/main/assembly/min-lib.xml             |   3 +-
 core/pom.xml                                       |   6 +-
 .../opensymphony/xwork2/util/ClassPathFinder.java  | 279 ++++++++++-----------
 .../com/opensymphony/xwork2/ognl/OgnlUtilTest.java |  44 ++--
 .../xwork2/util/AnnotationUtilsTest.java           |   2 +-
 .../xwork2/util/ClassPathFinderTest.java           |  15 +-
 .../xwork2/util/fs/JarEntryRevisionTest.java       |  22 +-
 .../test/java/org/apache/struts2/TestUtils.java    |  16 --
 .../conversion/UploadedFileConverterTest.java      |   2 +-
 .../FreemarkerThemeTemplateLoaderTest.java         |   9 +-
 plugins/bean-validation/pom.xml                    |  31 +++
 .../org/apache/struts2/EmbeddedJSPResultTest.java  |  12 +-
 plugins/json/pom.xml                               |   4 +-
 .../json/JSONValidationInterceptorTest.java        |   2 +-
 plugins/rest/pom.xml                               |   4 +-
 .../rest/handler/JacksonXmlHandlerTest.java        |   2 +-
 pom.xml                                            |  19 +-
 19 files changed, 252 insertions(+), 229 deletions(-)

diff --git a/.gitignore b/.gitignore
index 76e68ef..025e545 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,3 +63,4 @@ bundles/target
 plugins/target
 target
 plugins/testng/test-output
+test-output
diff --git a/.travis.yml b/.travis.yml
index 8d98574..5ba7076 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,12 +5,18 @@ jdk:
   - openjdk7
   - oraclejdk8
   - oraclejdk9
+  - oraclejdk11
 
 install: true
 script: mvn test -DskipAssembly
 
 after_success:
-  - mvn clean cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly
+  # TODO delete following if statement after fix of https://github.com/cobertura/cobertura/issues/271
+  - if [ "$TRAVIS_JDK_VERSION" == "openjdk8" ] || [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ]; then
+      mvn clean cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly
+    else
+      echo "Not reporting coverage for $TRAVIS_JDK_VERSION due to incomatibility or to save performance";
+    fi
 
 env:
   global:
diff --git a/assembly/src/main/assembly/min-lib.xml b/assembly/src/main/assembly/min-lib.xml
index a1cafea..3e6e4a1 100644
--- a/assembly/src/main/assembly/min-lib.xml
+++ b/assembly/src/main/assembly/min-lib.xml
@@ -38,9 +38,8 @@
         <include>org.apache.commons:commons-lang3</include>
         <include>org.apache.logging.log4j:log4j-api</include>
         <include>ognl:ognl</include>
-        <include>org.javassist:javassist</include>
         <include>commons-fileupload:commons-fileupload</include>
-        <include>commons-io:commons-io</include>
+        <include>org.apache.commons:commons-io</include>
       </includes>
     </dependencySet>
   </dependencySets>
diff --git a/core/pom.xml b/core/pom.xml
index 631da0f..f5e0dac 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -339,13 +339,13 @@
 
         <dependency>
             <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
+            <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
 
         <dependency>
-            <groupId>org.easytesting</groupId>
-            <artifactId>fest-assert</artifactId>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
             <scope>test</scope>
         </dependency>
 
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/ClassPathFinder.java b/core/src/main/java/com/opensymphony/xwork2/util/ClassPathFinder.java
index 5838abd..8cb69cb 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/ClassPathFinder.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/ClassPathFinder.java
@@ -36,158 +36,153 @@ import java.util.zip.ZipInputStream;
 /**
  * This class is an utility class that will search through the classpath
  * for files whose names match the given pattern. The filename is tested
- * using the given implementation of {@link com.opensymphony.xwork2.util.PatternMatcher} by default it 
+ * using the given implementation of {@link com.opensymphony.xwork2.util.PatternMatcher} by default it
  * uses {@link com.opensymphony.xwork2.util.WildcardHelper}
  */
 public class ClassPathFinder {
-	
-	/**
+
+    /**
      * The String pattern to test against.
      */
-	private String pattern ;
-	
-	private int[] compiledPattern ;
-	
-	/**
+    private String pattern;
+
+    private int[] compiledPattern;
+
+    /**
      * The PatternMatcher implementation to use
      */
-	private PatternMatcher<int[]> patternMatcher = new WildcardHelper();
-
-	private Vector<String> compared = new Vector<>();
-	
-	/**
-	 * @return the pattern in use
-	 */
-	public String getPattern() {
-		return pattern;
-	}
-
-	/**
-	 * @param pattern the String pattern for comparing filenames
-	 */
-	public void setPattern(String pattern) {
-		this.pattern = pattern;
-	}
-
-	/**
+    private PatternMatcher<int[]> patternMatcher = new WildcardHelper();
+
+    private Vector<String> compared = new Vector<>();
+
+    /**
+     * @return the pattern in use
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * @param pattern the String pattern for comparing filenames
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
      * Builds a {@link java.util.Vector} containing Strings which each name a file
-     * who's name matches the pattern set by setPattern(String). The classpath is 
+     * who's name matches the pattern set by setPattern(String). The classpath is
      * searched recursively, so use with caution.
      *
      * @return Vector&lt;String&gt; containing matching filenames
      */
-	public Vector<String> findMatches() {
-		Vector<String> matches = new Vector<>();
-		URL[] parentUrls = getClassLoaderURLs();
-		compiledPattern = patternMatcher.compilePattern(pattern);
-		for (URL url : parentUrls) {
-			if (!"file".equals(url.getProtocol())) {
-				continue ;
-			}
-			URI entryURI ;
-			try {
-				entryURI = url.toURI();
-			} catch (URISyntaxException e) {
-				continue;
-			}
-			File entry = new File(entryURI);
-			if (entry.isFile() && entry.toString().endsWith(".jar")) {
-				try {
-					ZipInputStream zip = new ZipInputStream(new FileInputStream(entry));
-					for (ZipEntry zipEntry = zip.getNextEntry(); zipEntry != null; zipEntry = zip.getNextEntry()) {
-						boolean doesMatch = patternMatcher.match(new HashMap<String, String>(), zipEntry.getName(), compiledPattern);
-						if (doesMatch) {
-							matches.add(zipEntry.getName());
-						}
-					}
-				} catch (IOException e) {
-					e.printStackTrace();
-				}
-			} else {
-				Vector<String> results = checkEntries(entry.list(), entry, "");
-				if (results != null) {
-					matches.addAll(results);
-				}
-			}
-		}
-		return matches;
-	}
-	
-	private Vector<String> checkEntries(String[] entries, File parent, String prefix) {
-		
-		if (entries == null ) {
-			return null;
-		}
-
-		Vector<String> matches = new Vector<>();
-		for (String listEntry : entries) {
-			File tempFile ;
-			if (!"".equals(prefix) ) {
-				tempFile = new File(parent, prefix + "/" + listEntry);
-			}
-			else {
-				tempFile = new File(parent, listEntry);
-			}
-			if (tempFile.isDirectory() && 
-					!(".".equals(listEntry) || "..".equals(listEntry)) ) {
-				if	(!"".equals(prefix) ) {
-					matches.addAll(checkEntries(tempFile.list(), parent, prefix + "/" + listEntry));
-				}
-				else {
-					matches.addAll(checkEntries(tempFile.list(), parent, listEntry));
-				}
-			}
-			else {
-				
-				String entryToCheck ;
-				if ("".equals(prefix)) {
-					entryToCheck = listEntry ;
-				}
-				else {
-					entryToCheck = prefix + "/" + listEntry ;
-				}
-				
-				if (compared.contains(entryToCheck) ) {
-					continue;
-				}
-				else {
-					compared.add(entryToCheck) ;
-				}
-				
-				boolean doesMatch = patternMatcher.match(new HashMap<String,String>(), entryToCheck, compiledPattern);
-				if (doesMatch) {
-					matches.add(entryToCheck);
-				}
-			}
-		}
-		return matches ;
-	}
-
-	/**
-	 * @param patternMatcher the PatternMatcher implementation to use when comparing filenames
-	 */
-	public void setPatternMatcher(PatternMatcher<int[]> patternMatcher) {
-		this.patternMatcher = patternMatcher;
-	}
-
-	private URL[] getClassLoaderURLs() {
-		URL[] urls;
-		ClassLoader loader = Thread.currentThread().getContextClassLoader();
-
-		if (!(loader instanceof URLClassLoader)) {
-			loader = ClassPathFinder.class.getClassLoader();
-		}
-
-		if (loader instanceof URLClassLoader) {
-			urls = ((URLClassLoader) loader).getURLs();
-		} else {    //jdk9 or later
-			try {
-				urls = Collections.list(loader.getResources("")).toArray(new URL[0]);
-			} catch (IOException e) {
-				throw new XWorkException("unable to get ClassLoader URLs", e);
-			}
-		}
-
-		return urls;
-	}
+    public Vector<String> findMatches() {
+        Vector<String> matches = new Vector<>();
+        URL[] parentUrls = getClassLoaderURLs();
+        compiledPattern = patternMatcher.compilePattern(pattern);
+        for (URL url : parentUrls) {
+            if (!"file".equals(url.getProtocol())) {
+                continue;
+            }
+            URI entryURI;
+            try {
+                entryURI = url.toURI();
+            } catch (URISyntaxException e) {
+                continue;
+            }
+            File entry = new File(entryURI);
+            if (entry.isFile() && entry.toString().endsWith(".jar")) {
+                try {
+                    ZipInputStream zip = new ZipInputStream(new FileInputStream(entry));
+                    for (ZipEntry zipEntry = zip.getNextEntry(); zipEntry != null; zipEntry = zip.getNextEntry()) {
+                        boolean doesMatch = patternMatcher.match(new HashMap<String, String>(), zipEntry.getName(), compiledPattern);
+                        if (doesMatch) {
+                            matches.add(zipEntry.getName());
+                        }
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                Vector<String> results = checkEntries(entry.list(), entry, "");
+                if (results != null) {
+                    matches.addAll(results);
+                }
+            }
+        }
+        return matches;
+    }
+
+    private Vector<String> checkEntries(String[] entries, File parent, String prefix) {
+
+        if (entries == null) {
+            return null;
+        }
+
+        Vector<String> matches = new Vector<>();
+        for (String listEntry : entries) {
+            File tempFile;
+            if (!"".equals(prefix)) {
+                tempFile = new File(parent, prefix + "/" + listEntry);
+            } else {
+                tempFile = new File(parent, listEntry);
+            }
+            if (tempFile.isDirectory() &&
+                !(".".equals(listEntry) || "..".equals(listEntry))) {
+                if (!"".equals(prefix)) {
+                    matches.addAll(checkEntries(tempFile.list(), parent, prefix + "/" + listEntry));
+                } else {
+                    matches.addAll(checkEntries(tempFile.list(), parent, listEntry));
+                }
+            } else {
+
+                String entryToCheck;
+                if ("".equals(prefix)) {
+                    entryToCheck = listEntry;
+                } else {
+                    entryToCheck = prefix + "/" + listEntry;
+                }
+
+                if (compared.contains(entryToCheck)) {
+                    continue;
+                } else {
+                    compared.add(entryToCheck);
+                }
+
+                boolean doesMatch = patternMatcher.match(new HashMap<String, String>(), entryToCheck, compiledPattern);
+                if (doesMatch) {
+                    matches.add(entryToCheck);
+                }
+            }
+        }
+        return matches;
+    }
+
+    /**
+     * @param patternMatcher the PatternMatcher implementation to use when comparing filenames
+     */
+    public void setPatternMatcher(PatternMatcher<int[]> patternMatcher) {
+        this.patternMatcher = patternMatcher;
+    }
+
+    private URL[] getClassLoaderURLs() {
+        URL[] urls;
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+
+        if (!(loader instanceof URLClassLoader)) {
+            loader = ClassPathFinder.class.getClassLoader();
+        }
+
+        if (loader instanceof URLClassLoader) {
+            urls = ((URLClassLoader) loader).getURLs();
+        } else {    //jdk9 or later
+            try {
+                urls = Collections.list(loader.getResources("")).toArray(new URL[0]);
+            } catch (IOException e) {
+                throw new XWorkException("unable to get ClassLoader URLs", e);
+            }
+        }
+
+        return urls;
+    }
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
index 2541ad5..99aa541 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
@@ -27,9 +27,9 @@ import com.opensymphony.xwork2.test.User;
 import com.opensymphony.xwork2.util.*;
 import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
 import ognl.*;
-import org.apache.struts2.TestUtils;
 
 import java.lang.reflect.Method;
+import java.text.DateFormat;
 import java.util.*;
 
 public class OgnlUtilTest extends XWorkTestCase {
@@ -373,24 +373,8 @@ public class OgnlUtilTest extends XWorkTestCase {
         cal.set(Calendar.YEAR, 1982);
 
         assertEquals(cal.getTime(), foo.getBirthday());
-        
-        //UK style test
-        if (TestUtils.isJdk9OrLater()) {
-            /* In JDK 9 and later, the default locale data uses data derived from the
-            Unicode Consortium's Common Locale Data Repository (CLDR). The short date-time format is ‹{1}, {0}› in the
-            CLDR locale, as opposed to {1} {0} in the JRE locale data.
-            Please refer : http://www.oracle.com/technetwork/java/javase/9-relnote-issues-3704069.html#JDK-8008577 */
-            props.put("event", "18/10/2006, 14:23:45");
-            props.put("meeting", "09/09/2006, 14:30");
-        }
-        else {
-            props.put("event", "18/10/2006 14:23:45");
-            props.put("meeting", "09/09/2006 14:30");
-        }
-        context.put(ActionContext.LOCALE, Locale.UK);
 
-        ognlUtil.setProperties(props, foo, context);
-        
+        //UK style test
         cal = Calendar.getInstance();
         cal.clear();
         cal.set(Calendar.MONTH, Calendar.OCTOBER);
@@ -399,9 +383,12 @@ public class OgnlUtilTest extends XWorkTestCase {
         cal.set(Calendar.HOUR_OF_DAY, 14);
         cal.set(Calendar.MINUTE, 23);
         cal.set(Calendar.SECOND, 45);
-        
-        assertEquals(cal.getTime(), foo.getEvent());
-        
+
+        Date eventTime = cal.getTime();
+        String formatted = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.UK)
+                .format(eventTime);
+        props.put("event", formatted);
+
         cal = Calendar.getInstance();
         cal.clear();
         cal.set(Calendar.MONTH, Calendar.SEPTEMBER);
@@ -409,8 +396,19 @@ public class OgnlUtilTest extends XWorkTestCase {
         cal.set(Calendar.YEAR, 2006);
         cal.set(Calendar.HOUR_OF_DAY, 14);
         cal.set(Calendar.MINUTE, 30);
-        
-        assertEquals(cal.getTime(), foo.getMeeting());
+
+        Date meetingTime = cal.getTime();
+        formatted = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.UK)
+                .format(meetingTime);
+        props.put("meeting", formatted);
+
+        context.put(ActionContext.LOCALE, Locale.UK);
+
+        ognlUtil.setProperties(props, foo, context);
+
+        assertEquals(eventTime, foo.getEvent());
+
+        assertEquals(meetingTime, foo.getMeeting());
         
         //test RFC 3339 date format for JSON
         props.put("event", "1996-12-19T16:39:57Z");
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java b/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
index 16fbab4..fdc5416 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/AnnotationUtilsTest.java
@@ -30,7 +30,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import static org.fest.assertions.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class AnnotationUtilsTest extends TestCase {
 
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/ClassPathFinderTest.java b/core/src/test/java/com/opensymphony/xwork2/util/ClassPathFinderTest.java
index 34c0bbe..17a9deb 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/ClassPathFinderTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/ClassPathFinderTest.java
@@ -22,6 +22,7 @@ import com.opensymphony.xwork2.XWorkTestCase;
 import org.apache.commons.io.IOUtils;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -62,12 +63,14 @@ public class ClassPathFinderTest extends XWorkTestCase {
         NotURLClassLoader loader = new NotURLClassLoader(Thread.currentThread().getContextClassLoader());
         Thread.currentThread().setContextClassLoader(loader);
 
-        Class<?> clazz = loader.loadClass(ClassPathFinderTest.class.getName());
-        Object test = clazz.getConstructor().newInstance();
+        try {
+            Class<?> clazz = loader.loadClass(ClassPathFinderTest.class.getName());
+            Object test = clazz.getConstructor().newInstance();
 
-        clazz.getMethod("testFinder").invoke(test);
-
-        Thread.currentThread().setContextClassLoader(loader.parentClassLoader);
+            clazz.getMethod("testFinder").invoke(test);
+        } finally {
+            Thread.currentThread().setContextClassLoader(loader.parentClassLoader);
+        }
     }
 
 
@@ -89,6 +92,8 @@ public class ClassPathFinderTest extends XWorkTestCase {
                     loadedClasses.put(name, defineClass(name, classBits, 0, classBits.length));
                 } catch (IOException e) {
                     throw new ClassNotFoundException("class " + name + " is not findable", e);
+                } catch (Exception e) {
+                    loadedClasses.put(name, parentClassLoader.loadClass(name));
                 }
             }
 
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java b/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java
index 6969ccd..20a21ce 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java
@@ -34,6 +34,7 @@ import java.net.URLConnection;
 import java.net.URLStreamHandler;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.jar.Attributes;
 import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
@@ -49,10 +50,13 @@ public class JarEntryRevisionTest extends XWorkTestCase {
         fileManager = container.getInstance(FileManagerFactory.class).getFileManager();
     }
 
-    private void createJarFile(long time) throws Exception {
+    private String createJarFile(long time) throws Exception {
         Manifest manifest = new Manifest();
         manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
-        FileOutputStream fos = new FileOutputStream("target/JarEntryRevisionTest_testNeedsReloading.jar", false);
+        Path jarPath = Paths.get(Thread.currentThread().getContextClassLoader()
+                .getResource("xwork-jar.jar").toURI()).getParent();
+        File jarFile = jarPath.resolve("JarEntryRevisionTest_testNeedsReloading.jar").toFile();
+        FileOutputStream fos = new FileOutputStream(jarFile, false);
         JarOutputStream target = new JarOutputStream(fos, manifest);
         target.putNextEntry(new ZipEntry("com/opensymphony/xwork2/util/fs/"));
         ZipEntry entry = new ZipEntry("com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class");
@@ -64,13 +68,14 @@ public class JarEntryRevisionTest extends XWorkTestCase {
         target.closeEntry();
         target.close();
         fos.close();
+
+        return jarFile.toURI().toURL().toExternalForm();
     }
 
     public void testNeedsReloading() throws Exception {
         long now = System.currentTimeMillis();
 
-        createJarFile(now);
-        URL url = new URL("jar:file:target/JarEntryRevisionTest_testNeedsReloading.jar!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class");
+        URL url = new URL("jar:" + createJarFile(now) + "!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class");
         Revision entry = JarEntryRevision.build(url, fileManager);
         assert entry != null;
         assertFalse(entry.needsReloading());
@@ -82,9 +87,8 @@ public class JarEntryRevisionTest extends XWorkTestCase {
     public void testNeedsReloadingWithContainerProvidedURLConnection() throws Exception {
         long now = System.currentTimeMillis();
 
-        createJarFile(now);
         URL url = new URL(null,
-                "jar:file:target/JarEntryRevisionTest_testNeedsReloading.jar!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class",
+                "jar:" + createJarFile(now) + "!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class",
                 new ContainerProvidedURLStreamHandler());
         Revision entry = JarEntryRevision.build(url, fileManager);
         assert entry != null;
@@ -97,9 +101,7 @@ public class JarEntryRevisionTest extends XWorkTestCase {
     public void testNeedsReloadingWithContainerProvidedURLConnectionEmptyProtocol() throws Exception {
         long now = System.currentTimeMillis();
 
-        createJarFile(now);
-        File targetDir = new File("target");
-        String targetUrlStr = targetDir.toURI().toURL().toString();
+        String targetUrlStr = createJarFile(now);
         if (targetUrlStr.startsWith("file:")) {
             targetUrlStr = targetUrlStr.substring(5);//emptying protocol; we expect framework will fix it
         }
@@ -107,7 +109,7 @@ public class JarEntryRevisionTest extends XWorkTestCase {
             targetUrlStr = targetUrlStr.substring(1);//we expect framework will fix it also
         }
         URL url = new URL(null,
-                "zip:" + targetUrlStr + "JarEntryRevisionTest_testNeedsReloading.jar!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class",
+                "zip:" + targetUrlStr + "!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class",
                 new ContainerProvidedURLStreamHandler());
         Revision entry = JarEntryRevision.build(url, fileManager);
         assert entry != null;
diff --git a/core/src/test/java/org/apache/struts2/TestUtils.java b/core/src/test/java/org/apache/struts2/TestUtils.java
index 111cd89..32f5630 100644
--- a/core/src/test/java/org/apache/struts2/TestUtils.java
+++ b/core/src/test/java/org/apache/struts2/TestUtils.java
@@ -91,20 +91,4 @@ public class TestUtils {
 
         return buffer.toString();
     }
-
-    public static boolean isJdk9OrLater() {
-        ClassLoader loader = Thread.currentThread().getContextClassLoader();
-
-        if(loader instanceof URLClassLoader) {
-            return false;
-        }
-
-        loader = TestUtils.class.getClassLoader();
-
-        if(loader instanceof URLClassLoader) {
-            return false;
-        }
-
-        return true;
-    }
 }
diff --git a/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java b/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java
index 0dda7cb..b88d2b3 100644
--- a/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java
+++ b/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java
@@ -29,7 +29,7 @@ import java.lang.reflect.Member;
 import java.util.Collections;
 import java.util.Map;
 
-import static org.fest.assertions.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class UploadedFileConverterTest {
 
diff --git a/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerThemeTemplateLoaderTest.java b/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerThemeTemplateLoaderTest.java
index e10968b..0c5538a 100644
--- a/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerThemeTemplateLoaderTest.java
+++ b/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerThemeTemplateLoaderTest.java
@@ -22,18 +22,15 @@ import freemarker.cache.TemplateLoader;
 import org.apache.struts2.StrutsInternalTestCase;
 import org.apache.struts2.components.template.Template;
 import org.apache.struts2.components.template.TemplateEngine;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
 import org.hamcrest.core.IsEqual;
-import org.mockito.Matchers;
 
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.fest.assertions.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
 
 public class FreemarkerThemeTemplateLoaderTest extends StrutsInternalTestCase {
 
@@ -65,7 +62,7 @@ public class FreemarkerThemeTemplateLoaderTest extends StrutsInternalTestCase {
         TemplateEngine engine = mock(TemplateEngine.class);
         Map<String, String> props = new HashMap<String, String>();
         props.put("parent", "foo/foo");
-        when(engine.getThemeProps(Matchers.argThat(new IsEqual<Template>(new Template("template", "foo/bar", "text.ftl"))))).thenReturn(props);
+        when(engine.getThemeProps(argThat(new IsEqual<>(new Template("template", "foo/bar", "text.ftl"))))).thenReturn(props);
         loader.setTemplateEngine(engine);
 
         TemplateLoader parent = mock(TemplateLoader.class);
diff --git a/plugins/bean-validation/pom.xml b/plugins/bean-validation/pom.xml
index d3e5693..f304f79 100644
--- a/plugins/bean-validation/pom.xml
+++ b/plugins/bean-validation/pom.xml
@@ -61,6 +61,37 @@
             <scope>test</scope>
         </dependency>
 
+        <!--
+         The Java EE API modules listed below are all marked @Deprecated(forRemoval=true), because they are scheduled
+         for removal in Java 11. So the -add-module approach will no longer work in Java 11 out of the box.
+         What we will need to do in Java 11 and forward is include our own copy of the Java EE APIs on the class path
+         or module path. For example, we can add the JAX-B APIs as a maven dependency like this:
+        -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>2.3.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-core</artifactId>
+            <version>2.3.0.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-impl</artifactId>
+            <version>2.3.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.activation</groupId>
+            <artifactId>activation</artifactId>
+            <version>1.1.1</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java b/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
index 952cd84..dbc8070 100644
--- a/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
+++ b/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
@@ -231,12 +231,14 @@ public class EmbeddedJSPResultTest extends TestCase {
         NotURLClassLoader loader = new NotURLClassLoader(parentClassLoader);
         Thread.currentThread().setContextClassLoader(loader);
 
-        result.setLocation("org/apache/struts2/tag0.jsp");
-        result.execute(null);
-
-        assertEquals("Thissessionisnotsecure.OtherText", StringUtils.deleteWhitespace(response.getContentAsString()));
+        try {
+            result.setLocation("org/apache/struts2/tag0.jsp");
+            result.execute(null);
 
-        Thread.currentThread().setContextClassLoader(parentClassLoader);
+            assertEquals("Thissessionisnotsecure.OtherText", StringUtils.deleteWhitespace(response.getContentAsString()));
+        } finally {
+            Thread.currentThread().setContextClassLoader(parentClassLoader);
+        }
     }
 
     @Override
diff --git a/plugins/json/pom.xml b/plugins/json/pom.xml
index 9caa942..a89b221 100644
--- a/plugins/json/pom.xml
+++ b/plugins/json/pom.xml
@@ -101,8 +101,8 @@
         </dependency>
 
         <dependency>
-            <groupId>org.easytesting</groupId>
-            <artifactId>fest-assert</artifactId>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
             <scope>test</scope>
         </dependency>
 
diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONValidationInterceptorTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONValidationInterceptorTest.java
index 6447d37..a4fd58d 100644
--- a/plugins/json/src/test/java/org/apache/struts2/json/JSONValidationInterceptorTest.java
+++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONValidationInterceptorTest.java
@@ -39,7 +39,7 @@ import java.io.StringWriter;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.fest.assertions.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class JSONValidationInterceptorTest extends StrutsTestCase {
 
diff --git a/plugins/rest/pom.xml b/plugins/rest/pom.xml
index 88a7d97..33324af 100644
--- a/plugins/rest/pom.xml
+++ b/plugins/rest/pom.xml
@@ -80,8 +80,8 @@
         </dependency>
 
         <dependency>
-            <groupId>org.easytesting</groupId>
-            <artifactId>fest-assert</artifactId>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
             <scope>test</scope>
         </dependency>
 
diff --git a/plugins/rest/src/test/java/org/apache/struts2/rest/handler/JacksonXmlHandlerTest.java b/plugins/rest/src/test/java/org/apache/struts2/rest/handler/JacksonXmlHandlerTest.java
index e2c4eda..befefee 100644
--- a/plugins/rest/src/test/java/org/apache/struts2/rest/handler/JacksonXmlHandlerTest.java
+++ b/plugins/rest/src/test/java/org/apache/struts2/rest/handler/JacksonXmlHandlerTest.java
@@ -28,7 +28,7 @@ import java.io.StringWriter;
 import java.io.Writer;
 import java.util.Arrays;
 
-import static org.fest.assertions.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class JacksonXmlHandlerTest extends XWorkTestCase {
 
diff --git a/pom.xml b/pom.xml
index 5ed9637..02fcdf6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -110,6 +110,7 @@
 
         <!-- Sonar -->
         <sonar.host.url>https://builds.apache.org/analysis/</sonar.host.url>
+        <maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
     </properties>
 
     <profiles>
@@ -169,6 +170,7 @@
             </activation>
             <properties>
                 <!-- coverall version 4.3.0 does not work with java 9, see https://github.com/trautonen/coveralls-maven-plugin/issues/112 -->
+                <!-- TODO delete coveralls.skip property after fix of https://github.com/cobertura/cobertura/issues/271 -->
                 <coveralls.skip>true</coveralls.skip>
             </properties>
             <build>
@@ -178,7 +180,8 @@
                             <groupId>org.apache.maven.plugins</groupId>
                             <artifactId>maven-surefire-plugin</artifactId>
                             <configuration>
-                                <argLine>--add-modules java.activation --add-modules java.xml.bind</argLine>
+                                <!-- TODO delete forkCount=0 after fix of https://issues.apache.org/jira/browse/SUREFIRE-1588 -->
+                                <forkCount>0</forkCount>
                             </configuration>
                         </plugin>
                     </plugins>
@@ -233,12 +236,12 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
-                    <version>2.22.1</version>
+                    <version>${maven-surefire-plugin.version}</version>
                     <dependencies>
                         <dependency>
                             <groupId>org.apache.maven.surefire</groupId>
                             <artifactId>surefire-junit47</artifactId>
-                            <version>2.22.1</version>
+                            <version>${maven-surefire-plugin.version}</version>
                         </dependency>
                     </dependencies>
                     <configuration>
@@ -972,16 +975,16 @@
             </dependency>
 
             <dependency>
-                <groupId>org.easytesting</groupId>
-                <artifactId>fest-assert</artifactId>
-                <version>1.4</version>
+                <groupId>org.assertj</groupId>
+                <artifactId>assertj-core</artifactId>
+                <version>2.9.1</version>
                 <scope>test</scope>
             </dependency>
 
             <dependency>
                 <groupId>org.mockito</groupId>
-                <artifactId>mockito-all</artifactId>
-                <version>1.10.19</version>
+                <artifactId>mockito-core</artifactId>
+                <version>2.23.0</version>
                 <scope>test</scope>
             </dependency>