Reverse merges master
diff --git a/Jenkinsfile b/Jenkinsfile
index 5bff27e..ac7516d 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -170,14 +170,21 @@
     failure {
       script {
         emailext(
-            subject: "[BUILD-FAILURE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'",
-            body: """
-              BUILD-FAILURE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]':
-               
-              Check console output at ${env.BUILD_URL}
-            """.stripMargin(),
             to: "dev@struts.apache.org",
-            recipientProviders: [[$class: 'DevelopersRecipientProvider']]
+            recipientProviders: [[$class: 'DevelopersRecipientProvider']],
+            from: "Mr. Jenkins <jenkins@builds.apache.org>",
+            subject: "Jenkins job ${env.JOB_NAME}#${env.BUILD_NUMBER} failed",
+            body: """
+There is a build failure in ${env.JOB_NAME}.
+
+Build: ${env.BUILD_URL}
+Logs: ${env.BUILD_URL}console
+Changes: ${env.BUILD_URL}changes
+
+--
+Mr. Jenkins
+Director of Continuous Integration
+"""
         )
       }
     }
@@ -186,14 +193,21 @@
     unstable {
       script {
         emailext(
-            subject: "[BUILD-UNSTABLE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'",
-            body: """
-              BUILD-UNSTABLE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]':
-               
-              Check console output at ${env.BUILD_URL}
-            """.stripMargin(),
             to: "dev@struts.apache.org",
-            recipientProviders: [[$class: 'DevelopersRecipientProvider']]
+            recipientProviders: [[$class: 'DevelopersRecipientProvider']],
+            from: "Mr. Jenkins <jenkins@builds.apache.org>",
+            subject: "Jenkins job ${env.JOB_NAME}#${env.BUILD_NUMBER} unstable",
+            body: """
+Some tests have failed in ${env.JOB_NAME}.
+
+Build: ${env.BUILD_URL}
+Logs: ${env.BUILD_URL}console
+Changes: ${env.BUILD_URL}changes
+
+--
+Mr. Jenkins
+Director of Continuous Integration
+"""
         )
       }
     }
@@ -202,14 +216,21 @@
     fixed {
       script {
         emailext(
-            subject: "[BUILD-STABLE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'",
-            body: """
-              BUILD-STABLE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]':
-               
-              Is back to normal.
-            """.stripMargin(),
             to: "dev@struts.apache.org",
-            recipientProviders: [[$class: 'DevelopersRecipientProvider']]
+            recipientProviders: [[$class: 'DevelopersRecipientProvider']],
+            from: 'Mr. Jenkins <jenkins@builds.apache.org>',
+            subject: "Jenkins job ${env.JOB_NAME}#${env.BUILD_NUMBER} back to normal",
+            body: """
+The build for ${env.JOB_NAME} completed successfully and is back to normal.
+
+Build: ${env.BUILD_URL}
+Logs: ${env.BUILD_URL}console
+Changes: ${env.BUILD_URL}changes
+
+--
+Mr. Jenkins
+Director of Continuous Integration
+"""
         )
       }
     }
diff --git a/apps/rest-showcase/pom.xml b/apps/rest-showcase/pom.xml
index 2bf65a1..9aff868 100644
--- a/apps/rest-showcase/pom.xml
+++ b/apps/rest-showcase/pom.xml
@@ -80,7 +80,7 @@
         <dependency>
             <groupId>net.sourceforge.htmlunit</groupId>
             <artifactId>htmlunit</artifactId>
-            <version>2.27</version>
+            <version>2.39.0</version>
             <scope>test</scope>
         </dependency>
 
diff --git a/apps/showcase/pom.xml b/apps/showcase/pom.xml
index 6360c0a..78564ac 100644
--- a/apps/showcase/pom.xml
+++ b/apps/showcase/pom.xml
@@ -144,7 +144,7 @@
        <dependency>
             <groupId>net.sourceforge.htmlunit</groupId>
             <artifactId>htmlunit</artifactId>
-            <version>2.37.0</version>
+            <version>2.39.0</version>
             <scope>test</scope>
         </dependency>
 
@@ -152,7 +152,7 @@
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-validator</artifactId>
-            <version>5.4.3.Final</version>
+            <version>6.1.2.Final</version>
         </dependency>
 
         <!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
@@ -171,7 +171,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-failsafe-plugin</artifactId>
-                <version>2.22.2</version>
+                <version>3.0.0-M4</version>
                 <configuration>
                     <includes>
                         <include>it.org.apache.struts2.showcase.*Test</include>
diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
index 9639205..749b08b 100644
--- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
+++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
@@ -18,7 +18,7 @@
  */
 package com.opensymphony.xwork2.conversion.impl;
 
-import org.apache.struts2.StrutsException;
+import org.apache.struts2.conversion.TypeConversionException;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Member;
@@ -90,11 +90,11 @@
                         Constructor constructor = toType.getConstructor(new Class[]{long.class});
                         return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
                     } catch (Exception e) {
-                        throw new StrutsException("Couldn't create class " + toType + " using default (long) constructor", e);
+                        throw new TypeConversionException("Couldn't create class " + toType + " using default (long) constructor", e);
                     }
                 }
             } catch (ParseException e) {
-                throw new StrutsException("Could not parse date", e);
+                throw new TypeConversionException("Could not parse date", e);
             }
         } else if (Date.class.isAssignableFrom(value.getClass())) {
             result = (Date) value;
diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java
index 92c5e7d..3f47566 100644
--- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java
+++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java
@@ -18,9 +18,9 @@
  */
 package com.opensymphony.xwork2.conversion.impl;
 
+import org.apache.struts2.conversion.TypeConversionException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.apache.struts2.StrutsException;
 
 import java.lang.reflect.Member;
 import java.math.BigDecimal;
@@ -51,7 +51,7 @@
                 Object convertedValue = super.convertValue(context, value, toType);
 
                 if (!isInRange((Number) convertedValue, stringValue, toType))
-                    throw new StrutsException("Overflow or underflow casting: \"" + stringValue + "\" into class " + convertedValue.getClass().getName());
+                    throw new TypeConversionException("Overflow or underflow casting: \"" + stringValue + "\" into class " + convertedValue.getClass().getName());
 
                 return convertedValue;
             } else {
@@ -67,11 +67,11 @@
                 Number number = numFormat.parse(stringValue, parsePos);
 
                 if (parsePos.getIndex() != stringValue.length()) {
-                    throw new StrutsException("Unparseable number: \"" + stringValue + "\" at position "
+                    throw new TypeConversionException("Unparseable number: \"" + stringValue + "\" at position "
                         + parsePos.getIndex());
                 } else {
                     if (!isInRange(number, stringValue, toType))
-                        throw new StrutsException("Overflow or underflow casting: \"" + stringValue + "\" into class " + number.getClass().getName());
+                        throw new TypeConversionException("Overflow or underflow casting: \"" + stringValue + "\" into class " + number.getClass().getName());
 
                     value = super.convertValue(context, number, toType);
                 }
@@ -103,7 +103,7 @@
         Number number = format.parse(stringValue, parsePosition);
 
         if (parsePosition.getIndex() != stringValue.length()) {
-            throw new StrutsException("Unparseable number: \"" + stringValue + "\" at position " + parsePosition.getIndex());
+            throw new TypeConversionException("Unparseable number: \"" + stringValue + "\" at position " + parsePosition.getIndex());
         }
 
         return number;
@@ -123,11 +123,11 @@
         Number number = format.parse(stringValue, parsePosition);
 
         if (parsePosition.getIndex() != stringValue.length()) {
-            throw new StrutsException("Unparseable number: \"" + stringValue + "\" at position " + parsePosition.getIndex());
+            throw new TypeConversionException("Unparseable number: \"" + stringValue + "\" at position " + parsePosition.getIndex());
         }
 
         if (!isInRange(number, stringValue, Double.class)) {
-            throw new StrutsException("Overflow or underflow converting: \"" + stringValue + "\" into class " + number.getClass().getName());
+            throw new TypeConversionException("Overflow or underflow converting: \"" + stringValue + "\" into class " + number.getClass().getName());
         }
 
         if (number != null) {
@@ -151,11 +151,11 @@
         Number number = format.parse(stringValue, parsePosition);
 
         if (parsePosition.getIndex() != stringValue.length()) {
-            throw new StrutsException("Unparseable number: \"" + stringValue + "\" at position " + parsePosition.getIndex());
+            throw new TypeConversionException("Unparseable number: \"" + stringValue + "\" at position " + parsePosition.getIndex());
         }
 
         if (!isInRange(number, stringValue, Float.class)) {
-            throw new StrutsException("Overflow or underflow converting: \"" + stringValue + "\" into class " + number.getClass().getName());
+            throw new TypeConversionException("Overflow or underflow converting: \"" + stringValue + "\" into class " + number.getClass().getName());
         }
 
         if (number != null) {
diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java
index 23129a6..d415a8d 100644
--- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java
+++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java
@@ -18,11 +18,11 @@
  */
 package com.opensymphony.xwork2.conversion.impl;
 
+import org.apache.struts2.conversion.TypeConversionException;
 import com.opensymphony.xwork2.conversion.TypeConverter;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.inject.Inject;
 import org.apache.struts2.StrutsConstants;
-import org.apache.struts2.StrutsException;
 
 import java.lang.reflect.Member;
 import java.util.Calendar;
@@ -130,7 +130,7 @@
             }
 
             if (result == null && value != null && !"".equals(value)) {
-                throw new StrutsException("Cannot create type " + toType + " from value " + value);
+                throw new TypeConversionException("Cannot create type " + toType + " from value " + value);
             }
         }
 
@@ -170,7 +170,7 @@
             try {
                 clazz = Class.forName((String) value);
             } catch (ClassNotFoundException e) {
-                throw new StrutsException(e.getLocalizedMessage(), e);
+                throw new TypeConversionException(e.getLocalizedMessage(), e);
             }
         }
         return clazz;
@@ -179,7 +179,7 @@
     private Object doConvertToCollection(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
         TypeConverter converter = container.getInstance(CollectionConverter.class);
         if (converter == null) {
-            throw new StrutsException("TypeConverter with name [#0] must be registered first!", StrutsConstants.STRUTS_CONVERTER_COLLECTION);
+            throw new TypeConversionException("TypeConverter with name [#0] must be registered first! Converter: "+ StrutsConstants.STRUTS_CONVERTER_COLLECTION);
         }
         return converter.convertValue(context, o, member, prop, value, toType);
     }
@@ -187,7 +187,7 @@
     private Object doConvertToArray(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
         TypeConverter converter = container.getInstance(ArrayConverter.class);
         if (converter == null) {
-            throw new StrutsException("TypeConverter with name [#0] must be registered first!", StrutsConstants.STRUTS_CONVERTER_ARRAY);
+            throw new TypeConversionException("TypeConverter with name [#0] must be registered first! Converter: "+ StrutsConstants.STRUTS_CONVERTER_ARRAY);
         }
         return converter.convertValue(context, o, member, prop, value, toType);
     }
@@ -195,7 +195,7 @@
     private Object doConvertToDate(Map<String, Object> context, Object value, Class toType) {
         TypeConverter converter = container.getInstance(DateConverter.class);
         if (converter == null) {
-            throw new StrutsException("TypeConverter with name [#0] must be registered first!", StrutsConstants.STRUTS_CONVERTER_DATE);
+            throw new TypeConversionException("TypeConverter with name [#0] must be registered first! Converter: "+ StrutsConstants.STRUTS_CONVERTER_DATE);
         }
         return converter.convertValue(context, null, null, null, value, toType);
     }
@@ -203,7 +203,7 @@
     private Object doConvertToNumber(Map<String, Object> context, Object value, Class toType) {
         TypeConverter converter = container.getInstance(NumberConverter.class);
         if (converter == null) {
-            throw new StrutsException("TypeConverter with name [#0] must be registered first!", StrutsConstants.STRUTS_CONVERTER_NUMBER);
+            throw new TypeConversionException("TypeConverter with name [#0] must be registered first! Converter: "+ StrutsConstants.STRUTS_CONVERTER_NUMBER);
         }
         return converter.convertValue(context, null, null, null, value, toType);
     }
@@ -211,7 +211,7 @@
     private Object doConvertToString(Map<String, Object> context, Object value) {
         TypeConverter converter = container.getInstance(StringConverter.class);
         if (converter == null) {
-            throw new StrutsException("TypeConverter with name [#0] must be registered first!", StrutsConstants.STRUTS_CONVERTER_STRING);
+            throw new TypeConversionException("TypeConverter with name [#0] must be registered first! Converter: "+ StrutsConstants.STRUTS_CONVERTER_STRING);
         }
         return converter.convertValue(context, null, null, null, value, null);
     }
diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/TypeConversionException.java b/core/src/main/java/org/apache/struts2/conversion/TypeConversionException.java
similarity index 97%
rename from core/src/main/java/com/opensymphony/xwork2/conversion/TypeConversionException.java
rename to core/src/main/java/org/apache/struts2/conversion/TypeConversionException.java
index 73db264..0d324bc 100644
--- a/core/src/main/java/com/opensymphony/xwork2/conversion/TypeConversionException.java
+++ b/core/src/main/java/org/apache/struts2/conversion/TypeConversionException.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package com.opensymphony.xwork2.conversion;
+package org.apache.struts2.conversion;
 
 import org.apache.struts2.StrutsException;
 
diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java
new file mode 100644
index 0000000..157e6d8
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/DateConverterTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.ActionContext;
+import org.apache.struts2.conversion.TypeConversionException;
+import org.apache.struts2.StrutsInternalTestCase;
+
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class DateConverterTest extends StrutsInternalTestCase {
+	
+	private String INPUT_TIME_STAMP_STR;
+	private String INPUT_WHEN_LONG_CONSTRUCTOR_STR;
+	private Locale mxLocale = new Locale("es_MX", "MX");
+	private final static String RES_TIME_STAMP_STR = "2020-03-20 00:00:00.0";
+	private final static String TIME_01_59_10 = "01:59:10 AM";
+	private final static String DATE_STR = "2020-03-20";
+	private final static String DATE_CONVERTED = "Fri Mar 20 00:00:00";
+	private final static String INVALID_DATE = "99/99/2010";
+	private final static String MESSAGE_PARSE_ERROR = "Could not parse date";
+	private final static String MESSAGE_DEFAULT_CONSTRUCTOR_ERROR = "Couldn't create class null using default (long) constructor";
+	
+	public void testSqlTimeType() {
+		DateConverter converter = new DateConverter();
+		
+		Map<String, Object> context = new HashMap<>();
+		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
+		
+		Object value = converter.convertValue(context, null, null, null, TIME_01_59_10, Time.class);
+		assertEquals("01:59:10", value.toString());
+	}
+	
+	public void testSqlTimestampType() {
+		DateConverter converter = new DateConverter();
+		Map<String, Object> context = new HashMap<>();
+		context.put(ActionContext.LOCALE, mxLocale);
+		
+		Object value = converter.convertValue(context, null, null, null, INPUT_TIME_STAMP_STR, Timestamp.class);
+		assertEquals(RES_TIME_STAMP_STR, value.toString());
+	}
+	
+	public void testDateType() {
+		DateConverter converter = new DateConverter();
+		
+		Map<String, Object> context = new HashMap<>();
+		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
+		
+		Object value = converter.convertValue(context, null, null, null, DATE_STR, Date.class);
+		assertTrue(((Date) value).toString().startsWith(DATE_CONVERTED));
+	}
+	
+	public void testTypeConversionExceptionWhenParseError() {
+		DateConverter converter = new DateConverter();
+		
+		Map<String, Object> context = new HashMap<>();
+		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
+		
+		try {
+			Object value = converter.convertValue(context, null, null, null, INVALID_DATE, Date.class);
+			fail("TypeConversionException expected - Conversion error occurred");
+		} catch (Exception ex) {
+			assertEquals(TypeConversionException.class, ex.getClass());
+			assertEquals(MESSAGE_PARSE_ERROR, ex.getMessage());
+		}
+	}
+	
+	public void testTypeConversionExceptionWhenUsingLongConstructor() {
+		DateConverter converter = new DateConverter();
+		
+		Map<String, Object> context = new HashMap<>();
+		context.put(ActionContext.LOCALE, new Locale("es_MX", "MX"));
+		
+		try {
+			Object value = converter.convertValue(context, null, null, null, INPUT_WHEN_LONG_CONSTRUCTOR_STR, null);
+			fail("TypeConversionException expected - Error using default (long) constructor");
+		} catch (Exception ex) {
+			assertEquals(TypeConversionException.class, ex.getClass());
+			assertEquals(MESSAGE_DEFAULT_CONSTRUCTOR_ERROR, ex.getMessage());
+		}
+	}
+	
+	@Override
+	protected void setUp() {
+		//Due to JEP 252: Use CLDR Locale Data by Default
+		DateFormat dFormat = DateFormat.getDateInstance(DateFormat.SHORT, mxLocale);
+		if(dFormat.format(new Date()).contains("-")){ 			// Format when Java 9 or greater
+			INPUT_TIME_STAMP_STR = "2020-03-20 00:00:00.000";
+			INPUT_WHEN_LONG_CONSTRUCTOR_STR = "2020-03-20";
+		}else{ 																							// Format when Java 8 or lower
+			INPUT_TIME_STAMP_STR = "03/20/2020 00:00:00.000";
+			INPUT_WHEN_LONG_CONSTRUCTOR_STR = "03/31/20";
+		}
+	}
+	
+}
diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java
index 2b6f34b..b0271ea 100644
--- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java
@@ -20,6 +20,7 @@
 
 import com.opensymphony.xwork2.SimpleFooAction;
 import com.opensymphony.xwork2.XWorkTestCase;
+import org.apache.struts2.conversion.TypeConversionException;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
@@ -28,6 +29,16 @@
 
 public class NumberConverterTest extends XWorkTestCase {
 
+    private final static String FLOAT_OUT_OF_RANGE = "3.5028235E38";
+    private final static String DOUBLE_OUT_OF_RANGE = "1.7976931348623157E309";
+    private final static String INTEGER_OUT_OF_RANGE = "2147483648";
+    private final static String MSG_OUT_OF_RANGE_CASTING = "Overflow or underflow casting";
+    private final static String MSG_OUT_OF_RANGE_CONVERTING = "Overflow or underflow converting";
+    private final static String MSG_UNPARSEABLE_NUMBER = "Unparseable number";
+    private final static String MSG_TEST_FAILS_OUT_OF_RANGE = "TypeConversionException expected when OUT OF RANGE";
+    private final static String MSG_TEST_FAILS_UNPARSEABLE_NUMBER = "TypeConversionException expected when UNPARSEABLE NUMBER";
+    private final static Locale LOCALE_MEXICO = new Locale("es_MX", "MX");
+
     public void testStringToNumberConversionPL() throws Exception {
         // given
         NumberConverter converter = new NumberConverter();
@@ -158,5 +169,137 @@
         assertEquals(1234.4F, value);
     }
 
+    public void testExceptionWhenPrimitiveIsOutOfRange() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, INTEGER_OUT_OF_RANGE, int.class);
+            fail(MSG_TEST_FAILS_OUT_OF_RANGE);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_OUT_OF_RANGE_CASTING));
+        }
+    }
+
+    public void testExceptionWhenANotPrimitiveIsUnparsable() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+        String strValue = "1.2";
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, strValue, Byte.class);
+            fail(MSG_TEST_FAILS_UNPARSEABLE_NUMBER);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_UNPARSEABLE_NUMBER));
+        }
+    }
+
+    public void testExceptionWhenANotPrimitiveIsOutOfRange() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+        String strValue = "129";
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, strValue, Byte.class);
+            fail(MSG_TEST_FAILS_OUT_OF_RANGE);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_OUT_OF_RANGE_CASTING));
+        }
+    }
+
+    public void testExceptionWhenUnparseableInConvertToBigDecimal() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+        String strValue = "1-23";
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, strValue, BigDecimal.class);
+            fail(MSG_TEST_FAILS_UNPARSEABLE_NUMBER);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_UNPARSEABLE_NUMBER));
+        }
+    }
+
+    public void testExceptionWhenUnparseableInConvertToDouble() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+        String strValue = "1-23";
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, strValue, Double.class);
+            fail(MSG_TEST_FAILS_UNPARSEABLE_NUMBER);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_UNPARSEABLE_NUMBER));
+        }
+    }
+
+    public void testExceptionWhenOutOfRangeInConvertToDouble() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, DOUBLE_OUT_OF_RANGE, Double.class);
+            fail(MSG_TEST_FAILS_OUT_OF_RANGE);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_OUT_OF_RANGE_CONVERTING));
+        }
+    }
+
+    public void testExceptionWhenOutOfRangeInConvertToFloat() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, FLOAT_OUT_OF_RANGE, Float.class);
+            fail(MSG_TEST_FAILS_OUT_OF_RANGE);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_OUT_OF_RANGE_CONVERTING));
+        }
+    }
+
+    public void testExceptionWhenUnparseableInConvertToFloat() {
+        // given
+        NumberConverter converter = new NumberConverter();
+        Map<String, Object> context = createContextWithLocale(LOCALE_MEXICO);
+        String strValue = "1-23";
+
+        // when
+        try {
+            Object value = converter.convertValue(context, null, null, null, strValue, Float.class);
+            fail(MSG_TEST_FAILS_UNPARSEABLE_NUMBER);
+        } catch (Exception ex) {
+            // then
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_UNPARSEABLE_NUMBER));
+        }
+    }
 
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
index 5c67924..4209da1 100644
--- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
@@ -20,8 +20,11 @@
 
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.XWorkTestCase;
+import org.apache.struts2.conversion.TypeConversionException;
+import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.test.annotations.Person;
 import org.apache.struts2.StrutsException;
