Reputation: 3056
Why is it not possible to define generic binding conversion within android data binding library?
@BindingConversion
public static <T> T convertMyClass(MyClass<T> obj) {
return obj.get();
}
With this method I am getting can not find the setter for attribute 'android:text' with parameter type com.example.MyClass<java.lang.String>
error. Defining explicit types works alright.
I was trying to find the way ObservableField<T>
is getting converted but didn't succeed. Does anyone know how is this happening? Is there anything I'm doing wrong?
Upvotes: 1
Views: 860
Reputation: 965
In two words: type erasure.
Generics are a double edged sword that cuts out some of the run time capability of the type system in exchange for compile time checks. You're telling the compiler to rewrite code to make these type conversions "just work." The trade-off is that it has to turn generic class references like "T" into just "Object". So the signature of your method after compilation is
Object convertMyClass(MyClass)
The data binding system is looking for a return type "String". And so doesn't even consider your method.
The data binding system could probably be made smarter, to be able to recognize your BindingConversion, but I wouldn't hold my breath for that feature.
Here is some bash which illustrates type erasure.
$ echo 'public class A{ public <T> T deRef(java.util.concurrent.atomic.AtomicReference<T> atom) {return atom.get();} }' >A.java
$ javac A.java
$ groovy -e 'println A.class.getMethod("deRef", java.util.concurrent.atomic.AtomicReference.class)'
public java.lang.Object A.deRef(java.util.concurrent.atomic.AtomicReference)
That last line of output is the method signature for the generic method.
A work-around would be to subclass MyClass with specific parameterized subclasses like so:
public class MyStringClass extends MyClass<String> {
@Override
public String get() {
return super.get();
}
@BindingConversion
public static String convertMyClass(MyStringClass obj) {
return obj.get();
}
}
Regarding ObservableField, it doesn't need the BindingConversion mechanism because the data-binding library references it in the java code, and therefore compile-time generics checking does the job of matching types up.
Upvotes: 2