سؤال

Going from 1.4 to 1.5, there seem to be many undocumented changes in addition to the documented ones.

In 1.4 I had:

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

With 1.5, I changed that like so (to match how getConverter() is now declared):

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

Which my IDE shows as just unchecked assignment warning. But then trying to build the project it's actually a compilation error:

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

The custom MonetaryBigDecimalConverter looks something like this (1.5):

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

How can I make this work again?

هل كانت مفيدة؟

المحلول

Since Wicket 1.5 converter has a generic type parameter:

IConverter<C>

Note that the type argument C of #getConverter() is not bound to the type parameter of your textfield, so you should test the requested type:

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);
        }
    }
};

You have to explicitely cast your converter to the requested IConverter to quiet the compiler. Or with your workaround you're dropping into a raw type, thus sidestepping the problem.

نصائح أخرى

I have no idea why, but the following small change in getConverter method made it compile.

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

I just extracted the MonetaryBigDecimalConverter instance into a varible of type IConverter. A field or constant would work similarly. (NB: the type must not be IConverter<C> or IConverter<BigDecimal>.) This code still produces "unchecked assignment" warning, but at least it compiles.

I'd be grateful if someone added an explanation or a better solution altogether. I am certainly no expert when it comes to Java generics oddities.

Because the return value is derived from whatever argument is passed to the method at runtime, Java is unable to determine the return type and a cast is always required.

On the other hand, if the return type would have been known upon compilation, then you would have been able to use a more smart approach. (E.g. when Component would have been a generic type that determined the type of C, instead of the parameter passed to it) :

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;
    }
}

Because the compiler now knows for a fact that the getConverter method will return IConverter<BigDecimal>, casting is not required.


Your own solution of extracting in a variable works the same as casting to raw type IConverter which is also possible. No need extracting it.

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

When casting to raw type, instead of saying 'I return a Converter of type BigDecimal' (which can be wrong when the passed argument is of another type) you are now saying 'I return an IConverter of whatever' (which is made possible for backward compatibility reasons when generics where introduced in Java 1.5, but of-course can throw a RuntimeException)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top