+import org.mockito.Mockito;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -37,6 +40,9 @@
 public class XWorkBasicConverterTest extends XWorkTestCase {
 
     private XWorkBasicConverter basicConverter;
+    private Container mockedContainer;
+    private final static String MSG_EXCEPTION_EXPECTED = "TypeConversionException expected";
+    private final static String MSG_TYPE_CONVERTER_EXCEPTION = "TypeConverter with name";
 
     // TODO: test for every possible conversion
     // take into account of empty string
@@ -285,11 +291,92 @@
         Class toType = String.class;
         basicConverter.convertValue(context, value, null, s, value, toType);
     }
+    
+    public void testExceptionWhenCantCreateTypeFromValue() {
+        try{
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, 4, Date.class);
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith("Cannot create type"));
+        }
+    }
+    
+    public void testExceptionInDoConvertToClass() {
+        try{
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", Class.class);
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+        }
+    }
+    
+    public void testExceptionInDoConvertToCollection() {
+        try{
+            Mockito.when(mockedContainer.getInstanceNames(CollectionConverter.class)).thenReturn(null);
+            basicConverter.setContainer(mockedContainer);
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", ArrayList.class);
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_TYPE_CONVERTER_EXCEPTION));
+        }
+    }
+    
+    public void testExceptionInDoConvertToArray() {
+        try{
+            int[] arrayInt = new int[1];
+            Mockito.when(mockedContainer.getInstanceNames(ArrayConverter.class)).thenReturn(null);
+            basicConverter.setContainer(mockedContainer);
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", arrayInt.getClass());
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_TYPE_CONVERTER_EXCEPTION));
+        }
+    }
+    
+    public void testExceptionInDoConvertToDate() {
+        try{
+            Mockito.when(mockedContainer.getInstanceNames(DateConverter.class)).thenReturn(null);
+            basicConverter.setContainer(mockedContainer);
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", Date.class);
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_TYPE_CONVERTER_EXCEPTION));
+        }
+    }
+    
+    public void testExceptionInDoConvertToNumber() {
+        try{
+            Mockito.when(mockedContainer.getInstanceNames(NumberConverter.class)).thenReturn(null);
+            basicConverter.setContainer(mockedContainer);
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "Foo", int.class);
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_TYPE_CONVERTER_EXCEPTION));
+        }
+    }
+    
+    public void testExceptionInDoConvertToString() {
+        try{
+            Mockito.when(mockedContainer.getInstanceNames(StringConverter.class)).thenReturn(null);
+            basicConverter.setContainer(mockedContainer);
+            Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, 1, String.class);
+            fail(MSG_EXCEPTION_EXPECTED);
+        }catch(Exception ex){
+            assertEquals(TypeConversionException.class, ex.getClass());
+            assertTrue(ex.getMessage().startsWith(MSG_TYPE_CONVERTER_EXCEPTION));
+        }
+    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         basicConverter = container.getInstance(XWorkBasicConverter.class);
+        mockedContainer = Mockito.mock(Container.class);
     }
 
     @Override
