-
Notifications
You must be signed in to change notification settings - Fork 4.4k
added a strategy to manage unknown fields during deserialization #660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project, in which case 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! |
|
CLAs look good, thanks! |
|
Appreciate you taking the time to write this. However, I think the usecase for this is too infrequent to warrant inclusion in standard Gson. Also, the approach is too narrow (for just unknown properties). We have had many requests to provide ability to intercept and validate a Gson generated instance. We would like to see a simple elegant solution to the broader issue. |
|
It is quite frequent. And I would reject solutions as not good enough only when there are other better alternatives presented. But it doesn't look like @inder123 is going to come up with any idea regarding this at all. |
|
I would agree that this is a common problem. For instance, a client sends a JSON object with a field name misspelled. If it is valid for that field to be omitted, you would never know that there was an issue. It would simply get silently ignored. |
|
I would like to have a choice to decide whether GSON should ignore unknown fields or should reject such requests. Sadly, I'm switching now to Jackson to get that. |
|
@inder123 I see a comment from you from over a year ago where you mention many requests like this one to support validation ... can you point me to a discussion where you are working on a more general and elegant solution? If not, please reconsider this PR as it is a simple and elegant approach to the specific problem of receiving unexpected fields in the JSON. |
|
I agree that the user should have the choice. |
|
"I think the usecase for this is too infrequent to warrant inclusion in standard Gson" We would like this use case - and from the looks of the comments so do many others. Jackson has this feature and it seems fairly frequently used (do a search on tutorials and examples). "Also, the approach is too narrow (for just unknown properties). We have had many requests to provide ability to intercept and validate a Gson generated instance. We would like to see a simple elegant solution to the broader issue." That maybe the case, but we came here looking for this exact feature, and only this feature. We want a way to be be able to detect/intercept additional fields in the JSON so that we can report/handle fields that we were not expecting. We spent quite a while trying to shoe-horn this feature in, and there are no hooks available to us to provide this functionality without duplicating all of the core type adapter factory and its supporting classes - that seems a tad wasteful. We took a quick review of the PR code, and it seems very simple, logical and well thought out. Keep the default behavior as is, and existing users wont have to change any code. Provide the builder option and everyone is happy/happier. :-) +1 for taking this PR. |
|
Throwing Exception on encountering an unnknown fields seems weird. JSON is an extensible and flexible format: a client shouldn't be broken by adding a new property in JSON. What about missing fields? Wouldn't you want a similar action? A better way is to use https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/PostConstructAdapterFactory.java |
|
@inder123 As @mcerina mentions in the first comment above, the UnknownFieldHandlingStrategy is extensible and could be used to just log unknown fields if throwing an exception doesn't suit your needs. I looked at PostConstructAdapterFactoryTest and see that your test throws an exception when the sandwich is too cheesy ... and I can see how that could also be used to take some action if a "required" field was missing (i.e. still null during post construct validation) ... but I can't figure out how to use the PostConstructAdapterFactory to catch when an unknown field was present in the original JSON. Can you provide a code example of how the PostConstructAdapterFactory could be used to solve the OP's issue about handling unknown fields? |
|
Can you deserialize the JSON object to get your Java object, then serialize your Java object back to JSON and see if you get the same result (compare the original JSON object to the converted Java JSON)! if not...extra fields! Haven't tried, yet, but this is just a thought. |
|
I am looking for this feature right now. Is the reason for its absence just adherence to dogma? |
|
Still no solution for this problem. |
Marcono1234
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not a maintainer of this project and they will sadly probably not change their mind.
Though maybe this review is helpful nonetheless in case you or someone else is using this code in a fork.
The review comments are mostly documentation related.
| * consideration for serialization and deserialization. You can change this behavior through | ||
| * {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li> | ||
| * <li>By default, during deserialization Gson silently ignores fields that are present in the | ||
| * incoming Json but not in the Java classes. You can change this policy through |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * incoming Json but not in the Java classes. You can change this policy through | |
| * incoming JSON but not in the Java classes. You can change this policy through |
| /** | ||
| * Configures Gson to apply a specific unknown field strategy during deserialization. | ||
| * | ||
| * @param unknownFieldHandlingStrategy the actual naming strategy to apply to the fields |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actual naming strategy
This appears to be wrong
|
|
||
| /** | ||
| * An enumeration that defines a few standard handling strategies for fields | ||
| * present in the incoming Json but not in the Java classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * present in the incoming Json but not in the Java classes. | |
| * present in the incoming JSON but not in the Java classes. |
| * An enumeration that defines a few standard handling strategies for fields | ||
| * present in the incoming Json but not in the Java classes. | ||
| * This enumeration should be used in conjunction with {@link com.google.gson.GsonBuilder} | ||
| * to configure a {@link com.google.gson.Gson} instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * to configure a {@link com.google.gson.Gson} instance | |
| * to configure a {@link com.google.gson.Gson} instance. |
| */ | ||
| THROW_EXCEPTION() { | ||
| public void handleUnknownField(JsonReader in, Object instance, String name) throws IOException { | ||
| String msg = String.format("Unrecognized field \"%s\" (Class %s)", name, instance.getClass().getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use String.format(Locale, String, Object...), e.g. String.format(Locale.ENGLISH, ...) to make the message independent of the system locale.
|
|
||
| /** | ||
| * A mechanism for providing custom unknown property handling in Gson during deserialization. | ||
| * This allows to provide custom behavior to handle fields present in the incoming Json which |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * This allows to provide custom behavior to handle fields present in the incoming Json which | |
| * This allows to provide custom behavior to handle fields present in the incoming JSON which |
| public interface UnknownFieldHandlingStrategy { | ||
|
|
||
| /** | ||
| * Handles a field present in the incoming Json but not in the Java class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * Handles a field present in the incoming Json but not in the Java class | |
| * Handles a field present in the incoming JSON but not in the Java class |
| /** | ||
| * Handles a field present in the incoming Json but not in the Java class | ||
| * | ||
| * @param in the {@link JsonReader} reading the incoming Json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Links in javadoc should be used sparingly and here the generated documentation already links to the type so there is no need to have an additional link here as well.
| * @param in the {@link JsonReader} reading the incoming Json | |
| * @param in the {@code JsonReader} reading the incoming JSON |
| * | ||
| * @param in the {@link JsonReader} reading the incoming Json | ||
| * @param instance the instance of the Java class we are trying to deserialize to | ||
| * @param name the name of the field in the incoming Json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @param name the name of the field in the incoming Json | |
| * @param name the name of the unknown field in the incoming JSON |
| Gson gson = new GsonBuilder().setUnknownFieldHandlingStrategy(THROW_EXCEPTION).create(); | ||
| try { | ||
| gson.fromJson(JSON, ClassWithTwoFields.class); | ||
| Assert.fail("A JsonParseException was expected"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to use TestCase's fail:
| Assert.fail("A JsonParseException was expected"); | |
| fail("A JsonParseException was expected"); |
(and then also remove the import)
See issue #188
While I understand the design choice of ignoring unknown fields during deserialization by default, I definitely think that there are use cases in which throwing an exception, or at least being able to log something is preferred.