Summary: | [wiring] NPE when accessing field deserialized with Gson (using @SerializedName) | ||
---|---|---|---|
Product: | z_Archived | Reporter: | EPP Error Reports <error-reports-inbox> |
Component: | Recommenders | Assignee: | Project inbox <recommenders-inbox> |
Status: | NEW --- | QA Contact: | |
Severity: | normal | ||
Priority: | P3 | CC: | sewe |
Version: | unspecified | Keywords: | needinfo |
Target Milestone: | --- | ||
Hardware: | All | ||
OS: | All | ||
Whiteboard: |
Description
EPP Error Reports
2015-11-11 07:12:22 EST
While the NPE occurs in a third-party plugin (Codetrails Connect), this nevertheless hints at an issue in org.eclipse.recommenders.utils and Gson. Hence, I am *not* closing as NOT_ECLIPSE for now. A bit more context about the third-party code, some of which was written by me: An OverrideFrequencyModel is deserialized using Gson, from a JSON string which has an "overrides" property. But apparently OverrideFrequencyModel.overrides is null. @SerializedName("overrides") private final Multiset<IMethodName> f = HashMultiset.create(); Now, I am 100% sure that the JSON strings that we deserialize do not contain "overrides": null so the question is how this field ends up being null (instead of the default, non-null value). Here's my theory: @SerializedName is not honored, so the "overrides" property in the JSON input is not copied over into f. Alas, due to this Gson 2.2.4 bug [1], the default value of HashMultiset.create() is not used for f either. As to why @SerializedName is not honored, this may be a wiring issue, which arises in the following scenario: 1. The user installs Code Recommenders and with it org.eclipse.recommenders.utils and version X of com.google.gson. 2. Equinox wires org.eclipse.recommenders.utils to the package com.google.gson from com.google.gson, version X. 3. Some other installation causes com.google.gson, version Y > X, to be installed. The wiring for org.eclipse.recommenders.utils remains unchanged. 4. The user installs Codetrails Connect and with it com.codetrails.connect.hippie. This bundle requires org.eclipse.recommenders.utils and imports both com.google.gson and com.google.gson.annotations (for @SerializedName). Because of the uses constraints of o.e.r.utils, the package com.google.gson gets wired to version X (the same version as used by o.e.r.utils). However, o.e.r does not import com.google.gson.annotations and hence places no constraints on it. Hence, Equinox chooses the newer version Y. 5. com.codetrails.connect.hippie uses com.google.gson, version X, to deserialize its data. However, Gson does not recognize the @SerializedName annotation, as it is loaded with the classloader of com.google.gson, version Y. Thus, whatever is in the "overrides" property is not put into field f. 6. Now, bug [1] kicks in, so we don't get the default value of HashMultiset.create() either, but null instead. [1] <https://github.com/google/gson/issues/513> (In reply to Andreas Sewe from comment #1) > Here's my theory: > > @SerializedName is not honored, so the "overrides" property in the JSON > input is not copied over into f. Alas, due to this Gson 2.2.4 bug [1], the > default value of HashMultiset.create() is not used for f either. > > As to why @SerializedName is not honored, this may be a wiring issue, which > arises in the following scenario: > > 1. The user installs Code Recommenders and with it > org.eclipse.recommenders.utils and version X of com.google.gson. > > 2. Equinox wires org.eclipse.recommenders.utils to the package > com.google.gson from com.google.gson, version X. > > 3. Some other installation causes com.google.gson, version Y > X, to be > installed. The wiring for org.eclipse.recommenders.utils remains unchanged. > > 4. The user installs Codetrails Connect and with it > com.codetrails.connect.hippie. This bundle requires > org.eclipse.recommenders.utils and imports both com.google.gson and > com.google.gson.annotations (for @SerializedName). Because of the uses > constraints of o.e.r.utils, the package com.google.gson gets wired to > version X (the same version as used by o.e.r.utils). However, o.e.r does not > import com.google.gson.annotations and hence places no constraints on it. > Hence, Equinox chooses the newer version Y. > > 5. com.codetrails.connect.hippie uses com.google.gson, version X, to > deserialize its data. However, Gson does not recognize the @SerializedName > annotation, as it is loaded with the classloader of com.google.gson, version > Y. Thus, whatever is in the "overrides" property is not put into field f. If the com.google.gson bundle includes uses constraints, this issue cannot happen: The constraints on com.google.gson would prevent com.codetrails.connect.hippie to wire to different versions of com.google.gson and com.google.gson.annotations. I hence filed a bug with Gson [1] to add such constraints. [1] <https://github.com/google/gson/issues/735> I admit that the theory in comment 1 is a bit far-fetched. Alas, it is ATM the only one I have that can explain the NPE on this line return overrides.count(method); given that private final Multiset<IMethodName> overrides = HashMultiset.create(); I am afraid, we need some more information from the user who reported this issue. Could you please do the following: - Open the "Console" view. - Select the "Host OGSi console" (pre-installed in Eclipse for JEE Developers). - Enter the following commands and report their result here: ss gson p com.google.gson p com.google.gson.annotations p com.google.gson.reflect p com.google.gson.stream Thank you very much. FYI, a second incident (same reporter) occurred in virtually identical situation [1]. [1] <https://dev.eclipse.org/recommenders/committers/confess//#/problems/564302fee4b0c02da2cfddc0/triage> |