我的问题是:
出于兼容性原因,我的某些实体字段需要具有确切的长度。该长度通过@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:只是为了让您知道,为清晰起见,我从转换器中删除了所有错误处理。
答案 0 :(得分:1)
关注@ Kukeltje的链接让我走上正轨:
我现在有两个复合属性,即bean
和field
。通过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+(?!$)", "");
}
}