BATMAN_2008
BATMAN_2008

Reputation: 3520

JAXB marshalling avoid adding the additional <name> wrapper during the custom XmlAdapter

I have a simple Java program that marshalls my Java object to XML. It's working fine but the only problem is that during the marshalling of List<String> it adds an additional <name> which I do not want.

I have a field in my Employee.class which is Object and it can be either a String or List<String> so to Jakarta/JAXB marshall field I am using my own custom XMLAdapter and for the simple String it works fine but for List<String> it adds <name> which I do not want.

Following is my code for Employee.class:

import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
    @XmlJavaTypeAdapter(CustomNameAdapter.class)
    private Object name;
}

Following is my custom XMLAdapter CustomNameAdapter.class:

import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilderFactory;
import java.util.List;

public class CustomNameAdapter extends XmlAdapter<Object, Object> {
    @Override
    public Object unmarshal(Object v) {
        return null;
    }

    //During the writing of XML handle either simple String or List<String> and write name field
    @Override
    public Object marshal(Object name) throws Exception {
        System.out.println("Obtained Name Values : " + name);
        final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

        if (name instanceof String) {
            final Element root = document.createElement("name");
            root.setTextContent((String) name);
            return root;
        } else if (name instanceof List) {
            final List<String> infoList = (List<String>) name;
            final Element root = document.createElement("name");

            for (final String item : infoList) {
                final Element element = document.createElement("name");
                element.setTextContent(item);
                root.appendChild(element);
            }
            return root;
        }
        return null;
    }
}

Following is my Main method MarshallerMain.class:

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;

import java.util.ArrayList;
import java.util.List;

public class MarshallerMain {
    public static void main(String[] args) throws JAXBException {
        final Employee employee1 = new Employee("Name1");

        final List<String> names = new ArrayList<String>();
        names.add("one");
        names.add("two");
        names.add("three");

        final Employee employee2 = new Employee(names);

        final JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
        final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        System.out.println("Employee 1 Simple String : ");
        jaxbMarshaller.marshal(employee1, System.out);

        System.out.println("Employee 2 List of String : ");
        jaxbMarshaller.marshal(employee2, System.out);
    }
}

Following is my complete output that I get:

Employee 1 Simple String : 
Obtained Name Values : Name1
<?xml version="1.0" encoding="UTF-8"?>
<employee>
   <name>Name1</name>
</employee>
Employee 2 List of String : 
Obtained Name Values : [one, two, three]
<?xml version="1.0" encoding="UTF-8"?>
<employee>
   <name>
      <name>one</name>
      <name>two</name>
      <name>three</name>
   </name>
</employee>

But I want the output for List<String> without additional wrapping with <name>:

<employee>
   <name>one</name>
   <name>two</name>
   <name>three</name>
</employee>

How to fix the issue during the XML marshalling to ensure I do not get additional wrapping for my <name>?

Upvotes: 2

Views: 62

Answers (1)

lance-java
lance-java

Reputation: 27958

Perhaps you could just do

@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements Serializable {
    private List<String> name;

    public Employee(String name) {
       this.name = name == null ? null : List.of(name);
    }
}

Upvotes: 1

Related Questions