fastjson2 icon indicating copy to clipboard operation
fastjson2 copied to clipboard

[QUESTION] 序列化和反序列化SimpleGrantedAuthority有没有完整教程啊?

Open jiangqiang1996 opened this issue 1 year ago • 11 comments

存序列化存Redis的时候报错: org.springframework.data.redis.serializer.SerializationException: Could not deserialize: invoke constructor error, public org.springframework.security.core.authority.SimpleGrantedAuthority(java.lang.String)

SimpleGrantedAuthority是springsecurity的类,没有默认的无参构造器。但是又没有详细的mixin文档

jiangqiang1996 avatar Aug 31 '22 07:08 jiangqiang1996

什么版本?2.0.12应该是能自动注册SimpleGrantedAuthority的mixin的

wenshao avatar Aug 31 '22 10:08 wenshao

 static Filter filter = JSONReader.autoTypeFilter(
            // 这里可以配置多个前缀
            "org.springframework.security.core.authority.SimpleGrantedAuthority",
            "org.springframework.util.LinkedCaseInsensitiveMap"
  );

  public Object deserialize(byte[] bytes) {
      return JSON.parseObject(bytes, Object.class, filter);
  }

  public Object deserialize(String str) {
      return JSON.parseObject(str, Object.class, filter);
  }

@Test
  public void testAuthority() {
      String json = "{\"@type\":\"org.springframework.security.core.authority.SimpleGrantedAuthority\",\"authority\":\"abc\"}";
      byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
      Object object = deserialize(bytes);
      assertEquals(org.springframework.security.core.authority.SimpleGrantedAuthority.class, object.getClass());
  }

参考上面的代码试试看

wenshao avatar Aug 31 '22 10:08 wenshao

有指定某个字段序列化规则到方式么?像jackson那样给某个属性加个注解,自己实现该属性的序列化和反序列化实现。我看了fastjson2的相关注解,JSONField的serializeUsing和deserializeUsing根本不生效,打断点不执行方法。JSONType里面到那两个属性是可以执行serializeUsing和deserializeUsing定义的方法的。但是也没找到别的参考文档可以看,代码注释写的太模糊。

jiangqiang1996 avatar Sep 03 '22 00:09 jiangqiang1996

能提供JSONField#serializeUsing和deserializeUsing不生效的重现的testcase么?

wenshao avatar Sep 05 '22 22:09 wenshao

能提供JSONField#serializeUsing和deserializeUsing不生效的重现的testcase么?

我这反序列化还是有问题:

    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

//        GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        FastJsonConfig fastJsonConfig = fastJsonRedisSerializer.getFastJsonConfig();
        fastJsonConfig.setReaderFeatures(JSONReader.Feature.SupportAutoType);
        fastJsonConfig.setWriterFeatures(JSONWriter.Feature.WriteClassName);
        fastJsonConfig.setReaderFilters(JSONReader.autoTypeFilter("org.springframework.security.core.authority.SimpleGrantedAuthority"));

        redisTemplate.setDefaultSerializer(fastJsonRedisSerializer);//设置默认的Serialize,包含 keySerializer & valueSerializer
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);//单独设置valueSerializer
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);//单独设置hashValueSerializer

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);//单独设置keySerializer
        redisTemplate.setHashKeySerializer(stringRedisSerializer);//单独设置hashKeySerializer
        return redisTemplate;
    }

jiangqiang1996 avatar Sep 09 '22 05:09 jiangqiang1996

这个是我反序列化的类型:

@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
    private User user;
    /**
     * 帐户是否过期
     */
    private boolean accountNonExpired = true;
    /**
     * 帐户是否被锁定
     */
    private boolean accountNonLocked = true;
    /**
     * 密码是否过期
     */
    private boolean credentialsNonExpired = true;
    /**
     * 帐户是否可用
     */
    private boolean enabled = true;
    /**
     * 拥有权限集合
     */
    private Set<? extends GrantedAuthority> authorities;

    /**
     * 可访问的菜单集合
     */
    private Set<MenuVo> menuSet;

    public LoginUser(User user) {
        this.user = user;
    }

    @JSONField(serialize = false,deserialize = false)
    public String getPassword() {
        return user.getPassword();
    }

    @JSONField(serialize = false,deserialize = false)
    public String getUsername() {
        return user.getUsername();
    }
}

