我有一个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方法访问有问题的方法,看看它是否也失败了。
存在一个有效且不基于表面随机性质的问题是有问题的。