2

I'm writing a custom Maven plugin for building a Flatpak from a Java project. In a Maven mojo I understand we use @Parameter annotations to parse pom.xml file configurations. For example:

pom.xml:

<configuration>
    <param1>VALUE</param1>
</configuration>

In MyMojo.java:

@Parameter
private String param1;

But how would I set a value that includes HTML tags? For example:

<configuration>
    <param1><p>VALUE</p></param1>
</configuration>

Trying this, I get the error:

Basic element 'param1' must not contain child elements.

So I wrap the <p>VALUE</p> in a CDATA block:

<configuration>
    <param1><![CDATA[<p>VALUE</p>]]></param1>
</configuration>

This works up to the point where the MetaInfo object is written to file:

private void writeMetaInfo(MetaInfo metaInfo, Writer writer) throws IOException {
    XmlMapper mapper = new XmlMapper();
    new PrintWriter(writer, true).println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    // metaInfo value is correct before writing - it has <p> not &lt;p>
    mapper.writerWithDefaultPrettyPrinter().writeValue(writer, metaInfo);
}

The result is an XML file with: <param1>&lt;p>VALUE&lt;/p></param1>

...with the leading angle brackets replaced with their entity, &lt;. This doesn't work for the Flatpak MetaInfo file I'm building. It needs the <p> and </p>.

So it seems to be a problem with the XmlMapper (com.fasterxml.jackson.dataformat.xml.XmlMapper from com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.20.1).

I found this question which seems to indicate just using the CDATA block should work.

Any ideas?

4
  • 1
    What do you see when execute your plugin with -X ... should be something about configurations and value passed to your params Commented Nov 26 at 23:10
  • [DEBUG] (s) description = <p>Initial release</p> [DEBUG] (f) releases = [flatpak.maven.plugin.models.Release@799fb45e] [DEBUG] (f) releases = [flatpak.maven.plugin.models.Release@799fb45e]. It's a complex object, a List<Release> each of which has a String field called description. The output shows unencoded p-tags. I've debugged to the point where the XmlMapper writes and , before the write, the release instance has a description without the encoding. Commented Nov 26 at 23:29
  • 1
    What is the library or fully-qualified name of that XmlMapper class? That said, what you see is the correct behaviour for writing a value with < into XML. If you want something else, then you will need to do more work, so it actually writes an XML fragment instead of a value (how or if you can do so depends on the actual XML library). Commented Nov 27 at 9:49
  • Thanks for replying. It's com.fasterxml.jackson.dataformat.xml.XmlMapper from com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.20.1. But I can try another solution if it helps. Can you point me at some code that writes an XML fragment when it's the value? Commented Nov 27 at 13:23

1 Answer 1

2

If you want to embed some XML fragments into the generated document, I don't think that high-level XML mappers are the right tool. I would use a more manual approach. Here is a solution based on the XOM library.

Assuming you have this class:

public class MetaInfo
{
    private String id;
    private String name;
    private String description;

    public String getId()
    {
        return id;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getDescription()
    {
        return description;
    }

    public void setDescription(String description)
    {
        this.description = description;
    }
}

You can generate the MetaInfo file like this:

import java.io.*;
import nu.xom.*;

class MetaInfoGenerator
{
    private void addSimpleValue(Element parent, String name, String value)
    {
        Element element = new Element(name);
        element.appendChild(value);
        parent.appendChild(element);
    }

    private void addXmlValue(Element parent, String name, String value) throws ParsingException, IOException
    {
        String xml = String.format("<%s>%s</%s>", name, value, name);
        Document doc = new Builder().build(xml, null);
        parent.appendChild(doc.getRootElement().copy());
    }

    public void createMetaInfo(MetaInfo metaInfo, OutputStream out) throws ParsingException, IOException
    {
        Element root = new Element("component");
        root.addAttribute(new Attribute("type", "desktop-application"));
        addSimpleValue(root, "id", metaInfo.getId());
        addSimpleValue(root, "name", metaInfo.getName());
        addXmlValue(root, "description", metaInfo.getDescription());

        Document doc = new Document(root);
        Serializer serializer = new Serializer(out, "UTF-8");
        serializer.setIndent(4);
        serializer.write(doc);
    }

    public static void main(String[] args) throws ParsingException, IOException
    {
        MetaInfo metaInfo = new MetaInfo();
        metaInfo.setId("com.example.foobar");
        metaInfo.setName("Foo Bar");
        metaInfo.setDescription("<p>An awesome app!</p>");

        new MetaInfoGenerator().createMetaInfo(metaInfo, System.out);
    }
}

Output:

<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
    <id>com.example.foobar</id>
    <name>Foo Bar</name>
    <description>
        <p>An awesome app!</p>
    </description>
</component>
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.