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

@JsonSetter affects serialization too #1519

Closed
tfga opened this issue Feb 6, 2017 · 5 comments
Closed

@JsonSetter affects serialization too #1519

tfga opened this issue Feb 6, 2017 · 5 comments

Comments

@tfga
Copy link

tfga commented Feb 6, 2017

According to the docs, @JsonSetter is supposed to affect only deserialization and allow for "asymmetric naming":

(...) this annotation was briefly deprecated for version 1.5; but has since been un-deprecated to both allow for asymmetric naming (possibly different name when reading and writing JSON) (...)

But it's affecting serialization too. It's behaving like @JsonProperty.

Jackson versions used:

+- com.fasterxml.jackson.core:jackson-core:jar:2.8.3:compile
+- com.fasterxml.jackson.core:jackson-databind:jar:2.8.3:compile
+- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.3:compile
\- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.8.3:compile
   +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.8.3:compile
   \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.8.3:compile

Unit test:

import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.ObjectMapper;

class A {
    
    private Integer id;

    public A() {
    }

    public A(Integer id) {
        
        this.id = id;
    }

    public Integer getId() {
        return id;
    }

    @JsonSetter("number")
    public void setId(Integer id) {
        
        this.id = id;
    }
    
    /*
     * Workaround:
     * 
     * Change the name of the method above (setId) to something else and the bug goes away.
     * 
     */
}


public class JsonSetterTest {

    public <T> String toJSON(T to)
    {
        final ObjectMapper mapper = new ObjectMapper();

        try
        {
            return mapper.writeValueAsString(to);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }
    
    @Test 
    public void toJSON() { 
         
        A a = new A(1); 
         
        String json = toJSON(a);
        
        System.out.println(json);
        
        assertTrue(json.contains("id"));
    }
}
@cowtowncoder
Copy link
Member

Documentation may be wrong; @JsonSetter does not only affect deserialization. While it can indeed be used for asymmetric naming (similar to @JsonProperty itself with "split" annotation), its scope is not limited.
It may have been at some point, but after unification of property handling (in 1.8 or so), there is less separation between various property accessors.

I can review Javadocs to make it clear that none of annotations is strictly limited in scope -- some may only be relevant to one or the other, but none is intentionally separated.

@tfga
Copy link
Author

tfga commented Feb 7, 2017

Let's suppose we have a variable a (like in the test case):

A a = new A(1);

With no annotations, a is serialized as {"id":1}.

If you add @JsonSetter("number") to setId, then it's serialized as {"number":1}.

If, however, you rename setId to anything else (e. g. setId_), then it's serialized again as {"id":1}.

Is this the expected behavior?

@cowtowncoder
Copy link
Member

cowtowncoder commented Feb 7, 2017

@tfga yes. If this is not what you want, you need to add additional @JsonProperty markers for other accessors.

@tfga
Copy link
Author

tfga commented Feb 20, 2017

I don't understand... Why would @JsonSetter have anything to do with serialization? And why would its behavior change depending on the name of the method it is attached to?

@cowtowncoder
Copy link
Member

@tfga SInce you feel the need to ask such questions, you really, should to read how system works. Serialization and deserialization are closely tied, and naming is something that concerns both. And existing name of method is of crucial importance: this is the implicit name used to connect things. Without such linkage (between setX() and getX(), or plain T name()/name(T value)) more annotations would be used for renaming. While this is possible theoretically this is approach Jackson has taken. You are free to disagree with that approach, but you do not get define it.

It is true that there is redundancy currently in that @JsonSetter is not strictly necessary (any more, at least), but there is no meaningful way it could or should only affect deserialization, given that property discovery, including naming, is a shared concern between read and write sides.

And at this point this is as much time as I will spend on explaining the system.

As per my earlier note, yes, result is as expected. Implicit id property has been renamed as number, due to annotation. The way to prevent that is to use another annotation. Use case here is a minority use case compared to the case where renaming is expected to affect all accessors.

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