无法在遇到换行符时反序列化标签内的空内容。

huangapple go评论70阅读模式
英文:

Can not deserialize empty content within tags when newline met

问题

以下是翻译好的内容:

有以下两个类:

@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: 无法构造 `com.test.models.Info` 的实例尽管至少存在一个创建者):没有可用于从字符串值反序列化的String-argument构造函数/工厂方法' '

这个 Jackson 特性没有起作用:

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/><Info></Info>

<Info/> 正常工作,
然而

<Info>
 </Info>

在出现换行符时会导致异常。

英文:

Have following 2 classes:<br>

@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;
}

doing deserialization like:

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

where input is my XML(see below)

got exception:

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 (&#39;

    &#39;)

this Jackson feature did not help:

XML_MAPPER.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

my XML that failed:

&lt;?xml version=&#39;1.0&#39; encoding=&#39;UTF-8&#39; ?&gt;
  &lt;Structure&gt;
    &lt;Info&gt;

    &lt;/Info&gt;
  &lt;/Structure&gt;

for this XML deserialization works OK:

&lt;?xml version=&#39;1.0&#39; encoding=&#39;UTF-8&#39; ?&gt;
  &lt;Structure&gt;
    &lt;Info/&gt;
  &lt;/Structure&gt;

The problem is with tag closing approach:
&lt;Info/&gt; VS &lt;Info&gt;&lt;/Info&gt;

&lt;Info/&gt; works OK
while

&lt;Info&gt;

 &lt;/Info&gt;

causes Exception when line terminators occurred

答案1

得分: 3

如其他人在他们的评论中已经提到的那样,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();
    
        // 忽略“空”Info元素
        if (instClass.isAssignableFrom(Info.class) && (value.isEmpty() || value.matches("[\\n\\s]+"))) {
            return null;
        }
        return super.handleMissingInstantiator(ctxt, instClass, valueInsta, p, msg);
    }
   
});

如果您想对所有元素都执行此操作,可以简单地忽略 instClass

英文:

As others already mentioned in their comments, <code>DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT</code> converts only empty strings to null, but you have spaces and line separators within your Info element.

Others cannot reproduce your problem since you either missed to mention that you also use <code>XML_MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)</code> in your code or Info in your example XML should actually be info, otherwise the element is ignored.

To handle empty strings and strings that only contain spaces and/or line separators you can add the following code before you parse the XML:

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

If you want to do this for all elements you can simply ignore <code>instClass</code>

huangapple
  • 本文由 发表于 2020年9月6日 03:26:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63757770.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定