diff --git a/core/src/main/java/org/apache/struts2/components/ListUIBean.java b/core/src/main/java/org/apache/struts2/components/ListUIBean.java index 6e24e822e..ed5094198 100644 --- a/core/src/main/java/org/apache/struts2/components/ListUIBean.java +++ b/core/src/main/java/org/apache/struts2/components/ListUIBean.java @@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Array; import java.util.Collection; +import java.util.Collections; import java.util.Map; /** @@ -70,28 +71,28 @@ public abstract class ListUIBean extends UIBean { if (list instanceof String) { value = findValue((String) list); - } else if (list instanceof Collection) { - value = list; - } else if (MakeIterator.isIterable(list)) { - value = MakeIterator.convert(list); - } - if (value == null) { - if (throwExceptionOnNullValueAttribute) { - // will throw an exception if not found - value = findValue((list == null) ? (String) list : list.toString(), "list", - "The requested list key '" + list + "' could not be resolved as a collection/array/map/enumeration/iterator type. " + - "Example: people or people.{name}"); - } else { - // ww-1010, allows value with null value to be compatible with ww - // 2.1.7 behaviour - value = findValue((list == null) ? (String) list : list.toString()); + if (value == null) { + if (throwExceptionOnNullValueAttribute) { + // will throw an exception if not found + value = findValue((list == null) ? (String) list : list.toString(), "list", + "The requested list key '" + list + "' could not be resolved as a collection/array/map/enumeration/iterator type. " + + "Example: people or people.{name}"); + } else { + // ww-1010, allows value with null value to be compatible with ww + // 2.1.7 behaviour + value = findValue((list == null) ? (String) list : list.toString()); + } } + } else { + value = list; } - if (value instanceof Collection) { + if (value == null || value instanceof Iterable) { addParameter("list", value); - } else { + } else if (MakeIterator.isIterable(value)) { addParameter("list", MakeIterator.convert(value)); + } else { + addParameter("list", Collections.singletonList(value)); } if (value instanceof Collection) { @@ -107,6 +108,8 @@ public abstract class ListUIBean extends UIBean { addParameter("listKey", listKey); } else if (value instanceof Map) { addParameter("listKey", "key"); + } else { + addParameter("listKey", "top"); } if (listValueKey != null) { @@ -119,6 +122,8 @@ public abstract class ListUIBean extends UIBean { addParameter("listValue", listValue); } else if (value instanceof Map) { addParameter("listValue", "value"); + } else { + addParameter("listValue", "top"); } if (listLabelKey != null) { diff --git a/core/src/main/java/org/apache/struts2/components/OptGroup.java b/core/src/main/java/org/apache/struts2/components/OptGroup.java index 58d0b9a72..95d94d26e 100644 --- a/core/src/main/java/org/apache/struts2/components/OptGroup.java +++ b/core/src/main/java/org/apache/struts2/components/OptGroup.java @@ -127,7 +127,7 @@ public class OptGroup extends Component { } @StrutsTagAttribute(description="Set the list attribute.") - public void setList(String list) { + public void setList(Object list) { internalUiBean.setList(list); } diff --git a/core/src/main/resources/template/simple/optgroup.ftl b/core/src/main/resources/template/simple/optgroup.ftl index f1f8a3e9e..765591cca 100644 --- a/core/src/main/resources/template/simple/optgroup.ftl +++ b/core/src/main/resources/template/simple/optgroup.ftl @@ -21,27 +21,26 @@ <#if parameters.optGroupInternalListUiBeanList??> <#assign optGroupInternalListUiBeans=parameters.optGroupInternalListUiBeanList /> <#list optGroupInternalListUiBeans as optGroupInternalListUiBean> - <#if optGroupInternalListUiBean.parameters.label?has_content> - label="${optGroupInternalListUiBean.parameters.label}" + label="${optGroupInternalListUiBean.parameters.label}"<#rt> <#if optGroupInternalListUiBean.parameters.disabled!false> - disabled="disabled" + disabled="disabled"<#rt> <#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" /> > - <#list optGroupInternalListUiBean.parameters.list as optGroupBean> <#assign trash=stack.push(optGroupBean) /> <#assign tmpKey=stack.findValue(optGroupInternalListUiBean.parameters.listKey) /> <#assign tmpValue=stack.findValue(optGroupInternalListUiBean.parameters.listValue) /> <#assign tmpKeyStr = tmpKey.toString() /> - + >${tmpValue?html}<#t> + <#lt> <#assign trash=stack.pop() /> diff --git a/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java b/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java index 1067ddd16..d82a6606e 100644 --- a/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java +++ b/core/src/test/java/org/apache/struts2/views/freemarker/FreemarkerResultMockedTest.java @@ -194,6 +194,55 @@ public class FreemarkerResultMockedTest extends StrutsInternalTestCase { assertEquals(expected, stringWriter.toString()); } + public void testSequenceForSelect() throws Exception { + File file = new File(FreeMarkerResultTest.class.getResource("select.ftl").toURI()); + EasyMock.expect(servletContext.getRealPath("/tutorial/org/apache/struts2/views/freemarker/select.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/select.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/select.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/select.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/optgroup.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/optgroup.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/optgroup.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/css.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/css.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/css.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/scripting-events.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/scripting-events.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/scripting-events.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/common-attributes.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/common-attributes.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/common-attributes.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/dynamic-attributes.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/dynamic-attributes.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/dynamic-attributes.ftl")).andReturn(file.getAbsolutePath()); + + file = new File(ClassLoaderUtil.getResource("template/simple/empty.ftl", getClass()).toURI()); + EasyMock.expect(servletContext.getRealPath("/template/simple/empty.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/~~~simple/empty.ftl")).andReturn(file.getAbsolutePath()); + EasyMock.expect(servletContext.getRealPath("/template/xhtml/empty.ftl")).andReturn(file.getAbsolutePath()); + + EasyMock.replay(servletContext); + + init(); + + request.setRequestURI("/tutorial/test9.action"); + ActionMapping mapping = container.getInstance(ActionMapper.class).getMapping(request, configurationManager); + dispatcher.serviceAction(request, response, mapping); + String result = stringWriter.toString(); + assertTrue(result.contains("")); + assertTrue(result.contains("")); + assertTrue(result.contains("")); + assertTrue(result.contains("")); + assertTrue(result.contains("")); + assertTrue(result.contains("")); + } + private void init() throws MalformedURLException, URISyntaxException { stringWriter = new StringWriter(); writer = new PrintWriter(stringWriter); diff --git a/core/src/test/resources/org/apache/struts2/views/freemarker/select.ftl b/core/src/test/resources/org/apache/struts2/views/freemarker/select.ftl new file mode 100644 index 000000000..91b84db2f --- /dev/null +++ b/core/src/test/resources/org/apache/struts2/views/freemarker/select.ftl @@ -0,0 +1,28 @@ +<#-- +/* + * 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. + */ +--> +<@s.select theme="simple" list=['a','b','c'] /> +<@s.select theme="simple" list=1 /> +<@s.select theme="simple" list={'key':'value'} /> +<@s.select theme="simple"> +<@s.optgroup label="label1" list={'optgroupKey1':'optgroupValue1','optgroupKey2':'optgroupValue2'} /> +<@s.optgroup label="label2" disabled=true list=['optgroupKey3','optgroupKey4'] /> +<@s.optgroup label="label3" disabled=true list=2 /> + \ No newline at end of file diff --git a/core/src/test/resources/struts.xml b/core/src/test/resources/struts.xml index 5b29c1e87..0b370aa3e 100644 --- a/core/src/test/resources/struts.xml +++ b/core/src/test/resources/struts.xml @@ -80,6 +80,12 @@ + + + org/apache/struts2/views/freemarker/select.ftl + + +