@@ -297,6 +384,5 @@
         super.tearDown();
         ActionContext.clear();
     }
-
-
+    
 }
diff --git a/plugins/bean-validation/pom.xml b/plugins/bean-validation/pom.xml
index ede4c08..fc616fa 100644
--- a/plugins/bean-validation/pom.xml
+++ b/plugins/bean-validation/pom.xml
@@ -41,7 +41,7 @@
         <dependency>
             <groupId>javax.validation</groupId>
             <artifactId>validation-api</artifactId>
-            <version>1.1.0.Final</version>
+            <version>2.0.1.Final</version>
         </dependency>
 
         <dependency>
@@ -52,7 +52,7 @@
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-validator</artifactId>
-            <version>5.4.3.Final</version>
+            <version>6.1.2.Final</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -82,7 +82,7 @@
         <dependency>
             <groupId>com.sun.xml.bind</groupId>
             <artifactId>jaxb-impl</artifactId>
-            <version>2.3.1</version>
+            <version>2.3.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/plugins/cdi/pom.xml b/plugins/cdi/pom.xml
index 7317b25..fefaa93 100644
--- a/plugins/cdi/pom.xml
+++ b/plugins/cdi/pom.xml
@@ -47,7 +47,7 @@
         </dependency>
 
         <dependency>
