3

I'm sending a User object through REST which contains a Set of SimpleGrantedAuthority objects. On the receiver side, I'm getting an exception:

org.springframework.core.codec.DecodingException: JSON decoding error: Cannot construct instance of org.springframework.security.core.authority.SimpleGrantedAuthority (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator);

I'm using the default JSON mapper which Spring Boot 2.1.2 provides. On the receiving side, I'm using WebFlux's WebClient (WebTestClient in this case).

Can anyone explain to me why am I getting this error and how to solve it?

juanlumn
  • 6,155
  • 2
  • 30
  • 39
OCPi
  • 316
  • 1
  • 5
  • 16
  • https://stackoverflow.com/questions/47570931/jackson-deserialize-class-with-private-fields-and-arg-constructor-without-annot?rq=1 – xingbin Jan 15 '19 at 14:55

1 Answers1

8

SimpleGrantedAuthority is not suitable for automatic mapping with Jackson; it has no no-arg constructor and no setter for the authority field.

So it needs a custom deserializer. Something like this:

class SimpleGrantedAuthorityDeserializer extends StdDeserializer<SimpleGrantedAuthority> {
    public SimpleGrantedAuthorityDeserializer() {
        super(SimpleGrantedAuthority.class);
    }
    @Override
    public SimpleGrantedAuthority deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode tree = p.getCodec().readTree(p);
        return new SimpleGrantedAuthority(tree.get("authority").textValue());
    }
}

Register it with Jackson globally like this:

objectMapper.registerModule(new SimpleModule().addDeserializer(
                      SimpleGrantedAuthority.class, new SimpleGrantedAuthorityDeserializer()));

Or annotate the field(s) with:

@JsonDeserialize(using = SimpleGrantedAuthorityDeserializer.class)

Note: you don't need a serializer because SimpleGrantedAuthority has the getAuthority() method, which is usable by Jackson.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • Thank you very much! Works like a charm. – OCPi Jan 16 '19 at 08:44
  • If you're annotating the signature `public Collection getAuthorities()` make sure to use `contentUsing`, so `@JsonDeserialize(contentUsing = SimpleGrantedAuthorityDeserializer.class)`, otherwise the deserializer gets the entire collection node to deserialize at once. – Simon Jan 11 '22 at 13:31