日志信息: org.springframework.data.redis.serializer.SerializationException: Could not deserialize: invoke constructor error, public org.springframework.security.core.authority.SimpleGrantedAuthority(java.lang.String)

这个错误是我在redisTemplate.get的时候报的

jiangqiang1996 avatar Sep 09 '22 05:09 jiangqiang1996

redis里面存的数据信息:

{"@type":"top.jiangqiang.framework.system.entity.LoginUser","accountNonExpired":true,"accountNonLocked":true,"authorities":Set[{"@type":"org.springframework.security.core.authority.SimpleGrantedAuthority","authority":"123"},{"@type":"org.springframework.security.core.authority.SimpleGrantedAuthority","authority":"12312"}],"credentialsNonExpired":true,"enabled":true,"menuSet":Set[{"@type":"top.jiangqiang.framework.system.entity.vo.MenuVo","authority":"","component":"routerView/parent.vue","externalLink":false,"id":25,"menuSort":8,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isIframe":false,"isKeepAlive":true,"icon":"iconfont icon-diannao1","isAffix":false,"title":"测试名称","url":"","isHide":false},"name":"test","parentId":0,"path":"/test","redirect":""},{"@type":"top.jiangqiang.framework.system.entity.vo.MenuVo","component":"home/index.vue","externalLink":false,"id":1,"menuSort":1,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin","common"],"isKeepAlive":true,"icon":"iconfont icon-shouye","isAffix":true,"title":"首页","isHide":false},"name":"home","parentId":0,"path":"/home"},{"@type":"top.jiangqiang.framework.system.entity.vo.MenuVo","authority":"","component":"3123123","externalLink":false,"id":51,"menuSort":0,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isIframe":false,"isKeepAlive":true,"icon":"","isAffix":false,"title":"123","url":"","isHide":false},"name":"3123","parentId":0,"path":"12312312","redirect":"1231"},{"@type":"top.jiangqiang.framework.system.entity.vo.MenuVo","authority":"123","component":"system/generator/index.vue","externalLink":false,"id":48,"menuSort":0,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isIframe":false,"isKeepAlive":true,"icon":"iconfont icon-diannao-shuju","isAffix":false,"title":"代码生成","url":"","isHide":false},"name":"112","parentId":0,"path":"/genCode","redirect":""},{"@type":"top.jiangqiang.framework.system.entity.vo.MenuVo","children":[{"component":"system/dept/index.vue","externalLink":false,"id":6,"menuSort":6,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin"],"isKeepAlive":true,"icon":"ele-OfficeBuilding","isAffix":false,"title":"部门管理","isHide":false},"name":"systemDept","parentId":2,"path":"/system/dept"},{"component":"system/menu/index.vue","externalLink":false,"id":3,"menuSort":3,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin"],"isKeepAlive":true,"icon":"iconfont icon-caidan","isAffix":false,"title":"菜单管理","isHide":false},"name":"systemMenu","parentId":2,"path":"/system/menu"},{"component":"system/user/index.vue","externalLink":false,"id":5,"menuSort":5,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin"],"isKeepAlive":true,"icon":"iconfont icon-icon-","isAffix":false,"title":"用户管理","isHide":false},"name":"systemUser","parentId":2,"path":"/system/user"},{"component":"system/role/index.vue","externalLink":false,"id":4,"menuSort":4,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin"],"isKeepAlive":true,"icon":"ele-ColdDrink","isAffix":false,"title":"角色管理","isHide":false},"name":"systemRole","parentId":2,"path":"/system/role"},{"authority":"","component":"system/i18n/index.vue","externalLink":false,"id":45,"menuSort":9,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isIframe":false,"isKeepAlive":true,"icon":"iconfont icon-diannao1","isAffix":false,"title":"国际化","url":"","isHide":false},"name":"i18n","parentId":2,"path":"/system/i18n","redirect":""},{"component":"system/dic/index.vue","externalLink":false,"id":7,"menuSort":7,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin"],"isKeepAlive":true,"icon":"ele-SetUp","isAffix":false,"title":"字典管理","isHide":false},"name":"systemDic","parentId":2,"path":"/system/dic"}],"component":"routerView/parent.vue","externalLink":false,"id":2,"menuSort":2,"menuType":"menu","meta":{"@type":"java.util.LinkedHashMap","isLink":"","isIframe":false,"roles":["admin"],"isKeepAlive":true,"icon":"iconfont icon-xitongshezhi","isAffix":false,"title":"系统设置","isHide":false},"name":"system","parentId":0,"path":"/system","redirect":"/system/setting"}],"user":{"active":true,"deleted":false,"id":1,"nickname":"admin","password":"d29d20329fbd47d8b42fb2ac69069a4a104f215e509b85868c1f47ba9eab114dd6fdfe4d6812e7b7f498056f7b0ac5740c6c056e198632992fa8b9dd958e9bd5ef765b4e46b8fe58079eb6b10a7e563c4bee074b412138ca2d426a9b3f406ad3","username":"admin"}}

