Jackson在反序列化的错误级别上搜索方法



我正在尝试将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类序列化,该类还包含相应的setter并实现具有相应名称的文件。

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"])

当然;"范围";不是在反序列化OAuth2Authentication的上下文中,而是在DefaultAuthorizationRequest的上下文中。为什么杰克逊在错误的班级里找它?我正在取消Jackson版本2.12.4

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

  • 您必须让Jackson知道如何反序列化DefaultAuthorizationRequest类。一种可能的解决方案是将@JsonCreator@JsonProperty添加到类中。这同样适用于GrantedAuthority
  • DefaultAuthorizationRequest具有类型为Map的字段,这些字段需要特别注意。请参阅以下链接,了解如何将JSON字符串转换为Map<字符串,字符串>或者,如果Map具有自定义对象,如何反序列化为自定义对象的HashMap

此外,您还可以使用Jackson 查看映射序列化和反序列化

我发现了我的问题。我以前通过一个处理程序映射了接口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;
}
}

最新更新