-            <groupId>org.jboss.weld</groupId>
+            <groupId>org.jboss.weld.se</groupId>
             <artifactId>weld-se</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/pom.xml b/pom.xml
index bfbb5d4..a551c0d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,6 +72,14 @@
         </notifiers>
     </ciManagement>
 
+    <distributionManagement>
+        <site>
+            <id>struts-site</id>
+            <name>Apache Struts</name>
+            <url>https://struts.apache.org/maven/</url>
+        </site>
+    </distributionManagement>
+
     <modules>
         <module>bom</module>
         <module>core</module>
@@ -99,21 +107,21 @@
         <java.version>1.8</java.version>
 
         <!-- dependency versions in alphanumeric order -->
-        <asm.version>7.2</asm.version>
-        <jackson.version>2.10.1</jackson.version>
-        <log4j2.version>2.12.1</log4j2.version>
-        <ognl.version>3.2.12</ognl.version>
-        <slf4j.version>1.7.29</slf4j.version>
-        <spring.platformVersion>4.3.25.RELEASE</spring.platformVersion>
+        <asm.version>7.3.1</asm.version>
+        <jackson.version>2.10.3</jackson.version>
+        <log4j2.version>2.13.1</log4j2.version>
+        <ognl.version>3.2.14</ognl.version>
+        <slf4j.version>1.7.30</slf4j.version>
+        <spring.platformVersion>4.3.26.RELEASE</spring.platformVersion>
         <tiles.version>3.0.8</tiles.version>
         <tiles-request.version>1.0.7</tiles-request.version>
 
         <!-- Site generation -->
