Merge pull request #931 from apache/fix/WW-5422-trimable
WW-5422 Fixes support for trimable locale string in request
diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java b/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java
index 8c7e15e..ab1a180 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ActionSupport.java
@@ -91,6 +91,11 @@
}
@Override
+ public Locale toLocale(String localeStr) {
+ return getLocaleProvider().toLocale(localeStr);
+ }
+
+ @Override
public boolean hasKey(String key) {
return getTextProvider().hasKey(key);
}
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java b/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java
index da89306..35f1619 100644
--- a/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultLocaleProvider.java
@@ -46,17 +46,23 @@
@Override
public boolean isValidLocaleString(String localeStr) {
+ Locale locale = this.toLocale(localeStr);
+ return isValidLocale(locale);
+ }
+
+ @Override
+ public boolean isValidLocale(Locale locale) {
+ return locale != null && LocaleUtils.isAvailableLocale(locale);
+ }
+
+ @Override
+ public Locale toLocale(String localeStr) {
Locale locale = null;
try {
locale = LocaleUtils.toLocale(StringUtils.trimToNull(localeStr));
} catch (IllegalArgumentException e) {
LOG.warn(new ParameterizedMessage("Cannot convert [{}] to proper locale", localeStr), e);
}
- return isValidLocale(locale);
- }
-
- @Override
- public boolean isValidLocale(Locale locale) {
- return LocaleUtils.isAvailableLocale(locale);
+ return locale;
}
}
diff --git a/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java b/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java
index 67972af..00a41a2 100644
--- a/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/LocaleProvider.java
@@ -18,6 +18,9 @@
*/
package com.opensymphony.xwork2;
+import org.apache.commons.lang3.LocaleUtils;
+import org.apache.commons.lang3.StringUtils;
+
import java.util.Locale;
@@ -58,4 +61,17 @@
*/
boolean isValidLocale(Locale locale);
+ /**
+ * Tries to convert provided locale string into {@link Locale} or returns null
+ * @param localeStr a String representing locale, e.g.: en_EN
+ * @return instance of {@link Locale} or null
+ * @since Struts 6.5.0
+ */
+ default Locale toLocale(String localeStr) {
+ try {
+ return LocaleUtils.toLocale(StringUtils.trimToNull(localeStr));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
}
diff --git a/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java b/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java
index 5c7f2c1..bc8c888 100644
--- a/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java
+++ b/core/src/main/java/com/opensymphony/xwork2/validator/DelegatingValidatorContext.java
@@ -122,10 +122,15 @@
return localeProvider.isValidLocale(locale);
}
+ @Override
+ public Locale toLocale(String localeStr) {
+ return localeProvider.toLocale(localeStr);
+ }
+
public boolean hasKey(String key) {
return textProvider.hasKey(key);
}
-
+
public String getText(String aTextName) {
return textProvider.getText(aTextName);
}
@@ -280,6 +285,11 @@
public boolean isValidLocale(Locale locale) {
return getLocaleProvider().isValidLocale(locale);
}
+
+ @Override
+ public Locale toLocale(String localeStr) {
+ return getLocaleProvider().toLocale(localeStr);
+ }
}
/**
diff --git a/core/src/main/java/org/apache/struts2/interceptor/I18nInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/I18nInterceptor.java
index e0f978f..6bce042 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/I18nInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/I18nInterceptor.java
@@ -24,7 +24,6 @@
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.TextParseUtil;
-import org.apache.commons.lang3.LocaleUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
@@ -85,7 +84,7 @@
}
public void setLocaleStorage(String storageName) {
- if (storageName == null || "".equals(storageName)) {
+ if (storageName == null || storageName.isEmpty()) {
this.storage = Storage.ACCEPT_LANGUAGE;
} else {
try {
@@ -169,27 +168,21 @@
}
/**
- * Creates a Locale object from the request param, which might
- * be already a Local or a String
+ * Creates a Locale object from the request param
*
* @param requestedLocale the parameter from the request
- * @return the Locale
+ * @return instance of {@link Locale} or null
*/
- protected Locale getLocaleFromParam(Object requestedLocale) {
+ protected Locale getLocaleFromParam(String requestedLocale) {
LocaleProvider localeProvider = localeProviderFactory.createLocaleProvider();
Locale locale = null;
if (requestedLocale != null) {
- if (requestedLocale instanceof Locale) {
- locale = (Locale) requestedLocale;
- } else {
- String localeStr = requestedLocale.toString();
- if (localeProvider.isValidLocaleString(localeStr)) {
- locale = LocaleUtils.toLocale(localeStr);
- } else {
- locale = localeProvider.getLocale();
- }
+ locale = localeProvider.toLocale(requestedLocale);
+ if (locale == null) {
+ locale = localeProvider.getLocale();
}
+
if (locale != null) {
LOG.debug("Found locale: {}", locale);
}
@@ -285,7 +278,7 @@
@Override
@SuppressWarnings("rawtypes")
public Locale find() {
- if (supportedLocale.size() > 0) {
+ if (!supportedLocale.isEmpty()) {
Enumeration locales = actionInvocation.getInvocationContext().getServletRequest().getLocales();
while (locales.hasMoreElements()) {
Locale locale = (Locale) locales.nextElement();
diff --git a/core/src/test/java/com/opensymphony/xwork2/DefaultLocaleProviderTest.java b/core/src/test/java/com/opensymphony/xwork2/DefaultLocaleProviderTest.java
new file mode 100644
index 0000000..bb5178a
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/DefaultLocaleProviderTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Locale;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class DefaultLocaleProviderTest {
+
+ private DefaultLocaleProvider provider;
+
+ @Before
+ public void setUp() throws Exception {
+ provider = new DefaultLocaleProvider();
+ }
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ ActionContext.of().bind();
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ ActionContext.clear();
+ }
+
+ @Test
+ public void getLocale() {
+ // given
+ ActionContext.getContext().withLocale(Locale.ITALY);
+
+ // when
+ Locale actual = provider.getLocale();
+
+ // then
+ assertEquals(Locale.ITALY, actual);
+ }
+
+ @Test
+ public void getLocaleNull() {
+ // given
+ ActionContext backup = ActionContext.getContext();
+ ActionContext.clear();
+
+ // when
+ Locale actual = provider.getLocale();
+
+ // then
+ assertNull(actual);
+ ActionContext.bind(backup);
+ }
+
+ @Test
+ public void toLocale() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ Locale actual = provider.toLocale("it");
+
+ // then
+ assertEquals(Locale.ITALIAN, actual);
+ }
+
+ @Test
+ public void toLocaleFull() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ Locale actual = provider.toLocale("it_IT");
+
+ // then
+ assertEquals(Locale.ITALY, actual);
+ }
+
+ @Test
+ public void toLocaleTrimEndOfLine() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ Locale actual = provider.toLocale("it_IT\n");
+
+ // then
+ assertEquals(Locale.ITALY, actual);
+ }
+
+ @Test
+ public void toLocaleTrimEmptySpace() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ Locale actual = provider.toLocale(" it_IT ");
+
+ // then
+ assertEquals(Locale.ITALY, actual);
+ }
+
+ @Test
+ public void isValidLocaleNull() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ boolean actual = provider.isValidLocale(null);
+
+ // then
+ assertFalse(actual);
+ }
+
+ @Test
+ public void isValidLocale() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ boolean actual = provider.isValidLocale(Locale.ITALIAN);
+
+ // then
+ assertTrue(actual);
+ }
+
+ @Test
+ public void isValidLocaleString() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ boolean actual = provider.isValidLocaleString("it");
+
+ // then
+ assertTrue(actual);
+ }
+
+ @Test
+ public void isValidLocaleStringNot() {
+ // given
+ ActionContext.getContext().withLocale(Locale.GERMAN);
+
+ // when
+ boolean actual = provider.isValidLocaleString("italy");
+
+ // then
+ assertFalse(actual);
+ }
+
+}
diff --git a/core/src/test/java/com/opensymphony/xwork2/LocaleProviderTest.java b/core/src/test/java/com/opensymphony/xwork2/LocaleProviderTest.java
new file mode 100644
index 0000000..03e05f5
--- /dev/null
+++ b/core/src/test/java/com/opensymphony/xwork2/LocaleProviderTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import org.junit.Test;
+
+import java.util.Locale;
+
+import static org.junit.Assert.*;
+
+public class LocaleProviderTest {
+
+ @Test
+ public void toLocale() {
+ // given
+ DummyLocale locale = new DummyLocale();
+
+ // when
+ Locale actual = locale.toLocale("de");
+
+ // then
+ assertEquals(Locale.GERMAN, actual);
+ }
+
+ @Test
+ public void toLocaleTrim() {
+ // given
+ DummyLocale locale = new DummyLocale();
+
+ // when
+ Locale actual = locale.toLocale(" de_DE ");
+
+ // then
+ assertEquals(Locale.GERMANY, actual);
+ }
+
+ @Test
+ public void toLocaleNull() {
+ // given
+ DummyLocale locale = new DummyLocale();
+
+ // when
+ Locale actual = locale.toLocale("germany");
+
+ // then
+ assertNull(actual);
+ }
+
+}
+
+class DummyLocale implements LocaleProvider {
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public boolean isValidLocaleString(String localeStr) {
+ return false;
+ }
+
+ @Override
+ public boolean isValidLocale(Locale locale) {
+ return false;
+ }
+}
diff --git a/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java
index a8fd842..604d61b 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java
@@ -147,6 +147,26 @@
assertEquals(Locale.getDefault(), session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
}
+ public void testTrimableLocaleString1() throws Exception {
+ prepare(I18nInterceptor.DEFAULT_PARAMETER, "de\n");
+
+ interceptor.intercept(mai);
+
+ assertFalse(mai.getInvocationContext().getParameters().get(I18nInterceptor.DEFAULT_PARAMETER).isDefined()); // should have been removed
+ assertNotNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should be stored here
+ assertEquals(Locale.GERMAN, session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
+ }
+
+ public void testTrimableLocaleString2() throws Exception {
+ prepare(I18nInterceptor.DEFAULT_PARAMETER, "de ");
+
+ interceptor.intercept(mai);
+
+ assertFalse(mai.getInvocationContext().getParameters().get(I18nInterceptor.DEFAULT_PARAMETER).isDefined()); // should have been removed
+ assertNotNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should be stored here
+ assertEquals(Locale.GERMAN, session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
+ }
+
public void testWithVariant() throws Exception {
prepare(I18nInterceptor.DEFAULT_PARAMETER, "ja_JP_JP");
interceptor.intercept(mai);