Spring Security com.fasterxml.jackson.core.JsonGenerationException:无法写入字段名,需要值

wlsrxk51  于 2023-04-30  发布在  Spring
关注(0)|答案(3)|浏览(636)
@NotNull
@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
    property = "type")
@JsonSubTypes(value = {@JsonSubTypes.Type(value = SimpleGrantedAuthority.class)})
private List<GrantedAuthority> authorityList;

上面是我的属性,它是一个用于设置/授权用户的Spring Security接口。在我的测试中,我使用下面的语句序列化为JSON,因为它将是使用camel内容丰富器注入的JSON请求主体中的数组或列表。

String jsonObject =  mapper.writeValueAsString(accountDetails);

我得到这个错误是因为上面那行:

com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value

    at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1897)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeFieldName(WriterBasedJsonGenerator.java:126)
    at com.fasterxml.jackson.core.json.JsonGeneratorImpl.writeStringField(JsonGeneratorImpl.java:202)
    at com.fasterxml.jackson.databind.jsontype.impl.AsExternalTypeSerializer._writeObjectSuffix(AsExternalTypeSerializer.java:163)
    at com.fasterxml.jackson.databind.jsontype.impl.AsExternalTypeSerializer.writeTypeSuffixForObject(AsExternalTypeSerializer.java:88)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeWithType(BeanSerializerBase.java:584)
    at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:151)
    at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:112)
    at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:292)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3681)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3057)
    at com.sammy.controller.HomeControllerTest.checkCreateUser(HomeControllerTest.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

任何帮助将不胜感激。

iezvtpos

iezvtpos1#

如果您发现此页面是因为您试图使用JsonGenerator在Spring的JsonSerializer中序列化对象。write(String/Number)Field函数并看到com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value错误,即使您已经提供了一个值:
确保在调用writeField之前调用了JsonGenerator.writeStartObject();

ewm0tg9j

ewm0tg9j2#

把这个换了

@JsonSubTypes(value = {
            @JsonSubTypes.Type(value = SimpleGrantedAuthority.class)
        }
)

对此,

@JsonSubTypes({
@JsonSubTypes.Type(value = SimpleGrantedAuthority.class, name = "ROLE_ADMIN"),
})

这里,JsonSubTypes的name参数应该是您在JSON对象中用来标识该子类的名称。

wooyq4lh

wooyq4lh3#

我最近遇到了同样的问题,但我成功地解决了它。如果您还想序列化List<GrantedAuthority> authorities,可以参考我的方法。
我还尝试分别序列化和反序列化List<GrantedAuthority> authorities字段,但是序列化失败,反序列化成功。这是因为在序列化过程中,我们必须使用gen.writeStartObject()序列化对象,否则将抛出一个异常,说明“无法写入字段名,期待一个值”。然而,这种方法不会给予我们预期的数组格式,相反,它看起来像这样:{ ["role1","role2"]}

UserDetails

@Data
@JsonSerialize(using = AuthoritySerializer.class)
public class SysUser implements Serializable, UserDetails,
        JSONSerializer<JSONObject, SysUser>, JSONDeserializer<SysUser> {

    @TableId(type = IdType.AUTO)
    private Long id;

    private String username;

    private String password;

    @TableField(exist = false)
    @JsonDeserialize(using = AuthorityDeserializer.class)
    private List<GrantedAuthority> authorities = new ArrayList<>();

    @TableField(exist = false)
    private String codeKey;

    @TableField(exist = false)
    private String Code;

    private String avatar;

    private String email;

    private String city;

    private LocalDateTime createTime;

    private LocalDateTime updateTime;

    private Integer status;

    private LocalDateTime lastLogin;

    @TableField(exist = false)
    private List<SysRole> roles;

    public SysUser() {
    }

    public SysUser(ArrayList<GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return this.status == 1;
    } 
}

序列化器

public class AuthoritySerializer extends JsonSerializer<SysUser> {

    @Override
    public void serialize(SysUser sysUser, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {      
       List<String> authorities = sysUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        jsonGenerator.writeStartObject();
        jsonGenerator.writeObjectField("id", sysUser.getId());
        jsonGenerator.writeStringField("username", sysUser.getUsername());
        jsonGenerator.writeStringField("password", sysUser.getPassword());
        jsonGenerator.writeStringField("avtar", sysUser.getAvatar());
        jsonGenerator.writeStringField("city", sysUser.getCity());
        jsonGenerator.writeStringField("email", sysUser.getEmail());
        jsonGenerator.writeObjectField("roles", sysUser.getRoles() == null ? "" : sysUser.getRoles());
        jsonGenerator.writeObjectField("authorities", authorities.toString());
        jsonGenerator.writeObjectField("status", sysUser.getStatus());
        jsonGenerator.writeObjectField("createTime", sysUser.getCreateTime());
        jsonGenerator.writeObjectField("updateTime", sysUser.getUpdateTime());
        jsonGenerator.writeObjectField("lastLogin", sysUser.getLastLogin());
    }
}

Serialize测试

@Test
    void testSerialize() throws JsonProcessingException {
        UserDetails admin = userDetailsService.loadUserByUsername("admin");
        JacksonObjectMapper objectMapper = new JacksonObjectMapper();
        String s = objectMapper.writeValueAsString(admin);
        stringRedisTemplate.opsForValue().set("user:admin",s);

下面是序列化的JSON结果。

AuthorityDeserializer

public class AuthorityDeserializer extends StdDeserializer<List<GrantedAuthority>> {
    public AuthorityDeserializer() {
        this(null);
    }

    protected AuthorityDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public List<GrantedAuthority> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        String authorities = jsonParser.getCodec().readValue(jsonParser, String.class);
        List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(authorities);
        return grantedAuthorities;
    }
}

测试DeSerialize

@Test
    void testDeSerialize() throws JsonProcessingException {
        String json = stringRedisTemplate.opsForValue().get("user:admin");
        JacksonObjectMapper objectMapper = new JacksonObjectMapper();
        SysUser sysUser = objectMapper.readValue(json, SysUser.class);
        System.out.println(sysUser);
    }

下面是DeSerialize结果。

相关问题