Защо MOXy JAXB маршалира до празен низ, докато референтната реализация на JAXB не го прави?

Тестът JUnit, показан по-долу, се проваля (в моята среда) с MOXy, но работи с референтната реализация на JAXB.

Очакваният получен XML е:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<itemManager>
    <items>
        <value>2</value>
    </items>
</itemManager>

но с включен MOXy - jaxb.properties, съдържащ:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

полученият XML низ е празен.

Каква може да е причината за това поведение и какво трябва да се направи, за да се коригира?

Опитах EclipseLink MOXy версии 2.5.1 и 2.4.2 - вижте pom.xml фрагмента по-долу. Зависимостта е първата в pom.xml, последвана от много други (които също може да са развалили шоуто).

<!-- Eclipselink moxy -->
<dependency>
  <groupId>org.eclipse.persistence</groupId>
  <artifactId>org.eclipse.persistence.moxy</artifactId>
  <version>2.4.2</version> 
  <!--  <version>2.5.1</version>   -->
  <scope>test</scope>
</dependency>

Java код на теста JUnit:

package com.bitplan.storage.moxy;

import static org.junit.Assert.*;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.junit.Test;

/**
 * show problem with empty xml result for Jaxb Marshaller
 * 
 * @author wf
 * 
 */
public class TestEmptyXml {

    public interface Copyable<T> {
        /**
         * copy me from the copyable
         * 
         * @param othe
         *          - the source copyaqble to copy from
         */
        public void copyFrom(T other);
    }

    public interface BO<BO_T> extends Copyable<BO_T> {

    }

    public interface ItemInterface {

    }

    @XmlRootElement
    public static class Item implements ItemInterface {
        int value;

        /**
         * @return the value
         */
        public int getValue() {
            return value;
        }

        /**
         * @param value
         *          the value to set
         */
        public void setValue(int value) {
            this.value = value;
        }

        public Item() {

        }

        public Item(int pValue) {
            value = pValue;
        }

    }

    public interface ItemManagerInterface {
        public void setItems(List<Item> pItems);

        public List<Item> getItems();
    }

    public interface MoxyList<BO_T> extends Collection<BO_T> {

    }

    public interface MoxyManager<BO_T> extends MoxyList<BO_T> {
    }

    public static class MoxyManagerImpl<BO_T> implements MoxyManager<BO_T> {
        public transient List<BO_T> bolist = new ArrayList<BO_T>();

        @Override
        public boolean add(BO_T arg0) {
            boolean result = bolist.add(arg0);
            return result;
        }

        @Override
        public boolean addAll(Collection<? extends BO_T> arg0) {
            boolean result = bolist.addAll(arg0);
            return result;
        }

        @Override
        public void clear() {
            bolist.clear();
        }

        @Override
        public boolean contains(Object arg0) {
            boolean result = bolist.contains(arg0);
            return result;
        }

        @Override
        public boolean containsAll(Collection<?> arg0) {
            boolean result = bolist.containsAll(arg0);
            return result;
        }

        @Override
        public boolean isEmpty() {
            boolean result = bolist.isEmpty();
            return result;
        }

        @Override
        public Iterator<BO_T> iterator() {
            Iterator<BO_T> result = bolist.iterator();
            return result;
        }

        @Override
        public boolean remove(Object arg0) {
            boolean result = bolist.remove(arg0);
            return result;
        }

        @Override
        public boolean removeAll(Collection<?> arg0) {
            boolean result = bolist.removeAll(arg0);
            return result;
        }

        @Override
        public boolean retainAll(Collection<?> arg0) {
            boolean result = bolist.retainAll(arg0);
            return result;
        }

        @Override
        public int size() {
            int result = bolist.size();
            return result;
        }

        @Override
        public Object[] toArray() {
            Object[] result = bolist.toArray();
            return result;
        }

        @Override
        public <T> T[] toArray(T[] arg0) {
            T[] result = bolist.toArray(arg0);
            return result;
        }

    }

    @XmlAccessorType(XmlAccessType.NONE)
    @XmlTransient
    public static abstract class MyMoxyManager<BO_T> extends
            MoxyManagerImpl<BO_T> {
        public abstract Class<? extends BO<?>> getEntityType();

    }

    @XmlRootElement
    public static class ItemManager extends MyMoxyManager<Item> implements
            ItemManagerInterface {
        public ItemManager() {

        }

        private List<Item> items = new ArrayList<Item>();

        @Override
        @XmlElement
        public void setItems(List<Item> pItems) {
            items = pItems;
        }

        @Override
        public List<Item> getItems() {
            return items;
        }

        @SuppressWarnings("unchecked")
        @Override
        public Class<? extends BO<?>> getEntityType() {
            return (Class<? extends BO<?>>) Item.class;
        }
    }

    /**
     * convert the target to XML Format
     * 
     * @param target
     * @return
     * @throws Exception
     */
    public String asXML(Object target) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(target.getClass());
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
        // output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        StringWriter sw = new StringWriter();
        jaxbMarshaller.marshal(target, sw);
        String result = sw.toString();
        return result;
    }

    @Test
    public void testMarshall() throws Exception {
        ItemManager im = new ItemManager();
        im.items.add(new Item(2));
        String xml = asXML(im);
        System.out.println(xml);
        assertNotEquals("xml should not be empty", "", xml);
    }

}

person Wolfgang Fahl    schedule 13.10.2013    source източник


Отговори (1)


Във вашия пример параметърът target, който се маршалира, е екземпляр на ItemManager. Поради следната организация на класовете MOXy в крайна сметка смята, че ItemManager е колекция, а не домейн обект, поради което се случват странни неща.

  • ItemManager -разширява-> MyMoxyManager
  • MyMoxyManager -разширява-> MoxyManagerImpl
  • MoxyManagerImpl -прилага-> MoxyManager
  • MoxyManager -разширява-> MoxyList
  • MoxyList -разширява-> Collection

Все още трябва да проуча какво трябва да бъде правилното поведение за този случай на употреба. Можете ли да отворите грешка за този проблем.

person bdoughan    schedule 15.10.2013
comment
Благодаря - чрез отстраняване на грешки в изходния код открих същото поведение. Моля, следете за моя доклад за грешка - ще отнеме няколко дни. - person Wolfgang Fahl; 16.10.2013