为什么这个模型映射器映射失败?

问题描述 投票:0回答:1

我正在尝试使用 ModelMapper 将 json pojo 映射到 xml pojo...

在下面的代码中,我期望看到“jsonSource”(源)POJO 的内容转移到 xmlDest POJO(目标)

...但是,代码失败 - 因为(“jsonSource”)中没有数据反映在目标(“xml”)中。即,如“.size()”方法值所示的差异。

来源(json)

jsonSource.getEmployees().size() == 2

目标(xml)

xml.getEmployees().size() == 0    <<< should also be 2

代码片段...

    @Test
    public void givenJsonSource_whenMapToXmlDest_thenFieldsMapCorrectly() throws Exception {

        Employees jsonSource = new Employees();
        List<Employee> employees = new ArrayList<>();

        Employee employee1 = new Employee();
        employee1.setName("thename");
        employee1.setGender("M");
        employee1.setAge(30);
        employees.add(employee1);

        Employee employee2 = new Employee();
        employee2.setName("thename2");
        employee2.setGender("M2");
        employee2.setAge(32);
        employees.add(employee2);

        jsonSource.setEmployees(employees);

        aaa.bbb.ccc.jar.generated.Employees xml = mapper.map(jsonSource, aaa.bbb.ccc.jar.generated.Employees.class);

        System.out.println("jsonSource.getEmployees().size()=>" + jsonSource.getEmployees().size());  // <<< 2
        System.out.println("xmlDest.getEmployee().size()=>" + xml.getEmployees().size());  // <<< 0


        // verify fields
        assertEquals(xml.getEmployees().get(0).getName(), jsonSource.getEmployees().get(0).getName());
    }
    

...虽然 jsonSource.getEmployees().size 是 2,但 xmlDest.getEmployee.size() 是 0

这是 Employee json pojo 类(上面引用)...

    package aaa.bbb.ccc.jar;

    import com.fasterxml.jackson.annotation.JsonProperty;

    public class Employee {

        @JsonProperty("name") 
        String name;
        @JsonProperty("gender")     
        String gender;
        @JsonProperty("age")     
        Integer age;
        
        public Employee() {
        }
        public Employee(String name, String gender, Integer age) {
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getGender() {
            return gender;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Employee{" + "name=" + name + ", gender=" + gender + ", age=" + age + '}';
        }

    }

这是Employees json POJO 类...

    package aaa.bbb.ccc.jar;

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

    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonRootName;

    @JsonRootName(value = "Employees")
    public class Employees {
        
        @JsonProperty(value = "Employees")
        protected List<Employee> employees;

        public Employees() {
        }

        public List<Employee> getEmployees() {
            if (employees == null) {
                employees = new ArrayList<>();
            }
            return this.employees;
        }

        public void setEmployees(List<Employee> employees) {
            this.employees = employees;
        }

        @Override
        public String toString() {
            return "Employees{" + "employees=" + employees + '}';
        }
        
    }

这是生成的 xml POJO (aaa.bbb.ccc.jar. generated.Employee)

    //
    // This file was generated by the Eclipse Implementation of JAXB, v3.0.0 
    // See https://eclipse-ee4j.github.io/jaxb-ri 
    // Any modifications to this file will be lost upon recompilation of the source schema. 
    // Generated on: 2024.04.12 at 08:27:40 AM EDT 
    //


    package aaa.bbb.ccc.jar.generated;

    import jakarta.xml.bind.annotation.XmlAccessType;
    import jakarta.xml.bind.annotation.XmlAccessorType;
    import jakarta.xml.bind.annotation.XmlElement;
    import jakarta.xml.bind.annotation.XmlType;


    /**
     * <p>Java class for Employee complex type.
     * 
     * <p>The following schema fragment specifies the expected content contained within this class.
     * 
     * <pre>
     * &lt;complexType name="Employee"&gt;
     *   &lt;complexContent&gt;
     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
     *       &lt;all&gt;
     *         &lt;element name="Name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
     *         &lt;element name="Gender" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
     *         &lt;element name="Age" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/&gt;
     *       &lt;/all&gt;
     *     &lt;/restriction&gt;
     *   &lt;/complexContent&gt;
     * &lt;/complexType&gt;
     * </pre>
     * 
     * 
     */
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Employee", propOrder = {

    })
    public class Employee {

        @XmlElement(name = "Name")
        protected String name;
        @XmlElement(name = "Gender")
        protected String gender;
        @XmlElement(name = "Age")
        protected Integer age;

        /**
         * Gets the value of the name property.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getName() {
            return name;
        }

        /**
         * Sets the value of the name property.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setName(String value) {
            this.name = value;
        }

        /**
         * Gets the value of the gender property.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getGender() {
            return gender;
        }

        /**
         * Sets the value of the gender property.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setGender(String value) {
            this.gender = value;
        }

        /**
         * Gets the value of the age property.
         * 
         * @return
         *     possible object is
         *     {@link Integer }
         *     
         */
        public Integer getAge() {
            return age;
        }

        /**
         * Sets the value of the age property.
         * 
         * @param value
         *     allowed object is
         *     {@link Integer }
         *     
         */
        public void setAge(Integer value) {
            this.age = value;
        }

    }