-        <fluido-skin.version>1.8</fluido-skin.version>
+        <fluido-skin.version>1.9</fluido-skin.version>
 
         <!-- Sonar -->
         <sonar.host.url>https://builds.apache.org/analysis/</sonar.host.url>
-        <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
+        <maven-surefire-plugin.version>3.0.0-M4</maven-surefire-plugin.version>
     </properties>
 
     <profiles>
@@ -223,7 +231,7 @@
                     <plugin>
                         <groupId>org.jacoco</groupId>
                         <artifactId>jacoco-maven-plugin</artifactId>
-                        <version>0.8.4</version>
+                        <version>0.8.5</version>
                         <executions>
                             <execution>
                                 <id>prepare-agent</id>
@@ -287,17 +295,17 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-war-plugin</artifactId>
-                    <version>3.2.2</version>
+                    <version>3.2.3</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.felix</groupId>
                     <artifactId>maven-bundle-plugin</artifactId>
-                    <version>3.5.0</version>
+                    <version>4.2.1</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-dependency-plugin</artifactId>
-                    <version>3.1.1</version>
+                    <version>3.1.2</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
@@ -353,7 +361,7 @@
                 <plugin>
                     <groupId>org.owasp</groupId>
                     <artifactId>dependency-check-maven</artifactId>
