Шаблон прототипа MOXy/JAXB - наследование интерфейса

Я пытаюсь реализовать версию шаблона прототипа Gang of Four, используя MOXy/JAXB 2.5.0. Я хочу иметь возможность указывать список элементов, некоторые из которых «основаны» на других, т.е. копировать их данные из других экземпляров. Для повторного использования я хотел бы создать интерфейс, который должен реализовывать любой объект, способный создавать прототипы, который будет предоставлять аннотации для свойств, необходимых для поддержки шаблона.

@XmlRootElement(name="IPrototype")
public interface IPrototype
{
    /**
     * Acts as a "copy constructor"
     */
    @XmlAttribute(name="prototype")
    @XmlIDREF
    public void setPrototype(IPrototype prototype); 

    @XmlAttribute(name="id")
    @XmlID
    public void setId(String id);

    public String getId();
}

Реализующий объект в идеале должен выглядеть примерно так, даже не заморачиваясь аннотацией методов, реализованных из интерфейса:

@XmlRootElement(name="Item")
public class Item implements IPrototype
{
    private String m_id = null;

    private String m_data = null;

    public Item()
    {

    }

    /**
     * Never called
     */
    @Override
    public void setPrototype(IPrototype prototype)
    {
        m_data = ((Item)prototype).getData();
    }

    @Override
    public void setId(String id)
    {
        m_id = id;
    }

    @Override
    public String getId()
    {
        return m_id;
    }

    @XmlAttribute(name="data")
    public void setData(String data)
    {
        m_data = data;
    }

    public String getData()
    {
        return m_data;
    }
}

И XML будет выглядеть так:

<Wrapper>
    <Item id="Item1" data="stuff and things" />
    <Item id="Item2" prototype="Item1" />
</Wrapper>

где Wrapper определяется как:

@XmlRootElement(name="Wrapper")
public class Wrapper
{
    @XmlElementRef
    private ArrayList<Item> m_items = null; 
}

Если бы это работало так, как я хочу, я бы получил список с двумя элементами, оба типа Item, которые содержат одни и те же данные. Однако MOXy, кажется, не «видит» аннотации в интерфейсе, и я получаю список с двумя элементами, у которых не установлен их XmlID, а setPrototype() никогда не вызывается. Единственным решением, по-видимому, является аннотирование методов setPrototype() и setId() в классе Item, но для этого требуется изменить тип аргумента setPrototype() с IPrototype на Item, чтобы MOXy искал XmlID в правильном классе. К сожалению, это нарушает унаследованный интерфейс.

Если вместо этого я изменю тип списка на IPrototype, надеясь, что это позволит MOXy увидеть его аннотации, я получу то же поведение - нулевой идентификатор, setPrototype() никогда не вызывается. В любом случае это не совсем то, что я хочу, я хотел бы иметь возможность ограничивать, какие подтипы могут быть включены в конкретный список.

Не уверен, что у меня есть правильные ожидания относительно того, как должны работать аннотации интерфейса, возможно, это источник моей ошибки.

Любые мысли о том, как заставить это работать? Заранее спасибо,

Стив

ОБНОВЛЕНИЕ: если я аннотирую класс Item, БЕЗ изменения сигнатуры метода setPrototype (с которой, я думаю, я могу жить), я получаю список с двумя элементами с правильно установленными XmlID, но setPrototype() все еще не вызывается. Похоже, что MOXy ищет экземпляры IPrototype (невозможно) с тем же XmlID, а не экземпляры Item.

ОБНОВЛЕНИЕ 2: И если я конвертирую IPrototype в абстрактный класс, все работает отлично. Однако, учитывая модель одиночного наследования в Java, это слишком ограничивает объект фреймворка, предназначенный для дополнения множественных иерархий наследования. Так еще и застрял.


person Stephen Carlson    schedule 29.05.2013    source источник


Ответы (2)


Я получил несколько приемлемую версию этого запуска, аннотировав свойства Item и объявив setPrototype() с использованием дженериков. Вот как выглядит объявление в IPrototype:

public <T> void setPrototype(T prototype);

А вот его реализация в Item:

@XmlAttribute(name="prototype")
@XmlIDREF
@Override
public <T> void setPrototype(T prototype)
{
    m_data = ((Item)prototype).getData();
}

Это работает, но мне не особенно нравится повторно аннотировать подкласс. Я открыл отдельный вопрос об этом, поскольку интуитивно (мне) не кажется, что так должны работать аннотации интерфейса:

Аннотация интерфейса MOXy/JAXB

person Stephen Carlson    schedule 02.06.2013
comment
Но это не сработает, если я попытаюсь объявить метод с параметром ограниченного типа: Я получаю исключение, жалующееся на то, что у IPrototype нет свойства, аннотированного @XmlID. Если я аннотирую эти методы, setPrototype() не вызывается. Так безгранично пока. - person Stephen Carlson; 02.06.2013

Вы можете использовать внешний документ привязки MOXy для переопределения суперкласса реализующих классов (т. е. Item) от Object до интерфейса IPrototype. Это позволит вам наследовать сопоставления от интерфейса.

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum16807019">
    <java-types>
        <java-type name="Item" super-type="forum16807019.IPrototype"/>
    </java-types>
</xml-bindings>

Полный пример см.

person bdoughan    schedule 07.06.2013