JacksonXML – 反序列化 XML 注释 <!– –>

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

JacksonXML - Deserialize XML Comments <!-- -->

问题

以下是您提供的内容的翻译:

我目前能找到的最接近的问题是这个,它没有明确的答案:

我正在尝试解析XML注释并将其映射到Java中的某些字段。

以下是我尝试让它工作的简单POC:

我的当前XML模型看起来像这样:

&lt;Model&gt;
    &lt;!--
    ** 这里有一些注释
    --&gt;
    &lt;Value1&gt;foo&lt;/Value1&gt;
    &lt;!--
    ** 这里有另一个注释
    --&gt;
    &lt;Value2&gt;bar&lt;/Value2&gt;
&lt;/Model&gt;

我已经像这样定义了我的Java模型:

@JacksonXmlRootElement(localName= &quot;Model&quot;)
@JsonDeserialize(using = CustomDeserializer.class)
final class ModelFile {

    @JacksonXmlProperty(localName = &quot;value1&quot;)
    private String value1;

    @JacksonXmlProperty(localName = &quot;value2&quot;)
    private String value2;

    private List&lt;String&gt; comments;

    // Getter和Setter
}

以及我的CustomDeserializer如下(Else If语句不起作用,这是我试图使其工作的部分):

public class CustomDeserializer extends JsonDeserializer&lt;ModelFile&gt; {

    @Override
    public ModelFile deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        List&lt;String&gt; comments = new ArrayList&lt;&gt;();
        ModelFile sample = new ModelFile();
        while (p.nextToken() != JsonToken.END_OBJECT) {
            if (p.getCurrentToken() == JsonToken.FIELD_NAME) {
                String fieldName = p.getCurrentName();
                p.nextToken();
                if (fieldName.equals(&quot;value1&quot;)) {
                    sample.setValue1(p.getText());
                } else if (fieldName.equals(&quot;value2&quot;)){
                    sample.setValue2(p.getText());
                }
            } else if (p.getText().equals(&quot;&lt;!--&quot;)) {
                p.nextToken();
                comments.add(p.getText());
                p.nextToken();
            }
        }
        sample.setComments(comments);
        return sample;
    }
}

最后,一个用于测试其功能的示例测试:

@Test
public void testDeserializeWithCommentsAsList() throws Exception {
    String xml = 
            &quot;&lt;model&gt;\n&quot; +
            &quot;  &lt;!--\n&quot; +
            &quot;  这是一个注释\n&quot; +
            &quot;  --&gt;\n&quot; +
            &quot;  &lt;value1&gt;foo&lt;/value1&gt;\n&quot; +
            &quot;  &lt;!--\n&quot; +
            &quot;  另一个注释\n&quot; +
            &quot;  --&gt;\n&quot; +
            &quot;  &lt;value2&gt;bar&lt;/value2&gt;\n&quot; +
            &quot;&lt;/yourclass&gt;&quot;;
    XmlMapper xmlMapper = new XmlMapper();

    YourClass yourClass = xmlMapper.readValue(xml, Model.class);
    List&lt;String&gt; comments = yourClass.getComments();
    assertNotNull(comments);
    assertEquals(2, comments.size());
    assertEquals(&quot;这是一个注释&quot;, comments.get(0));
    assertEquals(&quot;另一个注释&quot;, comments.get(1));
}

据我理解,问题在于CustomDeserializer似乎将value1value2都识别为有效字段,允许我直接映射字段。但XML注释根本没有被识别。

我之所以提到XML注释,是因为如果我将其更改为更标准的注释类型,如此:

    &quot;&lt;model&gt;\n&quot; +
    &quot;  // 这是一个注释\n&quot; +
    &quot;  &lt;value1&gt;foo&lt;/value1&gt;\n&quot; +
    &quot;  // 另一个注释\n&quot; +
    &quot;  &lt;value2&gt;bar&lt;/value2&gt;\n&quot; +
    &quot;&lt;/yourclass&gt;&quot;;

然后CustomDeserializer中的JsonParser将捕获注释。进一步查看JsonParser,我看到可以启用的功能,特别是ALLOW_COMMENTS,它可以识别典型的Java/C++注释,或者ALLOW_COMMENTS_YAML,它专门寻找#类型的注释。

https://fasterxml.github.io/jackson-core/javadoc/2.8/com/fasterxml/jackson/core/JsonParser.Feature.html#ALLOW_COMMENTS

我猜想,考虑到JacksonXML是JSON的扩展,通常不支持注释在JSON中,这可能不是一个可行的方法?考虑到它_在技术上可能_适用于//类型的注释,我觉得我离使其工作非常接近。

对于这个问题的答案是:如何在使用jackson-databind-xml将其反序列化为POJO时处理&lt;!-- --&gt;类型的XML注释?如果有任何想法或建议,都欢迎。

英文:

The closest question I can find currently is this which has no conclusive answer:

I am trying to parse XML comments and map it to certain fields in Java.

Below was a simple POC I did in attempt to get this to work.

My current XML model looks something like this:

&lt;Model&gt;
    &lt;!--
    ** some comment here
    --&gt;
    &lt;Value1&gt;foo&lt;/Value1&gt;
    &lt;!--
    ** another comment here
    --&gt;
    &lt;Value2&gt;bar&lt;/Value2&gt;
&lt;/Model&gt;

I have defined my Java model like so:

