Skip to content
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

AUTO_DETECT_SETTERS no effect on deserialization #1071

Closed
josefguenther opened this issue Jan 6, 2016 · 6 comments
Closed

AUTO_DETECT_SETTERS no effect on deserialization #1071

josefguenther opened this issue Jan 6, 2016 · 6 comments

Comments

@josefguenther
Copy link

I have globally disabled setters like so:

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.autoDetectFields(false).autoDetectGettersSetters(false);
    converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}

I have also tried using the ObjectMapper to configure like so:

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
    mapper.setVisibility(PropertyAccessor.FIELD, Visibility.NONE);
    mapper.setVisibility(PropertyAccessor.GETTER, Visibility.NONE);
    mapper.setVisibility(PropertyAccessor.SETTER, Visibility.NONE);
    builder.configure(mapper);
    converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}

I have also attempted to disable setters on my entity like so:

@JsonAutoDetect(fieldVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
@Entity
public class SomeEntity {
    private transient String something;
    public String getSomething () {
        return something;
    }
    public void setSomething (String something) {
        this.something = something;
    }
}

I can disable getters in the above manner and it works, ie, the fields (in this case 'something') do not get serialized.

When I deserialize some json specifying 'something', IT WILL CONTINUE TO USE THE SETTER METHOD.

{ "something": "test" }

I have only been able to successfully ignore the 'something' setter method like this:

    @JsonIgnore
    public void setSomething (String something) {
        this.something = something;
    }

I tried enabling 'PROPAGATE_TRANSIENT_MARKER' which from what I understand may disable the setter (since my field is marked as transient), that also failed to disable the setter (and getter for that matter, I guess I don't understand that property).

I also attempted disabling 'USE_GETTERS_AS_SETTERS', but that had no effect either.

Just an FYI: I am using jackson-databind-2.6.4. I am also using Spring (4.2.4). I was not able to test databind 2.7.0-rcX since it threw exceptions.

@josefguenther josefguenther changed the title AUTO_DETECT_SETTERS has unpredictable effect on deserialization AUTO_DETECT_SETTERS no effect on deserialization Jan 6, 2016
@josefguenther
Copy link
Author

Quick correction: enabling 'PROPAGATE_TRANSIENT_MARKER' does work insofar as everything gets disabled. So the setters got disabled as well!

But enabling a getter using '@JsonGetter' also enables the setter.

@cowtowncoder
Copy link
Member

@josefguenther The way annotations on setters, getters work is that if only one annotation (like @JsonIgnore to exclude; or @JsonProperty to include) is found, that will take effect. If only getter or setter should be ignore; other one included, it is necessary to add another annotation "split" accessors: so, for example, @JsonIgnore on one, @JsonProperty on the other.

Think of it this way: Jackson tries to create a logical property instance, and then gather all information for it. With all information available, it will then try to figure out intent from minimal amount of information.
Add to this various visibility settings and number of combinations becomes rather big.

Having said that, your original case where you are disabling auto-detection for setters and fields should indeed prevent deserialization.

Would it be possible to create a stand-alone test method, from code you included above, which recreates the problem only using jackson-databind? Sometimes there are issues with integration within framework, so it is important to figure out where the problem occurs.

@josefguenther
Copy link
Author

Ok I went ahead and made a test project for you.

I was able to determine a few things:

  1. Using the ObjectMapper.setVisibility() features works as expected.
  2. Using the ObjectMapper.disable() does NOT DISABLE SETTERS
  3. The Spring provided Jackson2ObjectMapperBuilder does not respect the Visibility settings, it only supports the disable() function, so it will ALWAYS FAIL

Summary:

// This works
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.GETTER, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.SETTER, Visibility.NONE);
// This DOES NOT WORK
// ONLY GETTERS ARE SUCCESSFULLY DISABLED
mapper.disable(MapperFeature.USE_GETTERS_AS_SETTERS);
mapper.disable(MapperFeature.AUTO_DETECT_FIELDS);
mapper.disable(MapperFeature.AUTO_DETECT_GETTERS);
mapper.disable(MapperFeature.AUTO_DETECT_SETTERS);
mapper.disable(MapperFeature.AUTO_DETECT_IS_GETTERS);

Attached is the test project:

testjacksonsetters.zip

@josefguenther
Copy link
Author

@cowtowncoder Any update? Were you able to confirm?

As an aside on the @JsonProperty annotation, that is fine. I understand it. But setting a @JsonGetter should not be the same thing as @JsonProperty -- I do not expect it to automatically enable @JsonSetter as well wethout even specifying it! There should be a setting to turn off this 'feature'... Basically my model has about 50 @JsonIgnore annotations -- one for each property and most setters. It is VERY annoying.

@cowtowncoder
Copy link
Member

@josefguenther Haven't had time yet unfortunately.

As to @JsonGetter: your inference from naming here is unfortunately incorrect: there is really very little difference between @JsonGetter and @JsonProperty at this point. Naming is confusing, but naming does not drive functionality; implied meaning does not dictate actual intended behavior.
@JsonGetter and @JsonSetter were in fact planned to be deprecated during 1.x development, due to redundancy.

About the only difference from @JsonProperty is the precedence; @JsonGetter has priority for serialization (over property), and @JsonSetter similarly for deserialization. It is not clear whether this difference has good uses.

So: for all practical purposes, @JsonProperty, @JsonGetter and @JsonSetter are indeed equivalent. There is nothing to turn off as that is the behavior. But documentation should reflect this state.

This is not to say that visibility handling could not have issues; I hope to find time to look into this issue in near future.

One more thing that might be helpful, in general: @JsonProperty has property access, so you can use:

@JsonProperty(access=Access.READ_ONLY)
protected int value;

to actually prevent deserialization, and only allow serialization. This feature was added in Jackson 2.6.
Intention was to make read-only and write-only properties easier to define, resulting annotations easier to read.

@cowtowncoder
Copy link
Member

At this point I would need a unit test reproducing remaining problem (if one still exists) against later version like 2.8.7.

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

No branches or pull requests

2 participants