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

JsonProperty.Access.READ_ONLY does not work with "getter-as-setter" Collections #2118

Closed
zhangyangyu opened this issue Aug 23, 2018 · 6 comments
Milestone

Comments

@zhangyangyu
Copy link

zhangyangyu commented Aug 23, 2018

I could still encounter the problem that JsonProperty.Access.READ_ONLY not work. I have read #1805 , and my jackson.databind version is 2.9.5. I also checked 2.9.6.

I have reduced my example as:

//AppTest.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

public class AppTest {
    @Test
    public void test() throws Exception {
        String data ="{\"security_group_rules\": [{\"id\": \"id1\"}, {\"id\": \"id2\"}, {\"id\": \"id3\"}, {\"id\": \"id4\"}]}";
        ObjectMapper mapper = new ObjectMapper();
        SecurityGroup sg = mapper.readValue(data, SecurityGroup.class);
        System.out.println(mapper.writeValueAsString(sg));
    }
}
//SecurityGroup.java
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Lists;
import java.util.List;

public class SecurityGroup {

    private List<SecurityGroupRule> securityGroupRules;

    public SecurityGroup() {
        this.securityGroupRules = Lists.newArrayList();
    }

    @JsonProperty(value="security_group_rules", access=JsonProperty.Access.READ_ONLY)
    public List<SecurityGroupRule> getSecurityGroupRules() {
        return securityGroupRules;
    }

    public SecurityGroup setSecurityGroupRules(List<SecurityGroupRule> securityGroupRules) {
        this.securityGroupRules = securityGroupRules;
        return this;
    }
}
//SecurityGroupRule.java
import com.fasterxml.jackson.annotation.JsonProperty;

public class SecurityGroupRule {

    private String id;

    public SecurityGroupRule() {

    }

    @JsonProperty
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

I hope securityGroupRules won't be deserialized but it still is. If I change JsonProperty(value="security_group_rules", access=JsonProperty.Access.READ_ONLY) to JsonIgnoreProperties(value="security_group_rules", allowGetters=true) as metioned in #1805, it throws UnrecognizedPropertyException instead of printing {"security_group_rules":[{"id":"id1"},{"id":"id2"},{"id":"id3"},{"id":"id4"}]}. I'd like the former behaviour since in project I can set FAIL_ON_UNKNOWN_PROPERTIES to avoid the error.

@zhangyangyu zhangyangyu changed the title JsonProperty.Access.READ_ONLY not work JsonProperty.Access.READ_ONLY still not work Aug 23, 2018
@cowtowncoder
Copy link
Member

@zhangyangyu I can reproduce the issue, but have to think if and how to fix it.

The problem is that by default setting

 MapperFeature.USE_GETTERS_AS_SETTERS

is true, and this means that for Collections and Maps, "getter" method may be used in absence of setter to get instance to modify.
What happens here, then, is that getter is used normally (since READ_ONLY only drops setter), but also to allow deserialization.

You can change this behavior by disabling MapperFeature.USE_GETTERS_AS_SETTERS, in the meantime.

cowtowncoder added a commit that referenced this issue Apr 4, 2020
@zhangyangyu
Copy link
Author

zhangyangyu commented Apr 9, 2020

Thanks for reply and explanation. Changing a global config could solve the problem but might not ideal. I hope READ_ONLY could take precedence over USE_GETTERS_AS_SETTERS on a signal property since it's explicitly specified and closer to what the author means.

@jdussouillez
Copy link

jdussouillez commented May 13, 2020

I have the same issue with v2.11.0

Code snippet :

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper()
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    String json = mapper.writeValueAsString(new Bar());
    System.out.println(json);
    System.out.println("Deserialized: " + mapper.readValue(json, Bar.class));
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public static abstract class Foo {

    @JsonProperty(value = "subfields", access = JsonProperty.Access.READ_ONLY)
    protected abstract Set<String> subfields();
}

public static class Bar extends Foo {

    @Override
    protected Set<String> subfields() {
        return Set.of("a", "b");
    }
}

I get any UnsupportedOperationException because Set.of returns an unmodifiable set. Using a "standard" Set implementation fixes the issue.


I managed to fix it by adding the annotation @JsonIgnoreProperties(value = {"subfields"}, allowGetters = true, allowSetters = false) on the Foo class. But I think the JsonProperty.Access.READ_ONLY should prevent any deserialization issue.

I do not want to disable the USE_GETTERS_AS_SETTERS which is very useful in my app. Is there any better solution for this ?

@jdussouillez
Copy link

An simpler way to fix it is to remove the value = "" in the @JsonProperty annotation.

See #2283

@cowtowncoder cowtowncoder changed the title JsonProperty.Access.READ_ONLY still not work JsonProperty.Access.READ_ONLY does not work with "getter-as-setter" Collections May 13, 2020
@cowtowncoder
Copy link
Member

@jdussouillez I think you can achieve this by having both setter and getter, and configuring them separately (use @JsonIgnore on one you want to excluded, @JsonProperty on one to include).

Aside from trying to fix this issue (which I hope to achieve at some point; but fix is not trivial unfortunately), another possibility might be to add a setting for @JsonFormat.Feature that would allow enabling/disabling getter-as-setter on specific properties. Not sure if that would help here.

@cowtowncoder
Copy link
Member

I think I managed to fix this, although verification would be appreciated: fix in 2.12 branch, will be included in 2.12.0 (not backported since changes have non-trivial chance of regression so trying to avoid adding in a patch).

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

3 participants