Closed tasomaniac closed 1 year ago
@tasomaniac do you have an example snippet of what this should generate?
It's 2 years since I don't use AutoValue anymore. IIRC, it was easy to reproduce with the AutoValue class above. If you look at the generated code, it should be fairly easy.
A user here at Google has run into a similar problem. I was able to reproduce their case by modifying the parameterizedType()
test method in AutoValueParcelExtensionTest
like this:
JavaFileObject intf = JavaFileObjects.forSourceString("test.Intf", ""
+ "package test;\n"
+ "import android.os.Parcelable;\n"
+ "interface Intf extends Parcelable {}"
);
JavaFileObject source = JavaFileObjects.forSourceString("test.Test", ""
+ "package test;\n"
+ "import android.os.Parcelable;\n"
+ "import com.google.auto.value.AutoValue;\n"
+ "@AutoValue public abstract class Test<T extends Intf> implements Parcelable {\n"
+ "public abstract T tea();\n"
+ "}"
);
...
Then the test fails like this:
warning: No processor claimed any of these annotations: com.google.auto.value.AutoValue warning: No processor claimed any of these annotations: javax.annotation.Generated android/os/Parcel.java:22: warning: [rawtypes] found raw type: java.util.HashMap HashMap readHashMap(ClassLoader cl); ^ missing type arguments for generic class java.util.HashMap<K,V> android/os/Parcel.java:23: warning: [rawtypes] found raw type: java.util.ArrayList ArrayList readArrayList(ClassLoader cl); ^ missing type arguments for generic class java.util.ArrayList<E> android/os/Parcel.java:41: warning: [rawtypes] found raw type: java.util.Map void writeMap(Map in); ^ missing type arguments for generic class java.util.Map<K,V> android/os/Parcel.java:42: warning: [rawtypes] found raw type: java.util.List void writeList(List in); ^ missing type arguments for generic class java.util.List<E> /SOURCE_OUTPUT/test/AutoValue_Test.java:10: warning: [rawtypes] found raw type: test.AutoValue_Test public static final Parcelable.Creator<AutoValue_Test> CREATOR = new Parcelable.Creator<AutoValue_Test>() { ^ missing type arguments for generic class test.AutoValue_Test<T> /SOURCE_OUTPUT/test/AutoValue_Test.java:10: warning: [rawtypes] found raw type: test.AutoValue_Test public static final Parcelable.Creator<AutoValue_Test> CREATOR = new Parcelable.Creator<AutoValue_Test>() { ^ missing type arguments for generic class test.AutoValue_Test<T> /SOURCE_OUTPUT/test/AutoValue_Test.java:12: warning: [rawtypes] found raw type: test.AutoValue_Test public AutoValue_Test createFromParcel(Parcel in) { ^ missing type arguments for generic class test.AutoValue_Test<T> /SOURCE_OUTPUT/test/AutoValue_Test.java:13: warning: [rawtypes] found raw type: test.AutoValue_Test return new AutoValue_Test( ^ missing type arguments for generic class test.AutoValue_Test<T> /SOURCE_OUTPUT/test/AutoValue_Test.java:14: error: non-static type variable T cannot be referenced from a static context (T) in.readParcelable(Test.class.getClassLoader()) ^ /SOURCE_OUTPUT/test/AutoValue_Test.java:18: warning: [rawtypes] found raw type: test.AutoValue_Test public AutoValue_Test[] newArray(int size) { ^ missing type arguments for generic class test.AutoValue_Test<T> /SOURCE_OUTPUT/test/AutoValue_Test.java:19: warning: [rawtypes] found raw type: test.AutoValue_Test return new AutoValue_Test[size]; ^ missing type arguments for generic class test.AutoValue_Test<T>
There's a lot of noise from the rawtypes
warnings, but there is one error in the bunch:
/SOURCE_OUTPUT/test/AutoValue_Test.java:14: error: non-static type variable T cannot be referenced from a static context
(T) in.readParcelable(Test.class.getClassLoader())
^
The problem is that the static CREATOR
field looks like this:
final class AutoValue_Test<T extends Intf> extends $AutoValue_Test<T> {
public static final Parcelable.Creator<AutoValue_Test> CREATOR = new Parcelable.Creator<AutoValue_Test>() {
@Override
public AutoValue_Test createFromParcel(Parcel in) {
return new AutoValue_Test(
(T) in.readParcelable(Test.class.getClassLoader())
);
}
@Override
public AutoValue_Test[] newArray(int size) {
return new AutoValue_Test[size];
}
};
That cast to (T)
fails because there is no T
in scope (we are inside the initializer of a static field). In the actual user code, there was a second field of type Optional<T>
which caused a second error because of the cast to (Optional<T>)
. I mention that because a fix that detects just the exact T
case would not be enough.
With plain <T extends Parcelable>
, as in the unmodified parameterizedType()
test, there is no cast in the generated code. The relevant code is here:
TypeName check = property.type instanceof TypeVariableName
? ((TypeVariableName) property.type).bounds.get(0)
: property.type;
if (!check.equals(PARCELABLE)) {
block.add("($T) ", property.type);
}
block.add("in.readParcelable($T.class.getClassLoader())", autoValueType);
In the exact case of <T extends Parcelable>
, this omits the cast, but in every other case it is inserted. A cast is in fact needed for the Optional<T>
case, though it would need to be (Optional)
or (Optional<?>)
. Perhaps in the presence of a type parameter, the code should look to see if that parameter is mentioned in the type in question, and if so cast to the erased type?
I have a field with type
Class<T>
Class
isSerializable
soauto-value-parcel
tries to put that as aSerializable
. This is fine.The problem is in the
CREATOR
method. Since it is a static context, it cannot access the type. Either you need to makeCREATOR
typed or you should remove the type insideCreator
. This will cause a warning of course but that can be suppressed.Right now, it just does not compile. Here is a simple class to reproduce it.