8000 Integrated Parceler into Extras by johncarl81 · Pull Request #977 · androidannotations/androidannotations · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

Conversation

@johncarl81
Copy link
Contributor

Basic integration of Parcler including transparent serialization/deserialization when used as Extras or InstanceState. I was unable to test this PR fully, so please let me know if anything is out of order or if any changes need to be made.
#301

@WonderCsabo
Copy link
Member

Unfortunately i cannot build this. I got this error in eclipse and maven, too:

java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.toSet()Lcom/google/common/collect/ImmutableSet;

I think this is the same bug as transfuse#34.

I printed the dependency tree, and it seems the guava dep is indeed the problem:

com.google.guava:guava:jar:13.0.1:test (version managed from 15.0; scope managed from compile)

The solution for this is excluding the guava dependency from your Android dependency.

@johncarl81
Copy link
Contributor Author

Shoot, I was running into the same thing... thought it wasn't in Parceler.

Does AA use Guava?

@WonderCsabo
Copy link
Member

Oops, yes... It uses Guava 13.0.1.

@johncarl81
Copy link
Contributor Author

Ah, I forgot to make the scope <scope>provided</scope>. Could you try again?

@WonderCsabo
Copy link
Member

I am confused. Where did you forget the scope?

EDIT: I was from mobile, i see now. You have rewritten your commit. :S

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not okay. Not just @Parcel annotated types should use getParcelable but types what are implementing the Parcelable interface, too. This change breaks compilation of SaveInstanceStateActivityand FragmentArguments classes in the test app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this breaks Parcelable interfaces? This method is called from the second else/if after it checks if the object is a Parcelable. Really all this call will do is set the boolean parcelerBean = true along with methodNameToSave = "put" + "Parcelable";and methodNameToRestore = "get" + "Parcelable";. I am, of course, open to different ways of integrating this stuff. This technique just seemed to fit with AA's existing architecture.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just check out this code:

if (isTypeParcelable(elementType)) {
    methodNameToSave = "put" + "Parcelable";
    methodNameToRestore = "get" + "Parcelable";
}
if (isTypeParcelerBean(elementType)){
    methodNameToSave = "put" + "Parcelable";
    methodNameToRestore = "get" + "Parcelable";
    parcelerBean = true;
}
else {
    methodNameToSave = "put" + "Serializable";
    methodNameToRestore = "get" + "Serializable";
    restoreCallNeedCastStatement = true;

    if (hasTypeArguments) {
        restoreCallNeedsSuppressWarning = true;
    }
}

So if there is no @Parcel annotation, always the serializable method will be used. You are missing an else i guess.
This is indeed breaks Parcelables in extras, i compiled the test project that's why i noticed the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. Fixed.

@WonderCsabo
Copy link
Member

Unfortunately the 13.0.1 Guava version is still a problem - it does takes precedence over your 15.0, so new com.google.common classes are not found. I have overridden temporarily the Guava version in the test project, now your annotation processor can run.

@johncarl81
Copy link
Contributor Author

This looks to be a shortcoming of Maven. Would you guys care to upgrade Guava?

@johncarl81
Copy link
Contributor Author

By the way, this integration does not take into account beans identified via the @ParcelClass annotation. Im not sure how this style of declaration could be used with AA.

@WonderCsabo
Copy link
Member

About the @ParcelClass: Please read this comment @yDelouis. If i am getting his words correctly, if AA copies the @ParcelClass then parceler can process it.

@WonderCsabo WonderCsabo mentioned this pull request May 1, 2014
@yDelouis
Copy link
Contributor
yDelouis commented May 1, 2014

I tried to add the parceler annotations processor to the branch of my PR #982 alongside AA.
@Parcel and @ParcelClass are copied to the generated class. So that parceler processes both base and generated class, because annotations processors are triggered until no file is generated.
By the way, we can't annotate a class with both @EBean and @Parcel because a Context field is in the generated class and can't be parceled.

@johncarl81
Copy link
Contributor Author

@yDelouis Are there other generated classes in AA that will take advantage of copying between the target and generated classes?

Keep in mind there is a handful of other annotations for Parceler to handle if this is the strategy you want to take.

@yDelouis
Copy link
Contributor
yDelouis commented May 7, 2014

All non AA annotations will be copied on all generated classes.

@johncarl81
Copy link
Contributor Author

Is this PR waiting on this one to be resolved: johncarl81/parceler#30 ?

@DayS
Copy link
Contributor
DayS commented Jun 1, 2014

This seems great.. But I'm sorry, I don't like being dependent on another Android framework (transfuse here). I was thinking about having our own implementation (transfuse free) based on your work :x

I'll have to close this one then.

@DayS DayS closed this Jun 1, 2014
@johncarl81
Copy link
Contributor Author

Shoot, I was looking forward to this collaboration.

I have a couple of points to clarify:

First, Parceler depends on a common codebase as Transfuse: transfuse-bootstrap, transfuse-core, and transfuse-support. This common codebase is not the android specific portion of Transfuse (regular transfuse), however, it is an eat-your-own-dog-food initiative that resulted in a set of generalized libraries for compile-time DI and annotation processor support. Parceler uses these libraries for DI within the annotation processor to solve a number of other common problems with annotation processors.

Second, this PR does not introduce Parceler or Parceler's dependencies as a dependency of AA. I was very careful to reference Parceler by String class name ie:

codeModel().ref("org.parceler.Parcels")

If you do a mvn dependency:tree on this branch of AA, you won't find Parceler or Parceler's dependencies as a dependency. Parceler is completely optional to the end user:

$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building AndroidAnnotations Annotation Processor 3.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ androidannotations ---
[INFO] org.androidannotations:androidannotations:jar:3.1-SNAPSHOT
[INFO] +- org.androidannotations:androidannotations-api:jar:3.1-SNAPSHOT:compile
[INFO] +- com.sun.codemodel:codemodel:jar:2.4.1:compile
[INFO] +- junit:junit:jar:4.8.1:test
[INFO] +- com.google.guava:guava:jar:13.0.1:test
[INFO] +- com.google.android:android:jar:4.1.1.4:provided
[INFO] |  +- commons-logging:commons-logging:jar:1.1.1:provided
[INFO] |  +- org.apache.httpcomponents:httpclient:jar:4.0.1:provided
[INFO] |  |  +- org.apache.httpcomponents:httpcore:jar:4.0.1:provided
[INFO] |  |  \- commons-codec:commons-codec:jar:1.3:provided
[INFO] |  +- org.khronos:opengl-api:jar:gl1.1-android-2.1_r1:provided
[INFO] |  +- xerces:xmlParserAPIs:jar:2.6.2:provided
[INFO] |  +- xpp3:xpp3:jar:1.1.4c:provided
[INFO] |  \- org.json:json:jar:20080701:provided
[INFO] \- org.springframework.android:spring-android-rest-template:jar:1.0.0.RELEASE:test
[INFO]    \- org.springframework.android:spring-android-core:jar:1.0.0.RELEASE:test

If you guys change your mind regarding this integration please let me know. Otherwise, I'm happy to help where I can if you run into issues with or have questions about your implementation.

Cheers and good luck!

@WonderCsabo
Copy link
Member

@johncarl81 i think we can revisit this one. It would be nice to have our implementation of Parcelable generators, but for the sake of AA + Parceler users, we could add this integration.

I think this PR was rejected, because the it seemed that AA will always need the Parceler processor. However as you explained it in the last comment, it is only needed if the user actually adds it, and will not make an difference at all for non Parceler users.

@johncarl81
Copy link
Contributor Author

@WonderCsabo, ok, sounds good.

Since we ended this effort a few other libraries picked up Parceler support. I'd like to highlight FragmentArgs' implementation as it offers further decoupling which may be of interested for AA. FragmentArgs offers an interface to handle any extra serialization concerns. This plays well into how the Parcels utility class wraps / unwraps @Parcel annotated beans (and ones that may not i.e. @ParcelClass). Here's the relevant classes:
https://github.com/sockeqwe/fragmentargs/blob/master/annotation/src/main/java/com/hannesdorfmann/fragmentargs/bundler/ArgsBundler.java
https://github.com/sockeqwe/fragmentargs/blob/master/bundler-parceler/src/main/java/com/hannesdorfmann/fragmentargs/bundler/ParcelerArgsBundler.java
https://github.com/sockeqwe/fragmentargs/#argsbundler

I imagine we could introduce a similar technique into the @Extra annotation:

 @Extra(value = "myParcelerExtra", converter = ParcelerConverter.class) ExampleParceler ep;

If you like this technique I'd be happy to work on a PR.

Also, I took a lesson from this conversation. From this I ended up shading the dependencies the Parceler processor had on Transfuse and Guava. This cleans up the dependency tree associated with Parceler, eliminates any library incompatibilities (remember we had to upgrade Guava), and removes the concern that Transfuse would be included along with Parceler. Parceler is now simply 2 jars, the Parceler processor and Parceler API.

@WonderCsabo
Copy link
Member

Well, i am not a real fan of shading, as it has lots of drawbacks, and kicks the dependency management concept in the ass. But it is needed sometimes, and who am i to tell when it is, so i accept your decision. :)

I like the idea of decoupling, but i think adding the converter parameter always is inconvenient. A static method should be available to set the default one. I also i think we should still use Parceler for your annotated classes even if the client do not explicitly set the converter.

@johncarl81
Copy link
Contributor Author

In that case we could simply more forward with the previous approach that will decorate the get/set calls to the extra with Parcels.wrap/unwrap if @Parcel exists on the target extra. Honestly, this is the most straight forward approach.

I'd just like to emphasize that the target extra may have a generated Parcelable but may not be annotated by @Parcel. Here's the case: http://parceler.org#classes_without_java_source .
We could have a scenario like the following:

@InjectExtra("parcelerExtra") Example e;

public class Example{}

@ParcelClass(Examle.class)
public class SomeOtherClass{}

I'd imagine we would error in this case. Not sure if this is a concern for you, but it would be a gap in the integration.

WDTY?

@WonderCsabo
Copy link
Member

In that case we could simply more forward with the previous approach that will decorate the get/set calls to the extra with Parcels.wrap/unwrap if @parcel exists on the target extra.

Hmm, i a little bit confused here. Previous is your old implementation in this PR? And decorate is the converter or our get/set?

Edit: ok, i guess you mean just the old implementation.

About @ParcelClass: i read all the comments, i do not forgot it. :) My question is: why we cannot handle that like we handle @Parcel? Edit: i think i do not really know what @ParcelClass is exactly doing.

@johncarl81
Copy link
Contributor Author

Yes, the "previous" implementation I am referring to is the old impl in this PR. By decorate Im referring to what Im doing with Parcels.wrap() / unwrap() in this PR.

@ParcelClass allows you to generate a Parcelable wrapper without annotating the target class. Notice in the example I gave, a Parcelable is generated for Example, but Example is not annotated with @Parcel, instead it is referenced via the value parameter of @ParcelClass. This is handy for classes that you can't edit the Java source (such as in a library).

I see the problem being that it's hard to detect that a given class is a candidate for wrapping if the target class isn't annotated directly with the @Parcel annotation.

Here's the possible implementations I see (and I've seen in the community):

  1. Don't handle @ParcelClass referenced Parcelable wrapping. I can't say this is the best scenario, but this is a corner case. This is the case with this PR at the moment.
  2. Add a parameter to @Extra (ie: @Extra(value="forced", forceParceler = true)) to force writing the Parcels.wrap/unwrap call. This would be a fall-back case in the event that this corner case is reached. This is what we do on Transfuse at the moment: http://androidtransfuse.org/documentation.html#parcel (although Im considering moving to something like FragmentArgs implemented).
  3. Add a parameter to @Extra to handle conversions like FragmentArgs did (mentioned earlier in this tread.
  4. Perform an initial scan of the classes being compiled for the @ParcelClass annotation and store the the referenced class value in a repository. Then, when generating @Extra reads / writes and the given type matches a class in the repository generate the wrapping/unwrapping code. Honestly, I've considered doing this in Transfuse, but this approach is pretty involved for such a small feature. Also, I'm not sure how this would fit into the AA architecture in general.

I'm sure there are other approaches. My recommendation is to go with point 3 and secondarily 2.

@WonderCsabo
Copy link
Member

@johncarl81 yeah, i understood @ParcelClass after i wrote the comment. :)

I had an idea: can the same annotation be claimed by two annotation processors? If so, we could process @ParcelClass and add it in the a map easily, then use it when processing @Extra etc.

Also please note we copy all non-AA annotations to our generated subclasses, so if two annotation processors cannot claim the same annotation in a round, maybe we could claim it only the first round, and Parceler can claim it in the second.

But i think we an handle @ParcelClass later. I am okay with your approach here, can you update it onto develop and push another PR? Also please note i can review the PR soon, but i can only merge it later, because we are currently doing a very big refactor #1480, and we the develop branch is currently frozen.

@WonderCsabo
Copy link
Member

@johncarl81 any news on this one?

@johncarl81
Copy link
Contributor Author

Sorry, I haven't given this any attention since we last talked. I'll try to get something going soon.

@johncarl81
Copy link
Contributor Author

@WonderCsabo, just reread this thread, yes, we could have AA recognize @ParcelClass, but maybe that would be better to address this corner case if it becomes an issue. Also, as you mentioned, we can always add the static calls by hand. To confirm, for now we will be looking for classes annotated with @Parcel and if AA finds that the extra is annotated it will wrap the get/set calls with the Parcels.wrap/unwrap calls. Is this correct? Should we also wrap get/set calls around the @FragmentArgs?

@WonderCsabo
Copy link
Member

@johncarl81 we have a bunch of annotations which extract from / add objects to Intents. This is all handled in our BundleHelper class. I think it would be enough to just modify that class. I just checked the old changes of yours, and i think it is possible.

About @ParcelClass: i agree, let's focus on @Parcel for now.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

0