55

I am attempting to deserialize a JSON object stored in CouchDb using Jackson. This object needs to deserialize into a pojo that contains overloaded methods. When I attempt to retrieve the object from couch and do the deserialization I get the following exception:

org.ektorp.DbAccessException: org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property "multiplier": com.db.commodities.framework.sdos.model.security.EqOpt#setMultiplier(1 params) vs com.db.commodities.framework.sdos.model.security.EqOpt#setMultiplier(1 params)

I tried to annotate the setter I would like Jackson to use, but that appears to not have worked.

@JsonProperty("multiplier")
public void setMultiplier(SDOSAttribute multiplier) {
     this.multiplier = multiplier;
}

public void setMultiplier(double multiplier) {
     this.multiplier.setValue(String.valueOf(multiplier));
}

How do I configure Jackson to properly deserialize using a specific method? Or am I approaching this problem the wrong way?

EDIT:

I have made the following changes. This seems to work, but is a little uglier. If anyone has a better way to do this please feel free to share and I will gladly accept.

@JsonProperty("multiplier")
protected void setMultiplierAttribute(SDOSAttribute multiplier) {
    this.multiplier = multiplier;
}

@JsonIgnore
public void setMultiplier(double multiplier) {
    this.multiplier.setValue(String.valueOf(multiplier));
}
gregwhitaker
  • 13,124
  • 7
  • 69
  • 78
  • Yes, this is valid fix. I agree in that it would be nice if inference was used such that if only one alternative was explicitly indicated, others could be ignored in case of overload ambiguity -- I can add a Jira feature request for this. – StaxMan Jun 15 '11 at 20:57
  • One other thing -- it is interesting that there is an overload issue here, since Jackson actually does allow limited overload. Specifically, if argument was int or long (instead of double), problem would not occur. But other primitive types (double, float, boolean, char, byte, short) are not supported this way; although float and double probably should be. With int and long difference is resolved based on what JSON has -- JSON objects use POJO setter; JSON numbers int or long. – StaxMan Jun 15 '11 at 21:04

4 Answers4

56

It's not necessary to change the name of the setter method to avoid ambiguity. You're otherwise on the right track with @JsonIgnore. With @JsonIgnore on all of the same-named methods to be ignored, the one to use does not need the @JsonProperty annotation.

Here's a simple example to demonstrate this point.

input.json: {"value":"forty-two"}

Foo.java:

import java.io.File;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  String value;

  public String getValue() {return value;}
  public void setValue(String value) {this.value = value;}

  @JsonIgnore
  public void setValue(int value) {this.value = String.valueOf(value);}

  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    Foo foo = mapper.readValue(new File("input.json"), Foo.class);
    System.out.println(mapper.writeValueAsString(foo));
  }
}

If you don't want to alter the pristine POJO defs with a Jackson annotation, then you can use a MixIn.

import java.io.File;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  String value;

  public String getValue() {return value;}
  public void setValue(String value) {this.value = value;}
  public void setValue(int value) {this.value = String.valueOf(value);}

  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.getDeserializationConfig().addMixInAnnotations(Foo.class, IgnoreFooSetValueIntMixIn.class);
    Foo foo = mapper.readValue(new File("input.json"), Foo.class);
    System.out.println(mapper.writeValueAsString(foo));
  }
}

abstract class IgnoreFooSetValueIntMixIn
{
  @JsonIgnore public abstract void setValue(int value);
}
Programmer Bruce
  • 64,977
  • 7
  • 99
  • 97
  • 5
    What about when you cannot alter the class, when it's third party? Is there a method for that? – crunchdog Jan 23 '13 at 12:15
  • 1
    Jackson's Mix-In facility may well suit your needs. It allows you to effectively annotate third party type definitions, without altering the originals. – Programmer Bruce Jan 23 '13 at 16:23
  • 6
    This solution seems to be ignoring both `setValue` properties (i.e., nothing gets set even though the JSON contains a value). Turns out you *do* need the `@JsonProperty("value")` on the one you want to keep. – mckamey Jun 11 '13 at 00:38
  • 4
    as of jackson 1.9, this solution no longer works. `@JsonIgnore` on any setter / getter / associated field applies the same to the property. – Jeffrey Blattman Jan 10 '14 at 01:03
  • 3
    Using jackson 1.9, I only needed `@JsonProperty("value")` on the correct setter (no `@JsonIgnore` on overloaded setters). – mmindenhall Feb 11 '14 at 20:21
  • 2
    Using Jackson 2.4, using only @JsonIgnore on the setters to be ignored *does* work. – pacoverflow Mar 20 '15 at 16:14
  • Lol, how ridiculous to switch back and forth. I am pulling in jackson-datatype-joda 3.0.0 which requires both annotations. I see v4.* brings in the updated jackson libraries so that only the @JsonIgnore property is needed. – Prancer Aug 13 '15 at 14:10
  • ackson 2.9.9 ignores the property completly if @JsonIgnore is added to one of the overloaded methods. Therefor
    @JsonProperty
    on one of the methods worked (no @JsonIgnore more needed).
    – radicarl Jun 07 '19 at 12:09
9

In Jackson > 2.4 use directly :

mapper.addMixIn(Foo.class, IgnoreFooSetValueIntMixIn.class);
gribo
  • 455
  • 3
  • 10
  • In other words, Jackson > 2.4 mean, if you are using com.fasterxml package instead of org.codehaus , then one needs to use this solution. – KnockingHeads Jul 30 '21 at 09:59
2

In cases where @JsonIgnore doesn't help (I currently have such a case, but am still unsure of the reason), it is also possible to use @XmlTransient instead.

lilalinux
  • 2,903
  • 3
  • 43
  • 53
0
@JsonSetter
public void setMultiplier(SDOSAttribute multiplier) {
     this.multiplier = multiplier;
}

public void setMultiplier(double multiplier) {
     this.multiplier.setValue(String.valueOf(multiplier));
}