mirror of
https://github.com/apache/struts.git
synced 2026-08-11 01:27:14 +00:00
WW-1830 Support non-String attributes to freemarker JSP tag extensions
* port from fix on WebWork rev 2866 git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/branches/STRUTS_2_0_X@539660 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -31,15 +31,16 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.struts2.components.ActionComponent;
|
||||
import org.apache.struts2.components.Component;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
import freemarker.template.DefaultObjectWrapper;
|
||||
import freemarker.template.SimpleNumber;
|
||||
import freemarker.template.SimpleSequence;
|
||||
import freemarker.template.TemplateModel;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import freemarker.template.TemplateTransformModel;
|
||||
|
||||
@@ -56,18 +57,48 @@ public abstract class TagModel implements TemplateTransformModel {
|
||||
this.res = res;
|
||||
}
|
||||
|
||||
public Writer getWriter(Writer writer, Map params) throws TemplateModelException, IOException {
|
||||
public Writer getWriter(Writer writer, Map params)
|
||||
throws TemplateModelException, IOException {
|
||||
Component bean = getBean();
|
||||
Container container = Dispatcher.getInstance().getConfigurationManager().getConfiguration().getContainer();
|
||||
container.inject(bean);
|
||||
Map basicParams = convertParams(params);
|
||||
bean.copyParams(basicParams);
|
||||
bean.addAllParameters(getComplexParams(params));
|
||||
|
||||
Map unwrappedParameters = unwrapParameters(params);
|
||||
bean.copyParams(unwrappedParameters);
|
||||
|
||||
return new CallbackWriter(bean, writer);
|
||||
}
|
||||
|
||||
protected abstract Component getBean();
|
||||
|
||||
protected Map unwrapParameters(Map params) {
|
||||
Map map = new HashMap(params.size());
|
||||
DefaultObjectWrapper objectWrapper = new DefaultObjectWrapper();
|
||||
for (Iterator iterator = params.entrySet().iterator(); iterator.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
|
||||
Object value = entry.getValue();
|
||||
|
||||
if (value != null) {
|
||||
// the value should ALWAYS be a decendant of TemplateModel
|
||||
if (value instanceof TemplateModel) {
|
||||
try {
|
||||
map.put(entry.getKey(), objectWrapper
|
||||
.unwrap((TemplateModel) value));
|
||||
} catch (TemplateModelException e) {
|
||||
LOG.error("failed to unwrap [" + value
|
||||
+ "] it will be ignored", e);
|
||||
}
|
||||
}
|
||||
// if it doesn't, we'll do it the old way by just returning the toString() representation
|
||||
else {
|
||||
map.put(entry.getKey(), value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
protected Map convertParams(Map params) {
|
||||
HashMap map = new HashMap(params.size());
|
||||
for (Iterator iterator = params.entrySet().iterator(); iterator.hasNext();) {
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* 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 org.apache.struts2.views.freemarker.tags;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.StrutsTestCase;
|
||||
import org.apache.struts2.components.Component;
|
||||
import org.apache.struts2.views.freemarker.tags.TagModel;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import com.opensymphony.xwork2.util.OgnlValueStack;
|
||||
|
||||
import freemarker.ext.util.WrapperTemplateModel;
|
||||
import freemarker.template.AdapterTemplateModel;
|
||||
import freemarker.template.TemplateBooleanModel;
|
||||
import freemarker.template.TemplateCollectionModel;
|
||||
import freemarker.template.TemplateHashModel;
|
||||
import freemarker.template.TemplateModel;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import freemarker.template.TemplateModelIterator;
|
||||
import freemarker.template.TemplateNumberModel;
|
||||
import freemarker.template.TemplateScalarModel;
|
||||
import freemarker.template.TemplateSequenceModel;
|
||||
|
||||
public class TagModelTest extends StrutsTestCase {
|
||||
|
||||
final Object ADAPTER_TEMPLATE_MODEL_CONTAINED_OBJECT = new Object();
|
||||
final Object WRAPPING_TEMPLATE_MODEL_CONTAINED_OBJECT = new Object();
|
||||
|
||||
public void testUnwrapMap() throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
OgnlValueStack stack = new OgnlValueStack();
|
||||
|
||||
Map params = new LinkedHashMap();
|
||||
|
||||
// Try to test out the commons Freemarker's Template Model
|
||||
|
||||
// TemplateBooleanModel
|
||||
params.put("property1", new TemplateBooleanModel() {
|
||||
public boolean getAsBoolean() throws TemplateModelException {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
params.put("property2", new TemplateBooleanModel() {
|
||||
public boolean getAsBoolean() throws TemplateModelException {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateScalarModel
|
||||
params.put("property3", new TemplateScalarModel() {
|
||||
public String getAsString() throws TemplateModelException {
|
||||
return "toby";
|
||||
}
|
||||
});
|
||||
params.put("property4", new TemplateScalarModel() {
|
||||
public String getAsString() throws TemplateModelException {
|
||||
return "phil";
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateNumberModel
|
||||
params.put("property5", new TemplateNumberModel() {
|
||||
public Number getAsNumber() throws TemplateModelException {
|
||||
return new Integer("10");
|
||||
}
|
||||
});
|
||||
params.put("property6", new TemplateNumberModel() {
|
||||
public Number getAsNumber() throws TemplateModelException {
|
||||
return new Float("1.1");
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateHashModel
|
||||
params.put("property7", new TemplateHashModel() {
|
||||
public TemplateModel get(String arg0) throws TemplateModelException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEmpty() throws TemplateModelException {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateSequenceModel
|
||||
params.put("property8", new TemplateSequenceModel() {
|
||||
public TemplateModel get(int arg0) throws TemplateModelException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size() throws TemplateModelException {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateCollectionModel
|
||||
params.put("property9", new TemplateCollectionModel() {
|
||||
public TemplateModelIterator iterator() throws TemplateModelException {
|
||||
return new TemplateModelIterator() {
|
||||
private Iterator i;
|
||||
{
|
||||
i = Collections.EMPTY_LIST.iterator();
|
||||
}
|
||||
|
||||
public boolean hasNext() throws TemplateModelException {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
public TemplateModel next() throws TemplateModelException {
|
||||
return (TemplateModel) i.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// AdapterTemplateModel
|
||||
params.put("property10", new AdapterTemplateModel() {
|
||||
public Object getAdaptedObject(Class arg0) {
|
||||
return ADAPTER_TEMPLATE_MODEL_CONTAINED_OBJECT;
|
||||
}
|
||||
});
|
||||
|
||||
// WrapperTemplateModel
|
||||
params.put("property11", new WrapperTemplateModel() {
|
||||
public Object getWrappedObject() {
|
||||
return WRAPPING_TEMPLATE_MODEL_CONTAINED_OBJECT;
|
||||
}
|
||||
});
|
||||
|
||||
TagModel tagModel = new TagModel(stack, request, response) {
|
||||
protected Component getBean() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Map result = tagModel.unwrapParameters(params);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(result.size(), 11);
|
||||
assertEquals(result.get("property1"), Boolean.TRUE);
|
||||
assertEquals(result.get("property2"), Boolean.FALSE);
|
||||
assertEquals(result.get("property3"), "toby");
|
||||
assertEquals(result.get("property4"), "phil");
|
||||
assertEquals(result.get("property5"), new Integer(10));
|
||||
assertEquals(result.get("property6"), new Float(1.1));
|
||||
assertNotNull(result.get("property7"));
|
||||
assertTrue(result.get("property7") instanceof Map);
|
||||
assertNotNull(result.get("property8"));
|
||||
assertTrue(result.get("property8") instanceof Collection);
|
||||
assertNotNull(result.get("property9"));
|
||||
assertTrue(result.get("property9") instanceof Collection);
|
||||
assertEquals(result.get("property10"),
|
||||
ADAPTER_TEMPLATE_MODEL_CONTAINED_OBJECT);
|
||||
assertEquals(result.get("property11"),
|
||||
WRAPPING_TEMPLATE_MODEL_CONTAINED_OBJECT);
|
||||
}
|
||||
|
||||
public void testGetWriter() throws Exception {
|
||||
|
||||
OgnlValueStack stack = new OgnlValueStack();
|
||||
|
||||
final InternalBean bean = new InternalBean(stack);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map params = new LinkedHashMap();
|
||||
|
||||
// Try to test out the commons Freemarker's Template Model
|
||||
|
||||
// TemplateBooleanModel
|
||||
params.put("property1", new TemplateBooleanModel() {
|
||||
public boolean getAsBoolean() throws TemplateModelException {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
params.put("property2", new TemplateBooleanModel() {
|
||||
public boolean getAsBoolean() throws TemplateModelException {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateScalarModel
|
||||
params.put("property3", new TemplateScalarModel() {
|
||||
public String getAsString() throws TemplateModelException {
|
||||
return "toby";
|
||||
}
|
||||
});
|
||||
params.put("property4", new TemplateScalarModel() {
|
||||
public String getAsString() throws TemplateModelException {
|
||||
return "phil";
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateNumberModel
|
||||
params.put("property5", new TemplateNumberModel() {
|
||||
public Number getAsNumber() throws TemplateModelException {
|
||||
return new Integer("10");
|
||||
}
|
||||
});
|
||||
params.put("property6", new TemplateNumberModel() {
|
||||
public Number getAsNumber() throws TemplateModelException {
|
||||
return new Float("1.1");
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateHashModel
|
||||
params.put("property7", new TemplateHashModel() {
|
||||
public TemplateModel get(String arg0) throws TemplateModelException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEmpty() throws TemplateModelException {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateSequenceModel
|
||||
params.put("property8", new TemplateSequenceModel() {
|
||||
public TemplateModel get(int arg0) throws TemplateModelException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size() throws TemplateModelException {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
// TemplateCollectionModel
|
||||
params.put("property9", new TemplateCollectionModel() {
|
||||
public TemplateModelIterator iterator() throws TemplateModelException {
|
||||
return new TemplateModelIterator() {
|
||||
private Iterator i;
|
||||
{
|
||||
i = Collections.EMPTY_LIST.iterator();
|
||||
}
|
||||
|
||||
public boolean hasNext() throws TemplateModelException {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
public TemplateModel next() throws TemplateModelException {
|
||||
return (TemplateModel) i.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// AdapterTemplateModel
|
||||
params.put("property10", new AdapterTemplateModel() {
|
||||
public Object getAdaptedObject(Class arg0) {
|
||||
return ADAPTER_TEMPLATE_MODEL_CONTAINED_OBJECT;
|
||||
}
|
||||
});
|
||||
|
||||
// WrapperTemplateModel
|
||||
params.put("property11", new WrapperTemplateModel() {
|
||||
public Object getWrappedObject() {
|
||||
return WRAPPING_TEMPLATE_MODEL_CONTAINED_OBJECT;
|
||||
}
|
||||
});
|
||||
|
||||
TagModel tagModel = new TagModel(stack, request, response) {
|
||||
protected Component getBean() {
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
|
||||
tagModel.getWriter(new StringWriter(), params);
|
||||
|
||||
assertNotNull(bean);
|
||||
assertEquals(bean.getProperty1(), true);
|
||||
assertEquals(bean.getProperty2(), false);
|
||||
assertEquals(bean.getProperty3(), "toby");
|
||||
assertEquals(bean.getProperty4(), "phil");
|
||||
assertEquals(bean.getProperty5(), new Integer(10));
|
||||
assertEquals(bean.getProperty6(), new Float(1.1));
|
||||
assertNotNull(bean.getProperty7());
|
||||
assertTrue(bean.getProperty7() instanceof Map);
|
||||
assertNotNull(bean.getProperty8());
|
||||
assertTrue(bean.getProperty8() instanceof Collection);
|
||||
assertNotNull(bean.getProperty9());
|
||||
assertTrue(bean.getProperty9() instanceof Collection);
|
||||
assertEquals(bean.getProperty10(), ADAPTER_TEMPLATE_MODEL_CONTAINED_OBJECT);
|
||||
assertEquals(bean.getProperty11(), WRAPPING_TEMPLATE_MODEL_CONTAINED_OBJECT);
|
||||
}
|
||||
|
||||
public static class InternalBean extends Component {
|
||||
|
||||
public InternalBean(OgnlValueStack stack) {
|
||||
super(stack);
|
||||
}
|
||||
|
||||
private boolean property1 = false; // inverse of the expected result, so we could test that it works
|
||||
private boolean property2 = true; // inverse of the expected result, so we could test that it works
|
||||
|
||||
private String property3;
|
||||
private String property4;
|
||||
|
||||
private Integer property5;
|
||||
private Float property6;
|
||||
|
||||
private Map property7;
|
||||
private Collection property8;
|
||||
private Collection property9;
|
||||
|
||||
private Object property10;
|
||||
private Object property11;
|
||||
|
||||
public void setProperty1(boolean property1) {
|
||||
this.property1 = property1;
|
||||
}
|
||||
|
||||
public boolean getProperty1() {
|
||||
return property1;
|
||||
}
|
||||
|
||||
public void setProperty2(boolean property2) {
|
||||
this.property2 = property2;
|
||||
}
|
||||
|
||||
public boolean getProperty2() {
|
||||
return property2;
|
||||
}
|
||||
|
||||
public void setProperty3(String property3) {
|
||||
this.property3 = property3;
|
||||
}
|
||||
|
||||
public String getProperty3() {
|
||||
return this.property3;
|
||||
}
|
||||
|
||||
public void setProperty4(String property4) {
|
||||
this.property4 = property4;
|
||||
}
|
||||
|
||||
public String getProperty4() {
|
||||
return this.property4;
|
||||
}
|
||||
|
||||
public void setProperty5(Integer property5) {
|
||||
this.property5 = property5;
|
||||
}
|
||||
|
||||
public Integer getProperty5() {
|
||||
return this.property5;
|
||||
}
|
||||
|
||||
public void setProperty6(Float property6) {
|
||||
this.property6 = property6;
|
||||
}
|
||||
|
||||
public Float getProperty6() {
|
||||
return this.property6;
|
||||
}
|
||||
|
||||
public void setProperty7(Map property7) {
|
||||
this.property7 = property7;
|
||||
}
|
||||
|
||||
public Map getProperty7() {
|
||||
return property7;
|
||||
}
|
||||
|
||||
public void setProperty8(Collection property8) {
|
||||
this.property8 = property8;
|
||||
}
|
||||
|
||||
public Collection getProperty8() {
|
||||
return property8;
|
||||
}
|
||||
|
||||
public void setProperty9(Collection property9) {
|
||||
this.property9 = property9;
|
||||
}
|
||||
|
||||
public Collection getProperty9() {
|
||||
return this.property9;
|
||||
}
|
||||
|
||||
public void setProperty10(Object property10) {
|
||||
this.property10 = property10;
|
||||
}
|
||||
|
||||
public Object getProperty10() {
|
||||
return this.property10;
|
||||
}
|
||||
|
||||
public void setProperty11(Object property11) {
|
||||
this.property11 = property11;
|
||||
}
|
||||
|
||||
public Object getProperty11() {
|
||||
return this.property11;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user