【问题标题】:jackson deserialize object with list of spring's interface杰克逊用spring接口列表反序列化对象
【发布时间】:2016-06-13 23:25:42
【问题描述】:

我需要从 redis 保存和加载对象。

该对象包含作为接口的 GrantedAuthority 列表(除其他外):

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

Jackson 成功序列化对象但未能反序列化它,出现以下异常:

abstract types can only be instantiated with additional type information

我知道我可以通过添加来指定类型:

@JsonTypeInfo(

但是在这种情况下我不能这样做,因为GrantedAuthority是Spring的接口,我无法更改它。


序列化的json是:

{
"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

}


摘要GrantedAuthority仅填充SimpleGrantedAuthority

所以我尝试了:

objectMapper.registerSubtypes(SimpleGrantedAuthority.class);

仍然没有运气。

【问题讨论】:

  • 你看看你的getter和setter写得是否正确吗?
  • 没有 getter 和 setter,它是对象内部使用的私有列表。

标签: java spring redis jackson


【解决方案1】:

我认为您需要添加自定义反序列化器

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;
}

}

这是我的json

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

然后在你的 POJO 的顶部

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

这是测试

@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);

}

【讨论】:

  • 我一步一步地按照你的代码进行编译,但是当它运行时,“解串器”从来没有断点,就好像它从来没有运行过一样,我收到了这个错误:org.codehaus.jackson.map。 JsonMappingException:无法从 [Source: java.io.StringReader@4db4a5cb; 的 START_ARRAY 令牌中反序列化 com.coronet.online.security.GrantedAuthorityContainer 的实例;行:1,列:2](通过引用链:com.coronet.online.security.UserAccountAuthentication["authorities"])
  • 你能发布你的json吗,我已经添加了我测试中使用的Jason。
  • 您还希望使用什么实现的 GrantedAuthority?
  • 只有 SimpleGrantedAuthority...我现在正在尝试做类似的事情: objectMapper.registerSubtypes(new NamedType(SimpleGrantedAuthority.class, "GrantedAuthority")); ...但到目前为止还没有运气
  • 我更改了测试以反映您的代码,它工作正常,看不到问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-11
  • 2019-11-15
  • 2014-06-10
  • 2021-06-18
  • 1970-01-01
  • 1970-01-01
  • 2018-03-16
相关资源
最近更新 更多