浏览 6255 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-11-28
最后修改:2008-11-28
昨晚下载了Struts2的源码,调试了一下,找到原因所在,应该是Struts2的一个Bug,修改了Struts2的一个类,问题解决。 因为解决了这个问题,对我来说,意义非常大,所以,我认为对其他朋友肯定也有意义,下文公开这个方法,希望能对大家起到帮助。 1、背景 做一个util.ftl文件,在里面定义一些常用Hash变量,如性别、分类、职业等, 然后在实际业务的ftl文件中,import这个util.ftl文件,将Hash变量赋值给Struts2的标签。 类似下面的代码:util.ftl文件 <#assign yearlist=[]> <#assign monthlist=1..12> <#assign daylist=1..31> <#macro year start=1910 end=2008> <#list end..start as item> <#assign yearlist = yearlist + [item]> </#list> </#macro> <#-- 网站Hash --> <#assign homepageMap={"ipcat.cn":"IP猫", "ourbooks.cn":"我们的书", "hulian56.com":"互联物流", "qilu56.com":"齐鲁物流" }> 然后,在实际业务的ftl文件中,象下面一样引用。 <#import "*/common/util.ftl" as util> <html> <head> <title>注册</title> </head> <body> <p> <label class="f-label" for="user.occupation">网站</label> <@s.select cssClass="f-select" id="user.homepage" name="user.homepage" list=util.homepageMap required="true" /> </p> </body> </html> 代码区加不了颜色,请大家直接注意homepageMap这个变量吧。 2、问题 如果象以上那样来使用FreeMarker的Hash(散列),在目前的情况下,势必出现下面样的问题: 也就是大家会看到FreeMarker的Hash变成了一串如freemarker.ext.beans.HashAdapter$1$1$1@6e90fb8e样的东东。 3、问题分析及解决之法 通过对Struts2源码的Debug,发现了问题所在,大家可以找到Struts2的如下类: org.apache.struts2.components.ListUIBean 。 当FreeMarker的Hash被传入后,类型是FreeMarker的HashAdapter类,当执行到ListUIBean类的第74行时,MakeIterator.isIterable(list)是true,这样传入的HashAdapter类型的list被MakeIterator类转换为Iterator类对象了,但是不幸的是第75行直接把转换后的Iterator对象赋给了value,这样的结果是导致后面一系统对Map类型变量进行的处理均无法对value对象进行处理了,因为此时的value已经不是Map,而是Iterator了。 虽然第94行,通过MakeIterator.convert处理时,不会对Iterator类型的value再次进行转换,但,接下来针对value的任何应该的处理都没了。这个错恰恰因为第75行的严重败笔! 正是因为这一行的失败处理,作为FreeMarker传入的Hash被搞成了个Iterator型的变量,在接下来的向值栈存储内容时,也会存放错误的内容(向值栈存放信息部分我没看,但是根据推测,肯定由于listKey和listValue没有正确设定,所以值栈中存放的格式肯定有问题),输出的时候也显示的是错误的内容。 经过上面的分析,相信大家已经明白如何改了,对,就是直接将75行这句改一下就可以了。 原来:value = MakeIterator.convert(list); 改为:value = list; 可以在工程的src目录下建立该类的包:org.apache.struts2.components, 将改后的ListUIBean类改后,拷贝进去,编译后,运行系统,大家会发现FreeMarker的Hash终于正常工作了。 至于为什么定义为OGNL格式的Hash可以正常工作,大家可以Debug下源代码,其实对于OGNL的Hash到ListUIBean类时,还只是一个字符串,只是经过findValue后,OGNL会自动转为Hash,所以可以正常工作,这样,实际上走的是ListUIBean类的第70和71行,而不会执行第75行,所以不会有问题。 正常工作后的载图: 希望以上的分析和解决之法对大家能有所帮助,写的不对之处,还请批评。 jar包的版本:Struts 2.12 FreeMarker 2.3.14 我是在以述版本上分析的,但实际上struts-2.0.14上也不行。 下附org.apache.struts2.components.ListUIBean类的上半部分源代码(没有变更过的)。 /* * $Id: ListUIBean.java 651946 2008-04-27 13:41:38Z apetrelli $ * * 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.components; import java.lang.reflect.Array; import java.util.Collection; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.views.annotations.StrutsTagAttribute; import org.apache.struts2.util.ContainUtil; import org.apache.struts2.util.MakeIterator; import com.opensymphony.xwork2.util.ValueStack; /** * DoubleListUIBean is the standard superclass of all Struts list handling components. * * <p/> * * <!-- START SNIPPET: javadoc --> * * Note that the listkey and listvalue attribute will default to "key" and "value" * respectively only when the list attribute is evaluated to a Map or its decendant. * Other thing else, will result in listkey and listvalue to be null and not used. * * <!-- END SNIPPET: javadoc --> * */ public abstract class ListUIBean extends UIBean { protected Object list; protected String listKey; protected String listValue; // indicate if an exception is to be thrown when value attribute is null protected boolean throwExceptionOnNullValueAttribute = false; protected ListUIBean(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); } public void evaluateExtraParams() { Object value = null; if (list == null) { list = parameters.get("list"); } 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 instanceof Collection) { addParameter("list", value); } else { addParameter("list", MakeIterator.convert(value)); } if (value instanceof Collection) { addParameter("listSize", Integer.valueOf(((Collection) value).size())); } else if (value instanceof Map) { addParameter("listSize", Integer.valueOf(((Map) value).size())); } else if (value != null && value.getClass().isArray()) { addParameter("listSize", Integer.valueOf(Array.getLength(value))); } if (listKey != null) { addParameter("listKey", listKey); } else if (value instanceof Map) { addParameter("listKey", "key"); } if (listValue != null) { if (altSyntax()) { // the same logic as with findValue(String) // if value start with %{ and end with }, just cut it off! if (listValue.startsWith("%{") && listValue.endsWith("}")) { listValue = listValue.substring(2, listValue.length() - 1); } } addParameter("listValue", listValue); } else if (value instanceof Map) { addParameter("listValue", "value"); } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |