Skip to content

Support custom annotation processing#1029

Open
fwonce wants to merge 13 commits intogoogle:mainfrom
fwonce:field-adapter
Open

Support custom annotation processing#1029
fwonce wants to merge 13 commits intogoogle:mainfrom
fwonce:field-adapter

Conversation

@fwonce
Copy link

@fwonce fwonce commented Mar 2, 2017

This discussion and issue #269 talks about the same problem I want to tackle with. I commented under issue #269 to state my reason and write a subject in Gson Group to talk about more detailed design thoughts. Generally speaking, I'd like to see a feature that let me use custom annotations in my data object freely without exposing Gson stuff there, and control the behaviors of reading/writing the fields with those annotations by Gson.

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed, please reply here (e.g. I signed it!) and we'll verify. Thanks.


  • If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check your existing CLA data and verify that your email is set on your git commits.
  • If you signed the CLA as a corporation, please let us know the company's name.

@fwonce
Copy link
Author

fwonce commented Mar 2, 2017

I signed it!

@googlebot
Copy link

CLAs look good, thanks!

@inder123
Copy link
Collaborator

Overall, I like where you are going with this.
A few questions:

  1. Why not support annotation on classes as well?
  2. Would be great if we can demonstrate some real use cases. For example, taking JPA or JAXB annotations, and automatically using them as SerializedName.

Thanks

@fwonce
Copy link
Author

fwonce commented Mar 10, 2017

Hi @inder123 Thanks for your inspiring reply.
Your first advise makes sense to me so I add a few lines to do that. And when considering it, I've realized that in some cases a FieldAdapterFactory should be versatile for both kinds of annotations as a best practice (like d722d40).
But can't write tests for real use cases right now because I do this in spare time. I'll complete it asap:)

EDIT: Is it appropriate to add 3rd-pty test scope dependencies like JPA / JAXB stuff to your pom for writing test cases? Or you mean just give some examples in javadoc?

@inder123
Copy link
Collaborator

You can add JPA/JAXB as test dependencies. We will factor them out in a separate project as this progresses. Thank you!

@fwonce
Copy link
Author

fwonce commented Mar 13, 2017

Speaking of JPA/JAXB, I think the most wanted feature is using the name specified by @Column (JPA) or @XmlElement (JAXB) as the serialized name. So I wrote a test. Before that I had to add the Gson instance as the first argument to FieldAdapterFactory#create. And then I did something like:

Column column = (Column) annotation;
final columnName = column.name();
return new TypeAdapter<T>() {
  @Override public void write(JsonWriter out, T value) throws IOException {
    // ... nullcheck ...
    out.name(columnName); // >>>> Unfortunately this will raise a IllegalStateException <<<<
    TypeAdapter adapter = gson.getAdapter(value.getClass());
    adapter.write(out, value);
  }
  // ... read ...
}

The 6th line will raise a IllegalStateException because ReflectiveTypeAdapterFactory.Adapter#write has already called out.name() right before it and probably there is no simple way to get around unless a major refactor is taken.

Deprecated: So at this point custom annotation processing should be good at dealing with the value part instead of the name part, for which a custom FieldNamingStrategy is more suitable, I think.

On the other hand, I wrote some meaningful tests regarding JPA indeed, like ignoring @Transient or @Version fields when serialization. But I'm not sure if that meets your expectation. Or you may give more information about what kind of use cases you would like to see?

EDIT (21 Apr 2017):
There IS a way to generate the wanted serialized names - kind of tricky. Updated the JPA example

sot of unconvincing to me. so this could be ditched somehow.
@inder123
Copy link
Collaborator

Great progress. @JakeWharton @swankjesse Can you review this as well please?
I think this generic way of binding annotation processing is what we want.

Copy link
Contributor

@swankjesse swankjesse left a comment

Choose a reason for hiding this comment

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

I’m reluctant to add something this powerful to Gson, particularly in this style.

