tom91136 / Akatsuki

Android states and arguments made easy with annotations
Apache License 2.0
138 stars 15 forks source link

Inheriting, @Retained, Parcelable #8

Closed ersin-ertan closed 9 years ago

ersin-ertan commented 9 years ago

I am unsure if the error pertains to this library or ParcelablePlease. Example The files in question are BeanInheritedParcelable, and BeanParcelableInherited.

One is a Bean that extends a RootBean that implements Parcelable along with having its own @ Retained fields, and the other implements Parcelable but extends a RootBean that has its own @ Retained fields.

In both cases, the class that directly implements Parcelable does not have their fields saved, even though a working example using the parcelable implementation was shown to work. It seems because the class is an extended version, using the recommended Parcelable type instead of the @ Retained annotation does not work.

ersin-ertan commented 9 years ago

My follow up to this fix - if one is required, will be to put generic types within both examples for the child class, the root class, and both.

tom91136 commented 9 years ago

To understand what happens when a type goes through the processor, you can take a look at the source:

CascadingTypeAnalyzer<?, ? extends TypeMirror, ? extends Analysis> findTransformationStrategy(
        ProcessorElement<?> element) {
    CascadingTypeAnalyzer<?, ?, ?> strategy = null;

    // @Retained defaults to a dummy converter, we don't want that
    final TypeMirror dummyConverter = context.utils().of(DummyTypeConverter.class);
    if (element.typeConverter() != null && !transformationContext.utils()
            .isSameType(element.typeConverter(), dummyConverter, true)) {
        strategy = new ConverterAnalyzer(transformationContext, element.typeConverter());
    }

    if (strategy == null) {
        final DeclaredType converterType = models.stream()
                .filter(m -> testTypeFilter(element.refinedMirror(), m.filters)).findFirst()
                .map(m -> m.converter).orElse(null);
        if (converterType != null)
            strategy = new ConverterAnalyzer(transformationContext, converterType);
    }

    if (strategy == null)
        strategy = findTransformationTemplates(templates, element, Execution.BEFORE);

    if (strategy == null) {
        final TypeMirror mirror = element.refinedMirror();
        // TODO consider discarding the switch and move the test
        // condition
        // into
        // every strategy
        if (transformationContext.utils().isPrimitive(mirror)) {
            strategy = new PrimitiveTypeAnalyzer(transformationContext, Type.UNBOXED);
        } else if (transformationContext.utils().isArray(mirror)) {
            strategy = new ArrayTypeAnalyzer(transformationContext);
        } else if (testTypeAssignableFromModel(mirror)) {
            // this field is a type that contains the @Retained
            // annotation
            strategy = new NestedTypeAnalyzer(transformationContext);
        } else if (transformationContext.utils().isAssignable(mirror,
                transformationContext.utils().of(Collection.class), true)) {
            strategy = new CollectionTypeAnalyzer(transformationContext);
        } else if (transformationContext.utils().isAssignable(mirror,
                transformationContext.utils().of(Map.class), true)) {
            // TODO: ETS phase 2
        } else if (transformationContext.utils().isObject(mirror)) {
            strategy = new ObjectTypeAnalyzer(transformationContext);
        } else if (mirror.getKind().equals(TypeKind.TYPEVAR)) {
            // we got a generic type of some bounds
            strategy = new GenericTypeAnalyzer(transformationContext);
        }
    }

    if (strategy == null) {
        final CascadingTypeAnalyzer<?, ?, Analysis> ignored = findTransformationTemplates(
                templates, element, Execution.NEVER);
        if (ignored != null)
            context.messager().printMessage(Kind.NOTE,
                    "found matching strategy:" + ignored.getClass() + " but ignored");
    }
    return strategy;
}

The method above finds a suitable Analyzer that will generate our code. As you can see, nested types (ones that have at least one @Retained annotation) comes before parcelable, in other words, if an object implements parcelable AND also contain @Retained, @Retained wins, anything done by the parcelable is ignored.

Akatsuki is not designed for general serialization, mixing @Retained with Parcelable is also not recommended and will most likely fail in strange ways.