-                    <version>5.2.4</version>
+                    <version>5.3.2</version>
                     <configuration>
                         <suppressionFiles>
                             <suppressionFile>src/etc/project-suppression.xml</suppressionFile>
@@ -366,7 +374,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-enforcer-plugin</artifactId>
-                    <version>3.0.0-M2</version>
+                    <version>3.0.0-M3</version>
                     <executions>
                         <execution>
                             <id>enforce</id>
@@ -425,7 +433,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-site-plugin</artifactId>
-                <version>3.8.2</version>
+                <version>3.9.0</version>
                 <configuration>
                     <relativizeDecorationLinks>false</relativizeDecorationLinks>
                 </configuration>
@@ -433,12 +441,12 @@
                     <dependency>
                         <groupId>org.apache.maven.doxia</groupId>
                         <artifactId>doxia-core</artifactId>
-                        <version>1.9</version>
+                        <version>1.9.1</version>
                     </dependency>
                     <dependency>
                         <groupId>org.apache.maven.doxia</groupId>
                         <artifactId>doxia-module-markdown</artifactId>
-                        <version>1.9</version>
+                        <version>1.9.1</version>
                     </dependency>
                 </dependencies>
             </plugin>
@@ -678,13 +686,13 @@
             <dependency>
                 <groupId>org.freemarker</groupId>
                 <artifactId>freemarker</artifactId>
-                <version>2.3.28</version>
+                <version>2.3.30</version>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>org.apache.felix.main</artifactId>
-                <version>4.6.1</version>
+                <version>6.0.3</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.felix</groupId>
@@ -713,7 +721,7 @@
             <dependency>
                 <groupId>org.apache.velocity</groupId>
                 <artifactId>velocity-engine-core</artifactId>