这是生成的 xml pojo(即 aaa.bbb.ccc.jar. generated.Employees)

    //
    // This file was generated by the Eclipse Implementation of JAXB, v3.0.0 
    // See https://eclipse-ee4j.github.io/jaxb-ri 
    // Any modifications to this file will be lost upon recompilation of the source schema. 
    // Generated on: 2024.04.12 at 08:27:40 AM EDT 
    //


    package aaa.bbb.ccc.jar.generated;

    import java.util.ArrayList;
    import java.util.List;
    import jakarta.xml.bind.annotation.XmlAccessType;
    import jakarta.xml.bind.annotation.XmlAccessorType;
    import jakarta.xml.bind.annotation.XmlElement;
    import jakarta.xml.bind.annotation.XmlRootElement;
    import jakarta.xml.bind.annotation.XmlType;


    /**
     * <p>Java class for anonymous complex type.
     * 
     * <p>The following schema fragment specifies the expected content contained within this class.
     * 
     * <pre>
     * &lt;complexType&gt;
     *   &lt;complexContent&gt;
     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
     *       &lt;sequence&gt;
     *         &lt;element name="Employees" type="{http://www.aaa.bbb.ccc/jar/mmdemo}Employee" maxOccurs="unbounded" minOccurs="0"/&gt;
     *       &lt;/sequence&gt;
     *     &lt;/restriction&gt;
     *   &lt;/complexContent&gt;
     * &lt;/complexType&gt;
     * </pre>
     * 
     * 
     */
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "employees"
    })
    @XmlRootElement(name = "Employees")
    public class Employees {

        @XmlElement(name = "Employees")
        protected List<Employee> employees;

        /**
         * Gets the value of the employees property.
         * 
         * <p>
         * This accessor method returns a reference to the live list,
         * not a snapshot. Therefore any modification you make to the
         * returned list will be present inside the Jakarta XML Binding object.
         * This is why there is not a <CODE>set</CODE> method for the employees property.
         * 
         * <p>
         * For example, to add a new item, do as follows:
         * <pre>
         *    getEmployees().add(newItem);
         * </pre>
         * 
         * 
         * <p>
         * Objects of the following type(s) are allowed in the list
         * {@link Employee }
         * 
         * 
         */
        public List<Employee> getEmployees() {
            if (employees == null) {
                employees = new ArrayList<Employee>();
            }
            return this.employees;
        }

    }

这是用于生成 XML 类的 xsd

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema 
        targetNamespace="http://www.aaa.bbb.ccc/jar/mmdemo"
        attributeFormDefault="unqualified"
        elementFormDefault="qualified"
        xmlns:es="http://www.aaa.bbb.ccc/jar/mmdemo"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
                
        <xs:complexType name="Employee">
            <xs:all>
                
                <xs:element name="Name" type="xs:string" minOccurs="0" />
                <xs:element name="Gender" type="xs:string" minOccurs="0" />
                <xs:element name="Age" type="xs:int" minOccurs="0" />
                                                        
            </xs:all>
        </xs:complexType>

        <xs:element name="Employees">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="Employees" type="es:Employee" minOccurs="0" maxOccurs="unbounded" />
                </xs:sequence>
            </xs:complexType>
        </xs:element>

    </xs:schema>

感谢任何帮助/提示来理解可能缺少的内容,从而使上述工作

json xml java-17 modelmapper spring-boot-3
1个回答
0
投票

看起来“一个”解决方案是在for循环中单独映射Employees的元素......

        for (Employee sourceEmployee : sourceEmployees) {
            aaa.bbb.ccc.jar.generated.Employee destEmployee = mapper.map(sourceEmployee, aaa.bbb.ccc.jar.generated.Employee.class);
            xml.getEmployees().add(destEmployee);
        }   

几乎可以肯定,这不一定是唯一的解决方案 -但是,现在可以了......

    @Test
    public void givenJsonSource_whenMapToXmlDest_thenFieldsMapCorrectly() throws Exception {

        Employees jsonSource = new Employees();
        List<Employee> employees = new ArrayList<>();

        Employee employee1 = new Employee();
        employee1.setName("thename");
        employee1.setGender("M");
        employee1.setAge(30);
        employees.add(employee1);

        Employee employee2 = new Employee();
        employee2.setName("thename2");
        employee2.setGender("M2");
        employee2.setAge(32);
        employees.add(employee2);

        jsonSource.setEmployees(employees);
        
        aaa.bbb.ccc.jar.generated.Employees xml = new aaa.bbb.ccc.jar.generated.Employees();
        
        List<Employee> sourceEmployees = jsonSource.getEmployees();
        for (Employee sourceEmployee : sourceEmployees) {
            aaa.bbb.ccc.jar.generated.Employee destEmployee = mapper.map(sourceEmployee, aaa.bbb.ccc.jar.generated.Employee.class);
            xml.getEmployees().add(destEmployee);
        }        

        System.out.println("jsonSource.getEmployees().size()=>" + jsonSource.getEmployees().size());
        System.out.println("xmlDest.getEmployee().size()=>" + xml.getEmployees().size());


        // verify fields
        assertEquals(xml.getEmployees().get(0).getName(), jsonSource.getEmployees().get(0).getName());
    }
© www.soinside.com 2019 - 2024. All rights reserved.