【问题标题】:Correctly deserialize an object with deserializer with Jackson使用 Jackson 的反序列化器正确反序列化对象
【发布时间】:2017-01-23 11:19:48
【问题描述】:

我需要一个自定义反序列化器来在复杂的 POJO 中转换字符串。反序列化在使用反序列化器之前一直有效:特别是在使用自定义反序列化器时,我的对象的非对象属性不会序列化。

我有一个以 pojo 作为参数的 RESTful Web 服务。

public PreventivoResponse calculate(@FormParam(value = "preventivo") PreventivoWs preventivo) throws Exception;

所以我的类PreventivoWs 需要fromString(String) 方法。这里是类定义:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PreventivoWs implements Serializable{
    private static final long serialVersionUID = -554141724349909424L;
    private ClienteMultiSelect cliente;

    private String riferimento;
    private List<EmailWS> email;

    private String dataritiro;
    private String dataconsegna;
    private Long tipoconsegna;

    private IndirizzoWS partenza;

    private IndirizzoWS destinazione;

    List<ColloWs> colli;

    HashMap<Long, String> services;

...
}

在 jsonObject 中我有一个枚举定义为

{
  "value" : "A",
  "text"  : "Active"
}

但是这个对象需要一个反序列化器才能被转换:

public class TipoPersonaFGJsonDeserializer extends JsonDeserializer<TipoPersonaFG> {

@Override
public TipoPersonaFG deserialize(JsonParser jsonParser, DeserializationContext context) 
        throws IOException, JsonProcessingException {

    JsonToken currentToken = null;
    while ((currentToken = jsonParser.nextValue()) != null) {
        switch (currentToken) {
            case VALUE_STRING:
                switch (jsonParser.getCurrentName()) {
                    case "value":
                        String name = jsonParser.getText();
                        return TipoPersonaFG.valueOf(name);
                }
                break;
            default:
                break;
        }
    }
    return null;
}
}

并且在属性上进行了注释:

@JsonDeserialize(using = TipoPersonaFGJsonDeserializer.class)
private TipoPersonaFG tipo;

fromString 方法只是调用jackson ObjectMapper:

public static PreventivoWs fromString(String jsonString) throws IOException{
    ObjectMapper mapper = new ObjectMapper();
    PreventivoWs oggetto = mapper.readValue(jsonString, PreventivoWs.class);
    return oggetto;
}

如果 jsonString 中没有指定 enum,它工作正常:对象被完美反序列化; 如果我在 jsonString 中添加枚举,则所有对象属性都将被反序列化(电子邮件、客户端、partenza、destinazione、...),但其他属性将被忽略(dataritiro、dataconsegna、tipoconsegna)。

为什么?自定义反序列化器破坏了反序列化的标准流程?

更新: 当自定义反序列化器发生时,解析过程被中断:我将cliente 属性(包含特定枚举)移到了 json 对象的末尾:现在字段 dataconsegna、dataritiro 等被反序列化。

所以当自定义反序列化程序发生时,反序列化过程结束(即使客户对象被中断)

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    解决了! 如Jackson Wiki 所写:

    不得处理任何超出反序列化值的令牌(不多也不少)

    所以问题出在反序列化器中:您必须在找到 END_OBJECT (}) 时停止,否则 jsonParser 会一直运行到流结束,消耗所有其他令牌。

    @Override
    public TipoPersonaFG deserialize(JsonParser jsonParser, DeserializationContext context) 
            throws IOException, JsonProcessingException {
    
        JsonToken currentToken = null;
        String name = null;
        while ((currentToken = jsonParser.nextValue()) != null) {
            switch (currentToken) {
                case VALUE_STRING:
                    switch (jsonParser.getCurrentName()) {
                        case "value":
                            name = jsonParser.getText();
                            break;
                    }
                    break;
                case END_OBJECT:
                    if(name != null)
                        return TipoPersonaFG.valueOf(name);
                    else 
                        return null;
            }
        }
        return TipoPersonaFG.valueOf(name);
    }
    

    我添加了 case 条件 END_OBJECT 仅使用第一个 '}' 并正确关闭枚举对象的解析。 return 在 END_OBJECT 情况下被移动,因为否则 '}' 标记将保留在流中,并且它将关闭枚举的父级。

    所以你需要将你的对象从'{'令牌解析为'}'令牌

    【讨论】:

      猜你喜欢
      • 2020-08-07
      • 1970-01-01
      • 2022-01-22
      • 2014-02-12
      • 2019-10-25
      • 2018-12-26
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多