@JacksonXmlRootElement(localName= &quot;Model&quot;)
@JsonDeserialize(using = CustomDeserializer.class)
final class ModelFile {

    @JacksonXmlProperty(localName = &quot;value1&quot;)
    private String value1;

    @JacksonXmlProperty(localName = &quot;value2&quot;)
    private String value2;

    private List&lt;String&gt; comments;

    // Getters and Setters
}

And my CustomDeserializer like so (Else If statement will not work, this is the part im trying to get working):

public class CustomDeserializerextends JsonDeserializer&lt;ModelFile&gt; {

    @Override
    public ModelFiledeserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        List&lt;String&gt; comments = new ArrayList&lt;&gt;();
        ModelFile sample = new ModelFile();
        while (p.nextToken() != JsonToken.END_OBJECT) {
            if (p.getCurrentToken() == JsonToken.FIELD_NAME) {
                String fieldName = p.getCurrentName();
                p.nextToken();
                if (fieldName.equals(&quot;value1&quot;)) {
                    sample.setValue1(p.getText());
                } else if (fieldName.equals(&quot;value2&quot;)){
                    sample.setValue2(p.getText());
                }
            } else if (p.getText().equals(&quot;&lt;!--&quot;)) {
                p.nextToken();
                comments.add(p.getText());
                p.nextToken();
            }
        }
        sample.setComments(comments);
        return sample;
    }
}

And finally a sample test to test it's functionality:

@Test
    public void testDeserializeWithCommentsAsList() throws Exception {
        String xml = 
                &quot;&lt;model&gt;\n&quot; +
                &quot;  &lt;!--\n&quot; +
                &quot;  this is a comment \n&quot; +
                &quot;  --&gt;\n&quot; +
                &quot;  &lt;value1&gt;foo&lt;/value1&gt;\n&quot; +
                &quot;  &lt;!--\n&quot; +
                &quot;  Another comment \n&quot; +
                &quot;  --&gt;\n&quot; +
                &quot;  &lt;value2&gt;bar&lt;/value2&gt;\n&quot; +
                &quot;&lt;/yourclass&gt;&quot;;
        XmlMapper xmlMapper = new XmlMapper();

        YourClass yourClass = xmlMapper.readValue(xml, Model.class);
        List&lt;String&gt; comments = yourClass.getComments();
        assertNotNull(comments);
        assertEquals(2, comments.size());
        assertEquals(&quot;this is a comment&quot;, comments.get(0));
        assertEquals(&quot;Another comment&quot;, comments.get(1));
    }

The problem as I understand it is the CustomDeserializer seems to recognize both value1 and value2 as valid fields allowing me to later map the fields directly. XML Comments however are not recognized at all.

I say XML Comments specifically because if I change this to a more standard comment type such as this:

    &quot;&lt;model&gt;\n&quot; +
    &quot;  // this is a comment \n&quot; +
    &quot;  &lt;value1&gt;foo&lt;/value1&gt;\n&quot; +
    &quot;  // another comment \n&quot; +
    &quot;  &lt;value2&gt;bar&lt;/value2&gt;\n&quot; +
    &quot;&lt;/yourclass&gt;&quot;;

Then the JsonParser in the CustomDeserializer will pick up the comments. Looking further into Jsonparser I see Features that can be enabled namely ALLOW_COMMENTS which does recognize typical Java/C++ comments or ALLOW_COMMENTS_YAML which looks specifically for # type comments.

https://fasterxml.github.io/jackson-core/javadoc/2.8/com/fasterxml/jackson/core/JsonParser.Feature.html#ALLOW_COMMENTS

My guess is considering JacksonXML extends of JSON and typically comments are not supported in JSON, this is not really viable? Considering that it could technically work for // type comments, I feel like im really close to getting this to work.

The question for this would be: How do I handle &lt;!-- --&gt; type comments in XMLs while using jackson-databind-xml to deserialize it into POJO?

Any idea or suggestions are welcomed.

答案1

得分: 0

这似乎无法实现。在根对象上添加@JsonDeserializer,然后查看正在使用的Jsonparser发现,当JacksonXML尝试处理XML时,所有注释的痕迹都已被移除(特别是&lt;!-- --&gt;类型的注释!)

我采取的替代解决方案,由用户LMC建议,是将XML作为流进行读取,查找Comment类型的事件。然后,我会将注释放入一个List中,最终将其返回。

虽然不太理想,因为XML被读取了两次(一次用于Jackson映射,再一次用于收集注释),但是对于我的情况来说,读取两次与一次相比性能几乎可以忽略不计,而且如果不使用Jackson来读取和手动填充我的业务对象,将需要很长时间来实现。

英文:

Ultimately, no this cannot be done it seems. Adding a @JsonDeserializer on the root Object and then having a look at the Jsonparser that is being used revealed that by the time JacksonXML attempts to process the XML, all traces of the comments has been removed (Specifically again &lt;!-- --&gt; type comments!)

The alternative solution I did, which was suggested by user LMC was to read the xml as a stream and look for events that are Comment type. I would then take the comment and push it into a List which is eventually returned.

Really not ideal as the XML is being read twice (Once for Jackson Mapping and once more to collect the comments) however for my scenario we've decided to go that way as the performance reading it twice vs once is negligible and to read and manually populate my business object without Jackson would take a lot of time to implement.

huangapple
  • 本文由 发表于 2023年4月19日 19:00:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76053707.html
匿名

发表评论

匿名网友

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

确定