从JSP访问HashMultimap时出现异常的原因是什么



我有一个Spring MVC控制器,它将Guava HashMultimap添加到作用域/模型中。然后JSP读取该数据结构以显示每个应用程序的角色列表:

控制器内:

HashMultimap<Long,Role> rolesByApp = HashMultimap.create();
//... fill the multimap
model.addAttribute("rolesByApp", rolesByApp);

在JSP:中

<c:forEach items="${applications}" var="app" varStatus="s1">
    <c:set var="appRoles" value="${rolesByApp.get(app.id)}"/>
    <!-- for each role display a checkbox, etc. -->
</c:forEach>

当我尝试从HashMultiMap:读取时,我在JSP的c:set行上得到了一个IllegalAccessException

java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a member of class com.google.common.collect.AbstractSetMultimap with modifiers "public volatile"

这种情况并不总是发生,可能在我的开发机器(Mac)上发生了四分之三。在服务器上,它一直运行良好(Red Hat Linux)。它过去在我的开发机器上也很好用,当时我正在开发它,我在Win7下。

如果我用HashMap<Long, List<Role>>替换HashMultimap<Long,Role>,它也可以正常工作。

我不理解这个错误。原因可能是什么?

在使用MultiMap构建数据结构时,我公开了它的Map视图,而不是MultiMap本身:

model.addAttribute("rolesByApp", rolesByApp.asMap());

在JSP中,我替换了

<c:set var="appRoles" value="${rolesByApp.get(app.id)}"/>

带有

<c:set var="appRoles" value="${rolesByApp[app.id]}"/>

这修复了错误。

我仍然不知道上一个错误的原因。如果有人能复制并解释错误,我会接受答案。否则,我最终会接受自己的变通办法。

请记住,com.google.common.collect.Multimap不会实现java.util.Map

因此,除非您在兼容Servlet 3.0的容器中运行代码,否则JSTL表达式语言不支持Multimap。JSTL规范指出,如果应用JSTL表达式的对象既没有实现java.util.List也没有实现java.til.Map,则JSTL需要符合JavaBean标准的getter。

这意味着对于Servlet 2和更低版本,您必须在将Multimap移交给JSP之前将其转换为"正常"映射,以便使用JSTL表达式访问该映射。

代码使用反射来访问方法。由于它不时工作,而且只在Mac上工作,所以它会出现与JDK实现相关的问题。我想这个问题是由JDK的安全管理器引起的。请尝试安装OpenJDK(顺便说一下,您使用的JDK是什么)并使用不同的JDK,如果问题仍然存在,请重试。

如果第二个JDK没有引起问题,请尽量减少您的问题,直到您可以重现问题,并使用visualVM或(远程)调试器来访问和理解手头的问题。将您所拥有的一切发送给JDK开发团队,并享受发现错误的乐趣。

您也可以尝试使用自己的Reflection方法访问有问题的方法,看看它是否也失败了。

存在一个有效且不基于表面随机性质的问题是有问题的。

最新更新