1
@FacesValidator("uniqueValidator")
public class UniqueValidator implements Validator
{
    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
    {
        if(context == null)
        {
            throw new NullPointerException();
        }
        if(component == null)
        {
            throw new NullPointerException();
        }

        ValueExpression valueExpression = component.getValueExpression("value");
        if(valueExpression == null)
        {
            return;
        }

        ValueReference valueReference = valueExpression.getValueReference(context.getELContext());
        if(valueReference == null)
        {
            return;
        }

        Object base = valueReference.getBase();
        Object property = valueReference.getProperty();

        Tracer.out(base, property);

        .....
    }
}

并且ValueReference始终为

怎么了?

4

2 回答 2

4

谢谢 BeanValidator :)

public class ValueExpressionAnalyzer
{
    public static ValueReference getReference(ELContext elContext, ValueExpression expression)
    {
        InterceptingResolver resolver = new InterceptingResolver(elContext.getELResolver());

        try
        {
            expression.setValue(new InterceptingContext(elContext, resolver), null);
        }
        catch(ELException ele)
        {
            return null;
        }

        ValueReference reference = resolver.getValueReference();
        if(reference != null)
        {
            Object base = reference.getBase();
            if(base instanceof CompositeComponentExpressionHolder)
            {
                ValueExpression ve = ((CompositeComponentExpressionHolder) base).getExpression((String) reference.getProperty());
                if(ve != null)
                {
                    reference = getReference(elContext, ve);
                }
            }
        }
        return reference;
    }

    private static class InterceptingContext extends ELContext
    {
        private final ELContext context;
        private final ELResolver resolver;

        public InterceptingContext(ELContext context, ELResolver resolver)
        {
            this.context = context;
            this.resolver = resolver;
        }

        // punch in our new ELResolver
        @Override
        public ELResolver getELResolver()
        {
            return resolver;
        }

        // The rest of the methods simply delegate to the existing context

        @Override
        public Object getContext(Class key)
        {
            return context.getContext(key);
        }

        @Override
        public Locale getLocale()
        {
            return context.getLocale();
        }

        @Override
        public boolean isPropertyResolved()
        {
            return context.isPropertyResolved();
        }

        @Override
        public void putContext(Class key, Object contextObject)
        {
            context.putContext(key, contextObject);
        }

        @Override
        public void setLocale(Locale locale)
        {
            context.setLocale(locale);
        }

        @Override
        public void setPropertyResolved(boolean resolved)
        {
            context.setPropertyResolved(resolved);
        }

        @Override
        public FunctionMapper getFunctionMapper()
        {
            return context.getFunctionMapper();
        }

        @Override
        public VariableMapper getVariableMapper()
        {
            return context.getVariableMapper();
        }
    }

    private static class InterceptingResolver extends ELResolver
    {
        private final ELResolver delegate;
        private ValueReference valueReference;

        public InterceptingResolver(ELResolver delegate)
        {
            this.delegate = delegate;
        }

        public ValueReference getValueReference()
        {
            return valueReference;
        }

        // Capture the base and property rather than write the value
        @Override
        public void setValue(ELContext context, Object base, Object property, Object value)
        {
            if(base != null && property != null)
            {
                context.setPropertyResolved(true);
                valueReference = new ValueReference(base, property.toString());
            }
        }

        // The rest of the methods simply delegate to the existing context

        @Override
        public Object getValue(ELContext context, Object base, Object property)
        {
            return delegate.getValue(context, base, property);
        }

        @Override
        public Class<?> getType(ELContext context, Object base, Object property)
        {
            return delegate.getType(context, base, property);
        }

        @Override
        public boolean isReadOnly(ELContext context, Object base, Object property)
        {
            return delegate.isReadOnly(context, base, property);
        }

        @Override
        public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
        {
            return delegate.getFeatureDescriptors(context, base);
        }

        @Override
        public Class<?> getCommonPropertyType(ELContext context, Object base)
        {
            return delegate.getCommonPropertyType(context, base);
        }

    }
}
于 2013-01-12T12:50:50.913 回答
0

看看 Omnifaces ExpressionInspector。似乎在 JSF 2.x 中它没有实现并且总是返回 null。

https://showcase.omnifaces.org/el/ExpressionInspector

于 2021-03-07T20:34:25.637 回答