JSF and expression language: Bind property only when it exists
Asked Answered
G

5

9

what is the best way to bind a datacolumn to a property that might or might not exist in the datasource?

This happens for example when you have a class hierarchy where some children might be of a subtype which has the property. The datasource contains various subclass types.

<DataColumn outputText="#{item.property}" />

always yields a PropertyNotFoundException when the property isn't present in one of the subclasses. I don't want to include the property in the base class because it shouldn't be there according to the business rules.

How would you solve this problem?

Guardrail answered 11/4, 2011 at 9:19 Comment(0)
G
3

I think the best way in such a case is to create a custom entity for the view tier with all the necessary fields and convert the items you want to display to it.

Guardrail answered 13/4, 2011 at 11:58 Comment(0)
T
8

Without changing the classes, your best bet is to do kind of an instanceof in EL. You can do that by checking the (simple) classname as obtained by Object#getClass() and then Class#getName() or Class#getSimpleName() in EL.

Assuming that the class with the property has the full qualified name com.example.SubItem, here's an example:

<h:outputText value="#{item.property}" rendered="#{item.class.name == 'com.example.SubItem'}" />

or

<h:outputText value="#{item.property}" rendered="#{item.class.simpleName == 'SubItem'}" />
Timorous answered 11/4, 2011 at 17:32 Comment(2)
I have an issue when try to use #{item.class} , but work well with #{item.getClass()}Scrivings
Any idea how to do that if one not knows the class before hand?Bashan
T
4

As an alternate way of providing instanceof functionality in EL, you might consider adding an isInstanceOf() method to an ApplicationScoped bean. I use something like:

@ManagedBean( name="app" )
@ApplicationScoped
public class ApplicationController implements Serializable {
    public boolean isInstanceOf( Object o, String className ) throws ClassNotFoundException {
        return Class.forName( className ).isInstance( o );
    }
}

then I call it from EL like:

<... rendered="#{app.isInstanceOf( someObject, 'java.lang.Object' )}">

With some tweaking this idea can be generalized to facilitate calling any static method from EL.

Tildy answered 19/3, 2013 at 2:46 Comment(0)
G
3

I think the best way in such a case is to create a custom entity for the view tier with all the necessary fields and convert the items you want to display to it.

Guardrail answered 13/4, 2011 at 11:58 Comment(0)
D
0

Why not have a boolean property of the base class that tells you whether you have the actual attribute in the subclasses or not. That way you can easily use the ternary operator in your EL expression, like this:

<DataColumn outputText="#{item.hasProperty ? item.property : 'I don't have this property.'}" />

This could work if EL evaluates the expression lazily, but I'm not sure and can't check it right now. But this is an idea to start with anyway.

Differentiable answered 11/4, 2011 at 12:1 Comment(0)
S
0

Depending on your model here I think you might want to do a lot more work in the backing bean rather than try to make it work on the actual JSF page.

You can just bind the table to the bean as

<h:dataTable binding="#{myBean.dataTable}" />

//BEAN
HtmlDataTable dataTable;

public DataTable getDataTable()
{
  dataTable = new HtmlDataTable(); //etc...
  //add the columns here based on the logic in code
}

and then actually do the rendering inside the bean by adding the components dynamically etc... If you're looking to separate the model and you need the page to be a very controlled bean then the above answers are really more what you're after.

Alternatively as suggested, just use the rendered property and check the class name (beware null pointers). I do both on a regular basis, it really depends on how much complex boolean logic I'm going to have in the actual JSF.

Shebeen answered 11/4, 2011 at 17:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.