如何在 Wicket 1.5 中将自定义 BigDecimal 转换器设置为文本字段<BigDecimal>?



从1.4到1.5,除了已记录的更改外,似乎还有许多未记录的更改。

在1.4中我有:

new TextField<BigDecimal>("capitalInput", 
        new PropertyModel<BigDecimal>(model, "capital")) {
    @Override
    public IConverter getConverter(Class<?> type) {
        return new MonetaryBigDecimalConverter();
    } 
};

在1.5中,我这样改变了(为了匹配getConverter()现在的声明方式):

new TextField<BigDecimal>("capital", 
        new PropertyModel<BigDecimal>(model, "capital")) {
    @Override
    public <C> IConverter<C> getConverter(Class<C> type) {
        return new MonetaryBigDecimalConverter();
    }
};

我的IDE显示为未选中的赋值警告。但是当试图构建项目时它实际上是一个编译错误:

incompatible types
found   : com.company.MonetaryBigDecimalConverter
required: org.apache.wicket.util.convert.IConverter<C>

自定义的MonetaryBigDecimalConverter看起来像这样(1.5):

public class MonetaryBigDecimalConverter extends BigDecimalConverter {
    @Override
    public String convertToString(BigDecimal value, Locale locale) {
        // ...
    }
}

我怎样才能使它再次工作?

由于Wicket 1.5转换器有一个泛型类型参数:

IConverter<C>

请注意,#getConverter()的类型参数C没有绑定到文本字段的类型参数,因此您应该测试所请求的类型:

new TextField<BigDecimal>("capital", 
        new PropertyModel<BigDecimal>(model, "capital")) {
    @Override
    public <C> IConverter<C> getConverter(Class<C> type) {
        if (type == BigDecimal) {
            return (IConverter<C>) new MonetaryBigDecimalConverter();
        } else {
            return super.getConverter(type);
        }
    }
};

您必须显式地将您的转换器强制转换为所请求的IConverter以静默编译器。或者使用您的变通方法,您可以使用原始类型,从而避开问题。

我不知道为什么,但是getConverter方法中的以下小变化使其编译。

@Override
public <C> IConverter<C> getConverter(Class<C> type) {
    IConverter converter = new MonetaryBigDecimalConverter();
    return converter;
}

我刚刚将MonetaryBigDecimalConverter实例提取到类型为IConverter变量中。字段或常数的工作原理类似。(注意:类型不能IConverter<C>IConverter<BigDecimal>。)这段代码仍然会产生"未检查的赋值"警告,但至少它可以编译。

如果有人能补充一个解释或一个更好的解决方案,我会很感激的。在Java泛型方面,我当然不是专家。

因为返回值是从运行时传递给方法的任何参数派生的,所以Java无法确定返回类型,并且强制转换总是必需的。

另一方面,如果在编译时返回类型是已知的,那么您就可以使用更聪明的方法。(例如,当Component是决定C类型的泛型类型,而不是传递给它的参数时):
Component myConverter = new Component<BigDecimal>() {
    @Override
    public IConverter<BigDecimal> getConverter() {
        return new MonetaryBigDecimalConverter();
    }
};
class Component<C> { // <-- Type of C is known at compile time!
    public IConverter<C> getConverter() {
        return null;
    }
}

因为编译器现在知道getConverter方法将返回IConverter<BigDecimal>,所以不需要强制类型转换。


您自己的提取变量的解决方案与转换为原始类型IConverter相同,这也是可能的。不需要提取。

@Override
public <C> IConverter<C> getConverter(Class<C> type) {
    return (IConverter) new MonetaryBigDecimalConverter();
}

当转换为原始类型时,而不是说"我返回BigDecimal类型的Converter"(当传递的参数是另一种类型时可能是错误的),你现在说"我返回任何类型的IConverter"(这是由于Java 1.5中引入泛型的向后兼容性原因,但当然可以抛出RuntimeException)

最新更新