Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jackson deserialize object with list of spring's interface

I need to save and load objects from redis.

The object contains list of GrantedAuthority (among other things) which is an interface:

public class UserAccountAuthentication implements Authentication {
    private List<GrantedAuthority> authorities;
    private boolean authenticated = true;
    ...
}

Jackson successfully serializes the object but fails to deserialize it with the following exception:

abstract types can only be instantiated with additional type information

I know that I can specify the type by adding:

@JsonTypeInfo(

But I can't do it in this case because the GrantedAuthority is an interface of Spring and I cannot change it.


the serialized json is:

{
"authorities": [
    {
        "authority": "ROLE_NORMAL_USER"
    }
],
"authenticated": true,
"securityToken": {
    "expiration": 1458635906853,
    "token": "sxKi3Pddfewl2rgpatVE7KiSR5qGmhpGl0spiHUTLAAW8zuoLFE0VLFYcfk72VLnli66fcVmb8aK9qFavyix3bOwgp1DRGtGacPI",
    "roles": [
        "ROLE_NORMAL_USER"
    ],
    "expired": false,
    "expirationDateFormatted": "2016-03-22 08:38:26.853 UTC"
},
"name": "admin",
"expired": false

}


the abstract GrantedAuthority is only filled with SimpleGrantedAuthority.

so i tried:

objectMapper.registerSubtypes(SimpleGrantedAuthority.class);

and still no luck.

like image 843
Mike Avatar asked Mar 01 '16 13:03

Mike


People also ask

How does Jackson deserialize dates from JSON?

This is how i'm deserializing the date: SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); getObjectMapper(). getDeserializationConfig(). setDateFormat(dateFormat);

How does ObjectMapper readValue work?

The simple readValue API of the ObjectMapper is a good entry point. We can use it to parse or deserialize JSON content into a Java object. Also, on the writing side, we can use the writeValue API to serialize any Java object as JSON output.

Does spring boot have Jackson ObjectMapper?

When using JSON format, Spring Boot will use an ObjectMapper instance to serialize responses and deserialize requests. In this article, we will take a look at the most common ways to configure the serialization and deserialization options.


1 Answers

I think you need to add a custom deserializer

public class UserAccountAuthenticationSerializer extends JsonDeserializer<UserAccountAuthentication> {

@Override
public UserAccountAuthentication deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
        throws IOException {

    UserAccountAuthentication userAccountAuthentication = new UserAccountAuthentication();

    ObjectCodec oc = jsonParser.getCodec();
    JsonNode node = oc.readTree(jsonParser);
    userAccountAuthentication.setAuthenticated(node.get("authenticated").booleanValue());

    Iterator<JsonNode> elements = node.get("authorities").elements();
    while (elements.hasNext()) {
        JsonNode next = elements.next();
        JsonNode authority = next.get("authority");
        userAccountAuthentication.getAuthorities().add(new SimpleGrantedAuthority(authority.asText()));
    }
    return userAccountAuthentication;
}

}

This is my json

{"authenticated":true,"authorities":[{"authority":"role1"},{"authority":"role2"}],"details":null,"principal":null,"credentials":null,"name":null}

Then at the top of your POJO

@JsonDeserialize(using = UserAccountAuthenticationSerializer.class)
public class UserAccountAuthentication  implements Authentication {

Here's the test

@Test
public void test1() throws IOException {

UserAccountAuthentication userAccountAuthentication = new UserAccountAuthentication();
userAccountAuthentication.setAuthenticated(true);
userAccountAuthentication.getAuthorities().add(new SimpleGrantedAuthority("role1"));
userAccountAuthentication.getAuthorities().add(new SimpleGrantedAuthority("role2"));

String json1 = new ObjectMapper().writeValueAsString(userAccountAuthentication);
UserAccountAuthentication readValue = new ObjectMapper().readValue(json1, UserAccountAuthentication.class);
String json2 = new ObjectMapper().writeValueAsString(readValue);
assertEquals(json1, json2);

}

like image 182
Essex Boy Avatar answered Oct 04 '22 03:10

Essex Boy