-                <version>2.1</version>
+                <version>2.2</version>
             </dependency>
 
             <dependency>
@@ -746,13 +754,13 @@
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
-                <version>4.12</version>
+                <version>4.13</version>
             </dependency>
 
             <dependency>
                 <groupId>org.easymock</groupId>
                 <artifactId>easymock</artifactId>
-                <version>3.5.1</version>
+                <version>4.2</version>
                 <scope>test</scope>
             </dependency>
 
@@ -766,7 +774,7 @@
             <dependency>
                 <groupId>org.glassfish</groupId>
                 <artifactId>javax.el</artifactId>
-                <version>3.0.1-b10</version>
+                <version>3.0.1-b11</version>
             </dependency>
 
             <dependency>
@@ -779,21 +787,21 @@
             <dependency>
                 <groupId>javax.servlet</groupId>
                 <artifactId>jstl</artifactId>
-                <version>1.1.2</version>
+                <version>1.2</version>
                 <scope>test</scope>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.tomcat</groupId>
                 <artifactId>tomcat-jasper</artifactId>
-                <version>8.5.37</version>
+                <version>8.5.53</version>
                 <scope>provided</scope>
             </dependency>
 
             <dependency>
                 <groupId>org.apache.tomcat</groupId>
                 <artifactId>tomcat-api</artifactId>
-                <version>8.5.37</version>
+                <version>8.5.53</version>
                 <scope>provided</scope>
             </dependency>
 
@@ -870,7 +878,7 @@
             <dependency>
                 <groupId>org.apache.tomcat</groupId>
                 <artifactId>tomcat-juli</artifactId>
-                <version>8.5.37</version>
+                <version>8.5.53</version>
             </dependency>
 
             <!-- Commons -->
@@ -903,7 +911,7 @@
             <dependency>
                 <groupId>org.apache.commons</groupId>
                 <artifactId>commons-lang3</artifactId>
-                <version>3.9</version>
+                <version>3.10</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.commons</groupId>
@@ -1025,14 +1033,22 @@
             <dependency>
                 <groupId>org.assertj</groupId>
                 <artifactId>assertj-core</artifactId>
-                <version>2.9.1</version>
+                <version>3.15.0</version>
                 <scope>test</scope>
             </dependency>
 
             <dependency>
                 <groupId>org.mockito</groupId>
                 <artifactId>mockito-core</artifactId>
-                <version>2.23.0</version>
+                <version>3.3.3</version>
+                <exclusions>
+                    <!-- The mockito-core artifact and easymock artifact use different versions of objenesis (2.6 vs 3.1).
+                         Excluding the older version here to pass enforcer.  When next upgrading mockito-core, confirm whether this exclusion is still required. -->
+                    <exclusion>
+                        <groupId>org.objenesis</groupId>
+                        <artifactId>objenesis</artifactId>
+                    </exclusion>
+                </exclusions>
                 <scope>test</scope>
             </dependency>
 
@@ -1063,7 +1079,7 @@
             <dependency>
                 <groupId>org.testng</groupId>
                 <artifactId>testng</artifactId>
-                <version>5.14.10</version>
+                <version>7.1.0</version>
                 <scope>compile</scope>
                 <optional>true</optional>
             </dependency>
@@ -1131,26 +1147,26 @@
             <dependency>
                 <groupId>org.apache.juneau</groupId>
                 <artifactId>juneau-marshall</artifactId>
-                <version>7.2.2</version>
+                <version>8.1.3</version>
             </dependency>
 
             <!-- CDI & Weld -->
             <dependency>
                 <groupId>javax.enterprise</groupId>
                 <artifactId>cdi-api</artifactId>
-                <version>1.0-SP4</version>
+                <version>1.2</version>
             </dependency>
 
             <dependency>
                 <groupId>org.jboss.weld</groupId>
                 <artifactId>weld-core</artifactId>
-                <version>1.0.1-SP4</version>
+                <version>2.2.16.SP1</version>
             </dependency>
 
             <dependency>
-                <groupId>org.jboss.weld</groupId>
+                <groupId>org.jboss.weld.se</groupId>
                 <artifactId>weld-se</artifactId>
-                <version>1.0.1-Final</version>
+                <version>2.2.16.SP1</version>
             </dependency>
 
             <dependency>