I have the following general BigDecimal
converter (deeply reviewing the code is absolutely superfluous).
@FacesConverter(value = "bigDecimalConverter")
public class BigDecimalConverter implements Converter {
@Inject
private CurrencyRateBean currencyRateBean; // Maintains a currency selected by a user in his/her session.
private static final int scale = 2; // Taken from an enum.
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (!StringUtils.isNotBlank(value)) {
return null;
}
try {
BigDecimal bigDecimal = new BigDecimal(value);
return bigDecimal.scale() > scale ? bigDecimal.setScale(scale, RoundingMode.HALF_UP).stripTrailingZeros() : bigDecimal.stripTrailingZeros();
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Message"), e);
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
BigDecimal newValue;
if (value instanceof Long) {
newValue = BigDecimal.valueOf((Long) value);
} else if (value instanceof Double) {
newValue = BigDecimal.valueOf((Double) value);
} else if (!(value instanceof BigDecimal)) {
throw new ConverterException("Message");
} else {
newValue = (BigDecimal) value;
}
final String variant = (String) component.getAttributes().get("variant");
if (variant != null) {
if (variant.equalsIgnoreCase("grouping")) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance();
formatter.setGroupingUsed(true);
formatter.setMinimumFractionDigits(scale);
formatter.setMaximumFractionDigits(scale);
return formatter.format(newValue);
} else if (variant.equalsIgnoreCase("currency")) {
String currency = currencyRateBean.getCurrency();
DecimalFormat formatter = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale("en", new String(currency.substring(0, 2))));
formatter.setDecimalFormatSymbols(formatter.getDecimalFormatSymbols());
formatter.setCurrency(Currency.getInstance(currency));
return formatter.format(newValue);
}
}
DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance();
formatter.setGroupingUsed(false); // Not necessary.
formatter.setMinimumFractionDigits(scale);
formatter.setMaximumFractionDigits(scale);
return formatter.format(newValue);
}
}
This can be used as follows.
<h:outputText value="#{bean.value}">
<f:converter converterId="bigDecimalConverter"/>
<f:attribute name="variant" value="grouping"/>
</h:outputText>
Depending upon the value of variant
in <f:attribute>
, it converts the value to either currency equivalent ($123) or a value using groups (11,111). Other criteria may also be defined as and when required i.e separate converters for other types of formats, if any, are not required. The default task of the converter is to round up the value to two decimal points.
In order to avoid mentioning of,
<f:converter converterId="bigDecimalConverter"/>
or converter="#{bigDecimalConverter}"
everywhere, the converter class needs to be decorated with,
@FacesConverter(forClass = BigDecimal.class)
Doing so, JSF takes its own javax.faces.convert.BigDecimalConverter
beforehand. I have tried extending that class but it did not make any difference.
Is it possible to override the default JSF javax.faces.convert.BigDecimalConverter
so that our own converter can be used by specifying forClass = BigDecimal.class
so that there is no need to fiddle around with <f:converter converterId="bigDecimalConverter"/>
or converter="#{bigDecimalConverter}"
anywhere?
In general, overriding default converters (and validators, components and renderers) can't take place with annotations on the same identifier(s). It really has to be explicitly registered in webapp's own faces-config.xml
.
In case you intend to override converter="javax.faces.BigDecimal"
, then do so:
<converter>
<converter-id>javax.faces.BigDecimal</converter-id>
<converter-class>com.example.YourBigDecimalConverter</converter-class>
</converter>
In case you intend to override implicit conversion for type java.math.BigDecimal
, then do so:
<converter>
<converter-for-class>java.math.BigDecimal</converter-for-class>
<converter-class>com.example.YourBigDecimalConverter</converter-class>
</converter>
You need the latter.