开发者

JSF and expression language: Bind property only when it exists

开发者 https://www.devze.com 2023-02-23 22:22 出处:网络
what is the best way to bind a datacolumn to a property that might or might not exist in the datasource?

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 shoul开发者_高级运维dn't be there according to the business rules.

How would you solve this problem?


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'}" />


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.


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消