自定义JSTL函数始终返回false

时间:2013-06-17 18:25:12

标签: java spring jstl

此代码段循环遍历testContainerCommand.testContainerLocationList的全局列表。对于每个位置,它将查看它是否存在于主对象的位置列表testContainerCommand.testContainer.testContainerLocationList中。

在这两个类中,它都是一个如下所示的属性:private Set<TestContainerLocation> testContainerLocationList = new HashSet<TestContainerLocation>(0);

当前调试显示testContainerCommand.testContainer.testContainerLocationList有两个项目

form.jsp

<p>Number of locations: ${fn:length(testContainerCommand.testContainer.testContainerLocationList)}</p>

<!-- currently shows 2 --> 

<c:forEach items="${testContainerCommand.testContainerLocationList}" var="loc" varStatus="status">

    <!-- ${cfn:containsSet(testContainerCommand.testContainer.testContainerLocationList,loc)} -->

    <c:choose>
        <c:when test="${cfn:containsSet(testContainerCommand.testContainer.testContainerLocationList,loc)}">
        </c:when>
        <c:otherwise>
        </c:otherwise>
    </c:choose>
</c:forEach>

我的custom.tld文件:

<function>
    <name>containsSet</name>
    <function-class>org.test.utils.Compare</function-class>
    <function-signature>boolean containsSet(java.util.Set,java.lang.Object)
    </function-signature>
</function>

我的Custom.java文件:

public class Compare {

    public static boolean containsSet(Set s, Object o){
        return s.contains(o);       
    }
}

TestContainer XML Hibernate映射:

...
<set name="testContainerLocationList" table="test_container_location_lookup"
 inverse="false" lazy="false" fetch="select" cascade="all">
    <key>
        <column name="id" not-null="true"/>
    </key>
    <many-to-many entity-name="org.test.vto.TestContainerLocation">
        <column name="location_id" not-null="true" />
    </many-to-many>
</set>
...

为什么它总是返回假?在比较之前我是否必须投射物体?

更新#1

我运行了以下测试代码:

public class Main {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().openSession();
        try{
            List<TestContainerLocation> testContainerLocationList = session.createQuery("from TestContainerLocation").list();
            TestContainer testContainer = (TestContainer)session.createQuery("from TestContainer where id = 12").list().get(0);

            for(TestContainerLocation l: testContainerLocationList){
                System.out.println(Compare.containsSet(testContainer.getTestContainerLocationList(), l));
            }
        }
        catch(RuntimeException e){
            e.printStackTrace();    
        }
        session.close();

    }
}

哪个输出(如预期的那样):

true
true
false
false
false

更新#2

网络流文件:

<view-state id="form" view="/dbtest/form" model="testContainerCommand">
    <on-entry>
        <evaluate
            expression="testContainerAction.getTestContainer(testContainerCommand, flowRequestContext)" />
        <evaluate
            expression="testContainerAction.getTestContainerLocationList(testContainerCommand, flowRequestContext)" />
    </on-entry>
    <transition on="submit" to="saveForm" />
    <transition on="display" to="display" />
</view-state>

TestContainerAction.java

public void getTestContainer(TestContainerCommand cmd, RequestContext requestContext) throws Exception{

        HttpServletRequest request = (HttpServletRequest) requestContext.getExternalContext().getNativeRequest();

        //get param
        String id = request.getParameter("id");

        //param present
        if(! StringUtils.isEmpty(id) && StringUtils.isNumeric(id)){
            cmd.setTestContainer(testContainerDao.getTestContainerById(Long.parseLong(id)));
        }
        //no param
        else{
            TestContainer t = new TestContainer();
            t.setTestContainerType(new TestContainerType());
            t.setTestContainerLocationList(new HashSet<TestContainerLocation>(0));
            cmd.setTestContainer(t);
        }

        cmd.setTestContainerTypeList(testContainerTypeDao.getTestContainerTypeList());
        cmd.setTestContainerLocationList(testContainerLocationDao.getTestContainerLocationList());
    }

public List<TestContainerLocation> getTestContainerLocationList(TestContainerCommand cmd, RequestContext requestContext) throws Exception{
        cmd.setTestContainerLocationList(testContainerLocationDao.getTestContainerLocationList());
        return cmd.getTestContainerLocationList();
    }

更新#3

TestContainerLocation类:

