首页 > 解决方案 > 遇到换行符时无法反序列化标签内的空内容

问题描述

有以下2个类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Structure {
    @JacksonXmlProperty
    private Info info;


@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@NoArgsConstructor
@AllArgsConstructor
public class Info{
    private Subinfo subinfo;
}

进行反序列化,例如:

 private static final XmlMapper XML_MAPPER = new XmlMapper();
 Structure structure = XML_MAPPER.readValue(input, Structure.class);

input我的 XML在哪里(见下文)

有异常:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.test.models.Info` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('

    ')

这个杰克逊功能没有帮助:

XML_MAPPER.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

我失败的XML:

<?xml version='1.0' encoding='UTF-8' ?>
  <Structure>
    <Info>

    </Info>
  </Structure>

对于这个 XML 反序列化工作正常:

<?xml version='1.0' encoding='UTF-8' ?>
  <Structure>
    <Info/>
  </Structure>

问题在于标签关闭方法: <Info/>VS<Info></Info>

<Info/>工作正常,而

<Info>

 </Info>

发生线路终止符时导致异常

标签: javaxmljacksondeserializationnewline

解决方案


正如其他人在他们的评论中已经提到的那样,DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT仅将空字符串转换为 null,但您的 Info 元素中有空格和行分隔符。

其他人无法重现您的问题,因为您要么错过了提及您还在XML_MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)代码中使用的信息,要么您的示例 XML 中的Info实际上应该是info,否则该元素将被忽略。

要处理空字符串和仅包含空格和/或行分隔符的字符串,您可以在解析 XML 之前添加以下代码:

XML_MAPPER.addHandler(new DeserializationProblemHandler() {
    
    @Override
    public Object handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass,
            ValueInstantiator valueInsta, JsonParser p, String msg) throws IOException {
    
      String value = p.getValueAsString();
    
      // ignore "empty" Info elements
      if (instClass.isAssignableFrom(Info.class) && (value.isEmpty() || value.matches("[\n\s]+"))) {
        return null;
      }
      return super.handleMissingInstantiator(ctxt, instClass, valueInsta, p, msg);
    }
   
});

如果你想对所有元素都这样做,你可以简单地忽略instClass


推荐阅读