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



我的问题是:

出于兼容性原因,我的一些实体字段需要具有确切的长度。该长度通过字段上的@Size(min=10, max=10)或类似内容定义。尽管这些字段键入为字符串,但它们实际上包含数字。大多数字段的值都带有前导零,例如: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:只是为了让您知道,出于清晰的原因,我从转换器中删除了所有错误处理。

遵循@Kukeltje的链接使我走上了正确的轨道:

我现在有两个复合属性,即beanfield。通过cc.attrs.bean[cc.attrs.field]我设置了输入文本的值。在我的转换器中,我计算表达式 #{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+(?!$)", "");
    }
}

最新更新