3

I know this is not supported in UIData and I understand why, but this should be a common issue for people using JPA and JSF since Sets are the superior collection when mapping M2M O2M relationships.

I know I need to create some structure to convert my property to a list when it's needed but after extensively googling this problem all I can find is reasons why it doesn't work, and only slight hints of a solution.

I believe the answer is to create an ELResolver to handle this but the structure of them and how they work is baffling to me and I don't see why I would need to be the one writing this when it's a common issue, Surely someone has written an ELResolver to do this?

I have found this article on the subject but I can't replicate it because the newer JSF doesn't seem to allow it:

http://techblog.bozho.net/?p=28&cpage=1#comment-13700

And this:

http://www.jroller.com/mert/entry/settolistpropresolver_for_jsf_el

Which is full of deprecated code because it's pre ELResolver. But I just can't find how to implement an ELResolver to do it. Can someone point me to some code that works or at least something similar that will help me fathom out how to use an ELResolver?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Link19
  • 586
  • 1
  • 18
  • 47
  • See also [Usings Sets with UIData](http://sfjsf.blogspot.com/2006/03/usings-sets-with-uidata.html) written by a former JSF spec lead. – McDowell Feb 17 '12 at 16:14

1 Answers1

8

Something easier, support for Set (actually, the entire Collection interface) in DataModel is available in JSF 2.2. It's currently already available as snapshot so that you can just start developing. It will be released around Q2.


Update: as per the comments, it didn't seem to quite work seamlessly together with Spring Web Flow. It turns out that it's not JSF 2.2 compatible (and initially also not JSF 2.1 compatible). Well, a custom ELResolver should be your best bet.

Easiest is to let it extend ListELResolver as follows:

public class SetToListELResolver extends ListELResolver {

    public static final String KEY_PROPERTY = "setToList";

    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        if (base instanceof Set<?> && KEY_PROPERTY.equals(property)) {
            context.setPropertyResolved(true);
            return new ArrayList<Object>((Set<?>) base);
        }

        return super.getValue(context, base, property);
    }

}

If you register it as follows in faces-config.xml

<application>
    <el-resolver>com.example.SetToListELResolver</el-resolver>
</application>

then you'll be able to use it in the syntax of #{bean.set.setToList} wherein the .setToList is a special property which will trigger the conversion:

<h:dataTable value="#{bean.set.setToList}" ...>

It will effectively end up in a fictive

<h:dataTable value="#{new ArrayList(bean.set)}" ...>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • How to I get Maven to use that? – Link19 Feb 17 '12 at 11:58
  • Click the "snapshot" link in my answer. – BalusC Feb 17 '12 at 12:12
  • Doesn't look like this is an option, I'm working in a project set up by someone else and he's left a comment in the pom saying that TOMCAT doesn't support 2.1 so don't upgrade jsf. – Link19 Feb 17 '12 at 12:36
  • 1
    That person is perhaps overgeneralizing a bug in Mojarra 2.1.0. This bug caused the first JSF 2.1 version to fail in Tomcat because Mojarra guys accidently included Glassfish-specific code in the annotation scanner which is fixed in 2.1.1. Mojarra 2.1.1 and newer definitely works in Tomcat. Even more, I am also using it for my quick'n'dirty playground project. See also http://stackoverflow.com/questions/7805928/mojarra-2-1-0-fcs-doesnt-work-with-tomcat-7/7806402#7806402 – BalusC Feb 17 '12 at 12:56
  • Do you think you could spare a few minutes just to help me go through this pom stuff? I've never used Maven but i'm puzzled because that site claims that the dependency only includes api for compile time so how does the functionality get in to my WAR and tomcat? – Link19 Feb 17 '12 at 13:05
  • Sorry, I've also never used Maven, but I'd imagine that it's just a matter of changing the `` declaration for JSF. – BalusC Feb 17 '12 at 13:07
  • Having changed my pom to use the repository and dependency from that site, my project still builds, but I still get get the same conversion error when trying to use my Set. – Link19 Feb 17 '12 at 13:35
  • Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/faces/webapp/FacesServlet – Link19 Feb 17 '12 at 13:49
  • This is not the same conversion error. This `ClassFormatError` is caused by a dirty classpath. You've still the old JSF 2.0 libs somewhere in the classpath. From all what I've read in Maven-related JSF problems, this can also be caused by having the entire "java-ee" dependency instead of the separate "jsp", "servlet" and "jstl" dependencies. – BalusC Feb 17 '12 at 13:50
  • I have an idea it's to do with the fact that the jar i'm using is actually just a code less shell that's used for compilation, what I can't figure out is how that's even remotely useful? Maven should have some way to get the actual implementations in to the final war but it's beyond me at the minute. – Link19 Feb 17 '12 at 14:02
  • Right, I managed to get the latest version running and the app started, now when i go through the login screen I get this error: java.lang.UnsupportedOperationException javax.faces.context.FacesContext.isReleased(FacesContext.java:624) I guess there's some feature that's now not supported in 2.2 that the old developer used? – Link19 Feb 17 '12 at 15:04
  • Are you using Spring Web Flow? I recall that some older versions will trigger an exception exactly like that. In any way, it's caused by a framework-specific `FacesContext` implementation which is not JSF 2.1 compatible. Maybe it's even the old JSF 2.0 leftover itself which is still wandering somewhere in the runtime classpath. – BalusC Feb 17 '12 at 15:08
  • I found a solution to that here which works: https://jira.springsource.org/browse/SWF-1467?focusedCommentId=72904&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel However the most annoying thing about this is that now it's all running and deployed with JSF 2.2 i am now once again getting the: No converter found capable of converting from 'java.util.Set' to 'javax.faces.model.DataModel' error all over again! – Link19 Feb 17 '12 at 15:17
  • If I google on ["No converter found capable of converting from"](https://www.google.com/search?q=%22No+converter+found+capable+of+converting+from%22) I get mainly results referring Spring. This seems to be a Spring specific issue :/ Maybe you should stick to JSF 2.0 and look for another solution. I'll look at an ELResolver. – BalusC Feb 17 '12 at 16:08
  • I was under the impression that 2.2 had a converter to do this though. – Link19 Feb 17 '12 at 16:18
  • No, this is Spring specific. Somehow Spring's EL resolver is interfering with it. But I found a relatively easy way with EL resolver. I'll update the answer. – BalusC Feb 17 '12 at 16:29
  • I'm getting some pretty strange behaviour here, I implemented your code and still got the "no converter" error. So I added some debug lines to the ELResolver and can see that it's not invoked at all when I navigate to my page that has my Set table on it. However when I navigate to a page that has a h:datatable generated from an actual List I can see the resolver being hit up lots. It's strange, almost as if there's some pre-validation on the List before it reaches the JSF. – Link19 Feb 20 '12 at 10:25
  • This is Spring specific. Spring has also its own EL resolver. I however can't go in further detail as I don't use Spring. – BalusC Feb 20 '12 at 12:19