如何在JSF中访问字段的@Size注释?

时间:2016-03-18 13:19:54

标签: jsf reflection annotations

我的问题是:

出于兼容性原因,我的某些实体字段需要具有确切的长度。该长度通过@Size(min=10, max=10)或类似字段定义。尽管字段键入为String,但它们实际上包含数字。大多数字段都具有前导零的值,例如:0000148233

现在我不想强迫用户在输入字段中输入那些前导零。应该可以输入148233

我的第一种方法是编写一个复合组件,该组件使用简单的FacesConverter根据属性length在输入上添加前导零:

<composite:interface>
    <composite:attribute name="value" required="true" />
    <composite:attribute name="length" required="true"
        type="java.lang.Integer" />
</composite:interface>

<composite:implementation>
    <h:inputText value="#{cc.attrs.value}">
        <f:converter converterId="leadingZeroesConverter" />
        <f:attribute name="length" value="#{cc.attrs.length}" />
    </h:inputText>
</composite:implementation>

我在转换器中读取了length属性:

@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
    int length = (Integer) component.getAttributes().get("length");
    return Strings.zeroPrefixFillUp(value, length);
}

这确实很有效,但我实际上并不想在JSF中定义长度。

我想要做的是以某种方式访问​​注释,无论是在JSF中还是在转换器中。这样我就可以避免在两个地方维护该属性。

在转换器中我有FacesContext和UIComponent(显然是一个InputText)。有没有办法获得该字段的名称(以及它的类),所以我可以访问该注释?

PS:只是为了让您知道,为清晰起见,我从转换器中删除了所有错误处理。

1 个答案:

答案 0 :(得分:1)

关注@ Kukeltje的链接让我走上正轨:

我现在有两个复合属性,即beanfield。通过cc.attrs.bean[cc.attrs.field]我设置了inputText的值。在我的转换器中,我评估表达式#{cc.attrs.bean}#{cc.attrs.field},它们返回bean和字段的名称。使用反射我现在可以访问@Size注释。

复合组件

<composite:interface>
    <composite:attribute name="bean" required="true" />
    <composite:attribute name="field" required="true" type="java.lang.String" />
</composite:interface>

<composite:implementation>
    <h:inputText value="#{cc.attrs.bean[cc.attrs.field]}">
        <f:converter converterId="leadingZerosConverter" />
    </h:inputText>
</composite:implementation>

转换器

@FacesConverter(value = "leadingZerosConverter")
public class LeadingZerosConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {

        Object bean = evaluateExpression("#{cc.attrs.bean}", context, Object.class);
        String fieldName = evaluateExpression("#{cc.attrs.field}", context, String.class);
        if (bean == null || fieldName == null) {
            throw new IllegalArgumentException("bean and field must not be null");
        }
        try {
            Size annotation = bean.getClass().getDeclaredField(fieldName).getAnnotation(Size.class);
            return Strings.zeroPrefixFillUp(value, annotation.min());
        } catch (NoSuchFieldException | SecurityException e) {
            throw new IllegalArgumentException(e);
        }   
    }

    private <T> T evaluateExpression(String expression, FacesContext context, Class<T> clazz) {

        ExpressionFactory factory = context.getApplication().getExpressionFactory();
        ValueExpression exp = factory.createValueExpression(context.getELContext(), expression, clazz);

        return clazz.cast(exp.getValue(context.getELContext()));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return ((String) value).replaceFirst("^0+(?!$)", "");
    }
}