jiangqiang1996 avatar Sep 09 '22 06:09 jiangqiang1996

您发的这个例子,我都跑不了。

image

看这报错,我是不是还要给他弄一个mixin?

jiangqiang1996 avatar Sep 09 '22 06:09 jiangqiang1996

您发的这个例子,我都跑不了。

image

看这报错,我是不是还要给他弄一个mixin?

写了个mixin,这个是可以用的,但是Redis的那个我应该在哪里给他注入mixin呢?有点不清楚fastjson内部逻辑是啥,JSON调用mixin之后,项目任何地方都可以用???这个是全局的?

jiangqiang1996 avatar Sep 09 '22 06:09 jiangqiang1996

interface JSON {
   static void mixIn(Class<?> target, Class<?> mixinSource) {
        JSONFactory.defaultObjectWriterProvider.mixIn(target, mixinSource);
        JSONFactory.getDefaultObjectReaderProvider().mixIn(target, mixinSource);
    }
}

通过JSON.mxin是注册在defaultObjectWriterProvider和defaultObjectReaderProvider上的,可以理解是全局的

wenshao avatar Sep 10 '22 03:09 wenshao

interface JSON {
   static void mixIn(Class<?> target, Class<?> mixinSource) {
        JSONFactory.defaultObjectWriterProvider.mixIn(target, mixinSource);
        JSONFactory.getDefaultObjectReaderProvider().mixIn(target, mixinSource);
    }
}

通过JSON.mxin是注册在defaultObjectWriterProvider和defaultObjectReaderProvider上的,可以理解是全局的

我随便写了个自定义序列化字段的demo,不生效,是使用jsonfield注解配置的,反序列化可以生效,序列化不执行。

jiangqiang1996 avatar Sep 10 '22 11:09 jiangqiang1996

同样的问题,字段是UnmodifiableSet类型,想通过自定义字段反序列化方法来做,发现@JSONField(deserializeUsing = 指定的反序列化类不生效),只有@JSONType(deserializer=指定反序列化类生效)但是反序列化的具体方法没有任何例子和说明,实现起来成本太高了

cycle2zhou avatar May 27 '23 05:05 cycle2zhou

@cycle2zhou 单开一个issue吧,你这个是新问题,否则无法跟踪

wenshao avatar May 27 '23 05:05 wenshao

已开https://github.com/alibaba/fastjson2/issues/1509#issue-1728517832

cycle2zhou avatar May 27 '23 07:05 cycle2zhou