user1154644
user1154644

Reputation: 4607

Deserialize String as List of Strings

I have a POJO that contains the following attributes

public class Example {
  @JsonProperty("inputFoo")
  private String foo
  @JsonProperty("inputBar")
  private String bar
  @JsonProperty("inputBaz")
  @JsonDeserialize(using = MyDeserializer.class)
  private Set<String> baz
}

The JSON that I am working with to represent this data currently represents the baz attribute as a single string:

{"inputFoo":"a", "inputBar":"b", "inputBaz":"c"}

I am using the Jackson ObjectMapper to attempt to convert the JSON to my POJO. I know that the input baz String from the JSON wont map cleanly to the Set that I am trying to represent it as, so I defined a custom Deserializer:

public class MyDeserializer extends StdDeserializer<Set<String>> {
   public MyDeserializer(){}

   public MyDeserializer(Class<?> vc) {
      super(vc);
   }

   public Set<String> deserialize(JsonParser p, DeserializationContext cxt) throws IOException, JsonProcessingException {
      String input = p.readValueAs(String.class);
      Set<String> output = new HashSet<>();
      if(input != null) {
         output.add(input);
      }
      return output;
   }
}

I am getting an IllegalArgumentException referencing the "inputBaz" attribute, which I can provide details on. Does anyone see any obvious issue with my deserializer implementation? Thanks

Upvotes: 1

Views: 1909

Answers (3)

pirho
pirho

Reputation: 12255

ACCEPT_SINGLE_VALUE_AS_ARRAY as suggested is a good option.

Maybe your actual problem is more complicated but if not you could also try @JsonCreator instead of custom deserializer. Like:

public class Example {

    @JsonCreator
    public Example(@JsonProperty("inputFoo") String foo,
            @JsonProperty("inputBar") String bar,
            @JsonProperty("inputBaz") String strBaz) {
        this.foo = foo;
        this.bar = bar;
        this.baz = new HashSet<>();
        baz.add(strBaz);
    }

    private String foo;
    private String bar;
    private Set<String> baz;
}

Just to show that in more general case you might avoid implementing custom deserializer with @JsonCreator also but still make some simple conversions.

Upvotes: 0

Andreas
Andreas

Reputation: 159215

Replace the 2 constructors with this no-arg constructor:

public MyDeserializer() {
    super(TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class));
}

Upvotes: 0

Michał Ziober
Michał Ziober

Reputation: 38710

You do not need to implement custom deserialiser, use ACCEPT_SINGLE_VALUE_AS_ARRAY feature. It works for sets as well:

Feature that determines whether it is acceptable to coerce non-array (in JSON) values to work with Java collection (arrays, java.util.Collection) types. If enabled, collection deserializers will try to handle non-array values as if they had "implicit" surrounding JSON array. This feature is meant to be used for compatibility/interoperability reasons, to work with packages (such as XML-to-JSON converters) that leave out JSON array in cases where there is just a single element in array. Feature is disabled by default.

See also:

Upvotes: 2

Related Questions