public class TestContainerLocation implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -1381290537575465609L;

    private Integer locationId;
    private String locationName;
    private Set<TestContainer> testContainer = new HashSet<TestContainer>(0);

    public Integer getLocationId() {
        return locationId;
    }
    public void setLocationId(Integer locationId) {
        this.locationId = locationId;
    }
    public String getLocationName() {
        return locationName;
    }
    public void setLocationName(String locationName) {
        this.locationName = locationName;
    }
    public Set<TestContainer> getTestContainer() {
        return testContainer;
    }
    public void setTestContainer(Set<TestContainer> testContainer) {
        this.testContainer = testContainer;
    }


}

我找到了一个似乎在谈论DPM所说的网站: http://javarevisited.blogspot.ca/2011/02/how-to-write-equals-method-in-java.html

以下是我之前缩写为forEach的内容:

<ul>
        <c:forEach items="${testContainerCommand.testContainerLocationList}" var="loc" varStatus="status">
            <!-- ${cfn:containsSet(testContainerCommand.testContainer.testContainerLocationList,loc)} -->
            <c:choose>
                <c:when test="${cfn:containsSet(testContainerCommand.testContainer.testContainerLocationList,loc)}">
                    <li><input type="checkbox" id="location${loc.locationId}" name="location"
                        value="${loc.locationId}" 
                        checked="checked" />
                        <label for="location${loc.locationId}">${loc.locationName}</label></li>
                </c:when>
                <c:otherwise>
                    <li><input type="checkbox" id="location${loc.locationId}" name="location"
                        value="${loc.locationId}" />
                        <label for="location${loc.locationId}">${loc.locationName}</label></li>
                </c:otherwise>
            </c:choose>
        </c:forEach>
    </ul>

更新#4

新的比较函数,对传入的对象执行简单的toString():

public class Compare {

    private static Logger logger = Logger.getLogger(Compare.class);

    public static boolean containsSet(Set s, Object o){

        logger.info(s.toString()+":"+o.toString());

        return s.contains(o);       
    }
}

所述记录的输出:

INFO : org.test.utils.Compare - [org.test.vto.TestContainerLocation@6c5bdfae, org.test.vto.TestContainerLocation@6a7be687]:org.test.vto.TestContainerLocation@13de6be9
INFO : org.test.utils.Compare - [org.test.vto.TestContainerLocation@6c5bdfae, org.test.vto.TestContainerLocation@6a7be687]:org.test.vto.TestContainerLocation@6f7e982f
INFO : org.test.utils.Compare - [org.test.vto.TestContainerLocation@6c5bdfae, org.test.vto.TestContainerLocation@6a7be687]:org.test.vto.TestContainerLocation@60396ed8
INFO : org.test.utils.Compare - [org.test.vto.TestContainerLocation@6c5bdfae, org.test.vto.TestContainerLocation@6a7be687]:org.test.vto.TestContainerLocation@5a9c5842
INFO : org.test.utils.Compare - [org.test.vto.TestContainerLocation@6c5bdfae, org.test.vto.TestContainerLocation@6a7be687]:org.test.vto.TestContainerLocation@4e668387

解决方案:

根据公认的解决方案,我只需要覆盖TestContainerLocation类中的equals和hashCode方法。

@Override
public boolean equals(Object obj) {
    if(this == obj)
        return true;
    if(obj == null)
        return false;
    if(getClass() != obj.getClass())
        return false;

    TestContainerLocation in = (TestContainerLocation) obj;

    return  getLocationId() == in.getLocationId() 
            && (getLocationName() == in.getLocationName() 
            || (getLocationName() != null && getLocationName().equals(in.getLocationName())));
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;

    result = prime * result + ((getLocationId() == null) ? 0 : Long.valueOf(getLocationId()).hashCode());
    result = prime * result + ((getLocationName() == null) ? 0 : getLocationName().hashCode());

    return result;
}

1 个答案:

答案 0 :(得分:1)

您应该发布TestContainerLocation类,这有助于回答这个问题。看起来你可能没有重写equals()或hashCode()。 TestContainerLocation将使用这些的Object实现,因此来自update 1的java示例代码可以工作(它们实际上是相同的对象),但是如果你在不同的时间从hibernate中检索对象,它们将不是Object.equal ,来自JSP的调用将返回false。