When we did Moshi we decided qualifier annotations were worth including, but we wired them in everywhere – in Moshi’s equivalent of the TypeAdapterFactory. With this we’re introducing a fourth way to link a fieldto an adapter that can encode or decode it (others are @JsonAdapter, TypeAdapter, and JsonSerializer/JsonDeserializer).

I think you’re better off just using @JsonAdapter instead of pushing more complexity and capability into Gson.

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2008 Google Inc.
Copy link
Contributor

Choose a reason for hiding this comment

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

Two small problems here. It’s not 2008, and it’s not Google. Please use “Copyright (C) 2017 Gson Authors”.

Copy link
Author

Choose a reason for hiding this comment

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

Sure. I copied the license lines from the bottom of google/gson's readme page, felt weird at first, but didn't think about it again. Maybe you guys should update it too.

* be ignored.
*
* @author Floyd Wan
* @since 2.8.1
Copy link
Contributor

Choose a reason for hiding this comment

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

unlikely that we’ll release new APIs in a patch release.

* @return the {@link TypeAdapter} for the given {@code field}
* @since 2.8.1
*/
public <T> TypeAdapter<T> getFieldAdapter(Field field) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I do like this shortcut

return null;
}
for (Annotation fieldAnnotation : field.getAnnotations()) {
Class<? extends Annotation> annotationType = fieldAnnotation.annotationType();
Copy link
Contributor

Choose a reason for hiding this comment

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

might be more efficient to loop over the factories and call field.isAnnotationPresent() rather than looping over the field’s annotations. Only because isAnnotationPresent() doesn’t allocate, but getAnnotations() needs to build instances of all of the field’s annotations.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks! I'll pay attention to that every time in the future.

return fieldAdapterFactory.create(fieldAnnotation, field);
}
}
// If both this field and its declaring class matched, ignore the latter one
Copy link
Contributor

Choose a reason for hiding this comment

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

precedence rules? ick

Copy link
Author

Choose a reason for hiding this comment

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

Removed the 'misleading' comment, but I think the logic here is natural - firtst look at the field annotation, and then the class annotations...

@fwonce
Copy link
Author

fwonce commented Mar 20, 2017

Hi @swankjesse!
First, thanks for your review. I have updated according to your inline comments but I'm not sure this is necessary, since you said you are reluctant about this whole idea.

@fwonce
Copy link
Author

fwonce commented Apr 17, 2017

Hi @swankjesse , you haven't made any further comment. Does it mean this is not going to be accepted. In fact, your last comment seemed quite ambiguous to me. The "style" in which to archive this goal can be discussed, if only new features can be assessed and accepted, w/o assuming something too powerful is not welcomed by Gson. Did you suggest that Gson is on its process of going into inactive development and the maintenance team is moving onto something new called Moshi (sorry I haven't heard about it before)?

@inder123 @JakeWharton What's your opinion?

@swankjesse
Copy link
Contributor

I’m reluctant to add large new features to Gson at this time. Large features need careful design and I’m not interested in spending that time to review them.

It’s a popular library and it is very difficult to anticipate the compatibility consequences of any change.

Note that although the project originated at Google, no Google employees are involved at this time.

@fwonce
Copy link
Author

fwonce commented Apr 19, 2017

Got it. For now my only choice is to maintain my own fork. Nevertheless, I have to say I'm quite confident that this PR is backward compatible and solid enough:) In my company, I have applied this version of Gson to many production applications for months and it works fine. There are several interesting use cases enabled by this. Hope you guys will have a second look in the future.

By the way, does Moshi support such kind of feature?

@inder123
Copy link
Collaborator

@swankjesse I think we have been looking for such a powerful feature for quite some time. This may be the fourth way, but for now, it is the only way to make existing annotations work with Gson. I am highly supportive of this, but am fine with looking at an alternate design.

@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.

@googlebot
Copy link

CLAs look good, thanks!

@googlebot
Copy link

We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s). If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and have the pull request author add another comment and the bot will run again.

@google-cla google-cla bot added the cla: no label Nov 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants