【问题标题】:Jackson searches method on wrong level on deserializationJackson 在反序列化的错误级别上搜索方法
【发布时间】:2021-11-15 14:41:29
【问题描述】:

我正在尝试将 JSON 读入课堂。 Jackson 想要将子元素的字段应用到元素本身,而它当然不存在。

这是 JSON:

{
        "authorizationRequest":{
                "scope":["write","read"],
                "resourceIds":["metadata"],
                "approved":true,
                "authorities":[],
                "authorizationParameters":{
                        "scope":"write read",
                        "response_type":"token",
                        "redirect_uri":"",
                        "state":"",
                        "stateful":"false",
                        "client_id":"5102686_metadata"
                },
                "approvalParameters":{},
                "state":"",
                "clientId":"5102686_metadata",
                "redirectUri":"",
                "responseTypes":["token"],
                "denied":false
        },
        "credentials":"",
        "clientOnly":false,
        "name":"testuser"
}

这些类如下所示:

// The main class that I try do deserialize:
public class DeserializedOAuth2Authentication extends OAuth2Authentication{

    private String name;

    private boolean clientOnly;

    private AuthorizationRequest authorizationRequest = new DefaultAuthorizationRequest("", new ArrayList<>());

    public DeserializedOAuth2Authentication() {
        super(new DefaultAuthorizationRequest("", new ArrayList<>()), null);
    }

    @Override
    @JsonProperty
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    @JsonProperty
    public boolean isClientOnly() {
        return clientOnly;
    }

    public void setClientOnly(boolean clientOnly) {
        this.clientOnly = clientOnly;
    }

    @Override
    @JsonProperty
    public AuthorizationRequest getAuthorizationRequest() {
        return authorizationRequest;
    }

    public void setAuthorizationRequest(AuthorizationRequest authorizationRequest) {
        this.authorizationRequest = authorizationRequest;
    }

}

AuthorizationRequest 是一个包含列出元素的所有 getter 的接口;它被配置为由 DefaultAuthorizationRequest 类进行序列化,该类还包含相应的设置器和具有相应名称的实现文件。

public class DefaultAuthorizationRequest implements AuthorizationRequest, Serializable {

    private Set<String> scope = new LinkedHashSet<String>();

    private Set<String> resourceIds = new HashSet<String>();

    private boolean approved = false;

    private Collection<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();

    private Map<String, String> authorizationParameters = new ConcurrentHashMap<String, String>();

    private Map<String, String> approvalParameters = new HashMap<String, String>();

    private String resolvedRedirectUri;

    public Map<String, String> getAuthorizationParameters() {
        return Collections.unmodifiableMap(authorizationParameters);
    }

    public Map<String, String> getApprovalParameters() {
        return Collections.unmodifiableMap(approvalParameters);
    }

    public String getClientId() {
        return authorizationParameters.get(CLIENT_ID);
    }

    public Set<String> getScope() {
        return Collections.unmodifiableSet(this.scope);
    }

    public Set<String> getResourceIds() {
        return Collections.unmodifiableSet(resourceIds);
    }

    public Collection<GrantedAuthority> getAuthorities() {
        return Collections.unmodifiableSet((Set<? extends GrantedAuthority>) authorities);
    }

    public boolean isApproved() {
        return approved;
    }

    public boolean isDenied() {
        return !approved;
    }

    public String getState() {
        return authorizationParameters.get(STATE);
    }

    public String getRedirectUri() {
        return resolvedRedirectUri == null ? authorizationParameters.get(REDIRECT_URI) : resolvedRedirectUri;
    }

    public Set<String> getResponseTypes() {
        return OAuth2Utils.parseParameterList(authorizationParameters.get(RESPONSE_TYPE));
    }

    public void setRedirectUri(String redirectUri) {
        this.resolvedRedirectUri = redirectUri;
    }

    public void setScope(Set<String> scope) {
        this.scope = scope == null ? new LinkedHashSet<String>() : new LinkedHashSet<String>(scope);
        authorizationParameters.put(SCOPE, OAuth2Utils.formatParameterList(scope));
    }

    public void setResourceIds(Set<String> resourceIds) {
        this.resourceIds = resourceIds == null ? new HashSet<String>() : new HashSet<String>(resourceIds);
    }

    public void setApproved(boolean approved) {
        this.approved = approved;
    }

    public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
        this.authorities = authorities == null ? new HashSet<GrantedAuthority>() : new HashSet<GrantedAuthority>(
                authorities);
    }

    public void setAuthorizationParameters(Map<String, String> authorizationParameters) {
        String clientId = getClientId();
        Set<String> scope = getScope();
        this.authorizationParameters = authorizationParameters == null ? new HashMap<String, String>()
                : new HashMap<String, String>(authorizationParameters);
    }

    public void setApprovalParameters(Map<String, String> approvalParameters) {
        this.approvalParameters = approvalParameters == null ? new HashMap<String, String>()
                : new HashMap<String, String>(approvalParameters);
    }
    ....
}

在上面的 JSON 字符串上调用 read 我得到一个异常

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "scope" (class de.mvbonline.vlx.auth.oauth2.DeserializedOAuth2Authentication), not marked as ignorable (3 known properties: "name", "authorizationRequest", "clientOnly"])
 at [Source: (String)"{        "credentials":"",        "clientOnly":false,        "authorizationRequest":{                "scope":["write","read"],                "resourceIds":["metadata"],                "approved":true,                "authorities":[],                "authorizationParameters":{                        "scope":"write read",                        "response_type":"token",                        "redirect_uri":"",                        "state":"",                        "stateful":"false",          "[truncated 316 chars]; line: 1, column: 111] (through reference chain: de.mvbonline.vlx.auth.oauth2.DeserializedOAuth2Authentication["scope"])

当然“范围”这个字段不在 DeserializedOAuth2Authentication 的上下文中,而是在 DefaultAuthorizationRequest 的上下文中。为什么杰克逊在错误的课程中寻找它? 我正在取消杰克逊 2.12.4 版

【问题讨论】:

  • 您能否展示一下您实际上是如何将 JSON 字符串解析/映射到一个对象中的?

标签: java json jackson


【解决方案1】:

确保 DefaultAuthorizationRequest 可以被 Jackson 序列化和反序列化。我想他们不是有几个原因。我能想到的两个:

另外,你可以看看Map Serialization and Deserialization with Jackson

【讨论】:

  • 根据文档,反序列化 Map 应该是可能的,无需任何进一步的概念。
【解决方案2】:

我发现了我的问题。 我以前通过处理程序映射了接口AuthorizationRequest 的具体实现:

        mapper.addHandler(new DeserializationProblemHandler() {
            @Override
            public Object handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, ValueInstantiator valueInsta, JsonParser p, String msg) throws IOException {
                if(instClass.isAssignableFrom(AuthorizationRequest.class)) {
                    return new DeserializedAuthorizationRequest();
                }
                return super.handleMissingInstantiator(ctxt, instClass, valueInsta, p, msg);
            }
        });

这似乎与用具体类注释字段绝对不一样。这现在可以正常工作了:

public class DeserializedOAuth2Authentication extends OAuth2Authentication{

    ...

    @Override
    @JsonProperty("authorizationRequest")
    @JsonDeserialize(as = DeserializedAuthorizationRequest.class)
    public AuthorizationRequest getAuthorizationRequest() {
        return authorizationRequest;
    }

    public void setAuthorizationRequest(AuthorizationRequest authorizationRequest) {
        this.authorizationRequest = authorizationRequest;
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多