Skip to content
This repository has been archived by the owner on Jan 22, 2019. It is now read-only.

Transient fields serialized when @XmlAccessorType(XmlAccessType.FIELD) is present #61

Closed
dsharp1 opened this issue Aug 26, 2016 · 15 comments
Milestone

Comments

@dsharp1
Copy link

dsharp1 commented Aug 26, 2016

private transient fields are serialized when the class is annotated with XmlAccessType.FIELD.

The cause is related to the way that the _addFields method in POJOPropertiesCollector determines if the field should be skipped. If the field is transient AND the field name is null (where the field name is determined by XmlElement, XmlElementWrapper, etc), the field is marked as not visible and gets skipped.

When the isVisible method in JaxbAnnotationIntrospector returns true if the annotated class has a XmlAccessType.FIELD class annotation, this causes the name to be returned as PropertyName.USE_DEFAULT instead of null. This means that the name is not null (its and empty string) when _addFields method checks the transient field and therefore it does not check if the field is transient.

The attached unit test demonstrates the use case and results in a stackoverflow due to infinite recursion. Removing the @XmlAccessorType(XmlAccessType.FIELD) will allow the test to run without an error.
simple.zip

@dsharp1
Copy link
Author

dsharp1 commented Aug 26, 2016

The changed that exposed this issue was made a couple months ago in POJOPropertiesCollector. The check for hasName is true since USE_DEFAULT is an empty string.

        if (f.isTransient()) {
            // 20-May-2016, tatu: as per [databind#1184] explicit annotation should override
            //    "default" `transient`
            if (!hasName) {
                visible = false;
                if (transientAsIgnoral) {
                    ignored = true;
                }
            }
        }

@cowtowncoder
Copy link
Member

Thank you for reporting this. I hope to look into it soon.

@cowtowncoder
Copy link
Member

Unfortunately I can not reproduce this locally with JSON output, with version 2.8.1, using classes shown in simple.zip.

@dsharp1
Copy link
Author

dsharp1 commented Aug 31, 2016

I am not sure why that would be. The issue occurs for me in 2.8.1, 2.8.2-SNAPSHOT, and 2.8.3-SNAPSHOT. Let me detail my steps a little further and maybe you can compare against the steps that you performed.

  1. cloned and pulled jackson-module-jaxb-annotations (branch = master)
  2. With the attached simple.zip, I extracted the zip into the src/test/java folder.
  3. Added the dataformat dependency to the root pom.xml:

    com.fasterxml.jackson.dataformat
    jackson-dataformat-xml
    ${version.jackson.core}
    test
  4. run "mvn clean test"

If I run the same test in the jackson-dataformat-xml project, I do not need to add the extra dependency, and the result is the same.

@dsharp1
Copy link
Author

dsharp1 commented Aug 31, 2016

I added an assertion to the code to see if that makes a difference for you when you run it. Also, I am attaching the pom.xml with the dependency required to run this.
simple2.zip

@rpatrick00
Copy link

jaxb-annotations-bug-61.zip is a simple example to reproduce the problem with Jackson 2.8.1. Simply unzip and run mvn test and see the failure.

If you set the jacksonVersion property to 2.7.6 in pom.xml and re-run the test, you will see that the test works properly.

@rpatrick00
Copy link

Any idea when you might have time to review Derek's proposed fix. This regression is preventing us from uptaking Jackson 2.8+. Thanks!

@cowtowncoder
Copy link
Member

@rpatrick00 I haven't had time to look into this. From above I am not 100% what the suggested fix is, although as it is related to name handling of JAXB module, perhaps it can be handled here, locally.
That'd be good since changes to jackson-databind often have higher risk of regression.

@cowtowncoder
Copy link
Member

cowtowncoder commented Sep 17, 2016

Downloaded zip, can reproduce the failure now.
I can also reproduce with json output, when using JAXB annotations.

@cowtowncoder
Copy link
Member

Looks like this has to do with auto-detection; should not see the getter...

@rpatrick00
Copy link

Whatever it is, this change caused the regression. I hope you are able to find a fix...

@cowtowncoder cowtowncoder modified the milestones: 2.8.0-rc3, 2.8.3 Sep 17, 2016
@cowtowncoder cowtowncoder changed the title transient fields serialized when @XmlAccessorType(XmlAccessType.FIELD) is present Transient fields serialized when @XmlAccessorType(XmlAccessType.FIELD) is present Sep 17, 2016
@cowtowncoder
Copy link
Member

Ok. This was bit tricky to resolve, as the change in databind exposed a problem more so than strictly causing it... problem being that JaxbAnnotationIntrospectors way of returning empty String actually implies same as plain @JsonProperty (without explicit name). More ideal would be to just return null, but I am guessing there is/was a reason to do this to boost visibility.
I will have a look at whether this could be simplified for 2.9; but for patch release I just added explicit check for transient to prevent "leakage" this way, and I think that should work well enough.

Thank you for the test case & follow up -- this will be in 2.8.3 patch.

@rpatrick00
Copy link

Thanks! I didn't look as closely at the code as Derek did but it seems like the tests for jaxb annotations directly on the field (to overrides the visibility) is picking up the class-level @XmlAccessorType(XmlAccessType.FIELD) when it shouldn't. In my opinion, a class-level annotation that applies to the field should not be considered when overriding the visibility...

@cowtowncoder
Copy link
Member

@rpatrick00 Class-level visibility only defines visibility for auto-detection, and explicit annotations can further make it certain (inclusion) or remove (exclusion). So @XmlAccessorType(XmlAccessType.FIELD) is translated to equivalent of:

        case FIELD: // all fields, independent of visibility; no methods
            return checker.withFieldVisibility(Visibility.ANY)
                .withSetterVisibility(Visibility.NONE)
                .withGetterVisibility(Visibility.NONE)
                .withIsGetterVisibility(Visibility.NONE)

so yes, modifiers on member itself should override class or global defaults.
But the tricky part is usually that of combining various indicators from different members.

At any rate, please let me know if things do (or do not) work after fix included in 2.8 branch (for 2.8.3).
There's still time for further fixes if necessary.

@dsharp1
Copy link
Author

dsharp1 commented Sep 23, 2016

Your change fixed my issue, thank you.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants