No access to nested property in managed bean withi

2019-02-13 15:43发布

I have following two simple POJOs:

class Person {
   String name
   Address address;
   //and of course the getter/setter for the attributes
}

class Address {
   String city;
   //also getter/setter for this attribute
}

And a backing bean:

@ManagedBean
@RequestScoped
class PersonController {

    private List persons;
    private List<String> columns = Arrays.toList("name", "address.city");
   //of course getter/setter
}

Now I want to create a dataTable.

<p:dataTable var="person" value="#{personController.persons}" columnIndexVar="index">
    <p:columns var="column" value="#{personController.columns}">
        <h:outputText value="#{person[column]}"/>
    <p:columms>
</p:dataTable>

When I execute this I get a ServletException:

The class Person does not have the property 'address.city'.

But if a try to access the property city like this within p:columns:

<h:outputText value="#{person.address.city}"/>

Everything is fine.

Why I can not access a nested property like that #{person['address.city']}? And how can I access it within p:columns?

2条回答
Explosion°爆炸
2楼-- · 2019-02-13 15:58

Nested bean properties in a brace notation string expression like #{person['address.city']} is by default not supported. You basically need a #{person['address']['city']}.

You need a custom ELResolver here. Easiest is to extend the existing BeanELResolver.

Here's a kickoff example:

public class ExtendedBeanELResolver extends BeanELResolver {

    @Override
    public Object getValue(ELContext context, Object base, Object property)
        throws NullPointerException, PropertyNotFoundException, ELException
    {
        if (property == null || base == null || base instanceof ResourceBundle || base instanceof Map || base instanceof Collection) {
            return null;
        }

        String propertyString = property.toString();

        if (propertyString.contains(".")) {
            Object value = base;

            for (String propertyPart : propertyString.split("\\.")) {
                value = super.getValue(context, value, propertyPart);
            }

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

}

To get it to run, register it as follows in faces-config.xml:

<application>
    <el-resolver>com.example.ExtendedBeanELResolver</el-resolver>
</application>
查看更多
等我变得足够好
3楼-- · 2019-02-13 16:18

In addition to @BalusC answer I had to add a check for PrimeResourceHandler. Otherwise all resolvements of #{resource...} like #{resource['primefaces:spacer/dot_clear.gif']} inside the primefaces.css failed and the output stream of the parsed CSS file gets corrupted.

public class ExtendedBeanELResolver extends BeanELResolver {

    private static final String PRIMEFACES_RESOURCE_PREFIX = "primefaces:";

    @Override
    public Object getValue(ELContext context, Object base, Object property) throws NullPointerException,
            PropertyNotFoundException, ELException {
        if (property == null || base == null || base instanceof ResourceBundle || base instanceof Map
                || base instanceof Collection || base instanceof PrimeResourceHandler) {
            return null;
        }

        String propertyString = property.toString();

        if (!propertyString.startsWith(PRIMEFACES_RESOURCE_PREFIX) && propertyString.contains(".")) {
            Object value = base;

            for (String propertyPart : propertyString.split("\\.")) {
                value = super.getValue(context, value, propertyPart);
            }

            return value;
        } else {
            return super.getValue(context, base, property);
        }
    }
}
查看更多
登录 后发表回答