Nano Hash - криптовалюты, майнинг, программирование

JAXB: полиморфизм и игнорирование класса как типа при маршалинге

Я использую JAXB для маршалинга классов Java. Я не могу понять, какую аннотацию xml я должен использовать в следующем сценарии:

XSD:

...
<xs:complexType name = "Message">
    <xs:sequence>
        <xs:element name = "memberOne"  type = "xs:hexBinary"/>
        <xs:element name = "memberTwo"  type = "xs:unsignedByte"/>
        <xs:choice>
            <xs:element name = "typeOne"        type = "MessageTypeOne"/>
            <xs:element name = "typeTwo"        type = "MessageTypeTwo"/>
            <xs:element name = "typeThree"      type = "MessageTypeThree"/>
        </xs:choice>
    </xs:sequence>
</xs:complexType>
..

MessageTypeOne/Two/Three определены ранее, но не важны для этого сценария.

Классы Java:

Message.java

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Message", propOrder = {
    "memberOne",
    "memberTwo",
})
public class Message{

    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(HexBinaryAdapter.class)
    @XmlSchemaType(name = "hexBinary")
    protected byte[] memberOne;
    @XmlSchemaType(name = "unsignedByte")
    protected short memberTwo;
    //Which annotations i have to use here?
    protected MessageBody messageBody;

    ...
}

MessageBody.java

//Which annotations i have to use here?
public class MessageBody {
    //Which annotations i have to use here?
    MessageType myChoice;

    ...
}

MessageBody не упоминается в файле XSD. Это должно быть "проигнорировано" при маршалинге. Только член его класса myChoice должен быть выстроен.

Я уже думал о реализации своего собственного XmlAdapter, но не смог найти способ решить проблему.

MessageType.java

public abstract class MessageType { ... }

Это базовый класс.

MessageTypeOne.java

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MessageTypeOne", propOrder = {
    "memberOne",
    "memberTwo",
})
public class MessageTypeOne extends MessageType {
    @XmlSchemaType(name = "unsignedByte")
    protected short memberOne;
    @XmlSchemaType(name = "unsignedByte")
    protected short memberTwo;

    ...
}

MessageTypeTwo/Three похожи на этот.

Пример вывода XML, который я могу сейчас получить:

<Message>
    <memberOne>01020304</memberOne>
    <memberTwo>5</memberOne>
    <MessageBody>
        <MessageTypeOne>
            ...
        </MessageTypeOne>
    </MessageBody>
</Message>

Желаемый вывод XML:

<Message>
    <memberOne>01020304</memberOne>
    <memberTwo>5</memberOne>
    <MessageTypeOne>
            ...
    </MessageTypeOne>
</Message>

Поэтому я просто хочу удалить тег <MessageBody> .. </MessageBody>.

Очевидно, я просто хочу прояснить проблему. На самом деле код намного сложнее.

Мне НЕ разрешено изменять файл XSD и разрешено вносить только незначительные изменения в классы java. Я НЕ могу изменить отношение классов друг к другу.

Мои вопросы:

  • Какие аннотации нужно использовать, чтобы пропустить класс MessageBody при маршаллинге? Как я могу указать JAXB, что нужно упорядочивать только своих участников myChoice?

  • Как полиморфизм работает в JAXB? Какую аннотацию мне нужно использовать для этого?

  • Можно ли в целом решить эту проблему с помощью JAXB?

РЕДАКТИРОВАТЬ: добавлены примеры выходных данных XML

28.05.2017

  • Не могли бы вы привести конкретный пример XML (желаемый результат)? Это сделало бы ответы намного проще. 28.05.2017
  • Добавлен и пример XML. Надеюсь, это поможет прояснить мою проблему. 28.05.2017

Ответы:


1

Как полиморфизм работает в JAXB? Какую аннотацию мне нужно использовать для этого?

Вы можете достичь такого рода полиморфизма JAXB с помощью @XmlElements аннотация:

@XmlAccessorType(XmlAccessType.FIELD)
public class MessageBody {
    @XmlElements({
        @XmlElement(name = "MessageTypeOne",   type = MessageTypeOne.class),
        @XmlElement(name = "MessageTypeTwo",   type = MessageTypeTwo.class),
        @XmlElement(name = "MessageTypeThree", type = MessageTypeThree.class)
    })
    protected MessageType myChoice;

    ...
}

Редактировать:

Какие аннотации мне нужно использовать, чтобы пропустить класс MessageBody при маршалинге? Как я могу указать JAXB, что нужно упорядочивать только своего участника myChoice?

Вы можете удалить класс MessageBody. Вместо этого поместите свойство myChoice непосредственно в класс Message.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Message", propOrder = {
    "memberOne",
    "memberTwo",
    "myChoice"
})
public class Message{

    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(HexBinaryAdapter.class)
    @XmlSchemaType(name = "hexBinary")
    protected byte[] memberOne;

    @XmlSchemaType(name = "unsignedByte")
    protected short memberTwo;

    @XmlElements({
        @XmlElement(name = "MessageTypeOne",   type = MessageTypeOne.class),
        @XmlElement(name = "MessageTypeTwo",   type = MessageTypeTwo.class),
        @XmlElement(name = "MessageTypeThree", type = MessageTypeThree.class)
    })
    protected MessageType myChoice;

    //...
}
28.05.2017
  • Это окончательно решило мою проблему с полиморфизмом! Спасибо! 28.05.2017
  • @Truntle добавил решение для пропуска MessageBody 28.05.2017
  • Это на самом деле то, что я придумал. Это действительно работает. Но мне не разрешено удалять MessageBody класс. При демаршаллинге мне нужно снова создать MessageBody. Я нашел решение, которое выглядит не очень чистым, но я думаю, что в JAXB нет другого выхода. Я отправлю это позже. 29.05.2017

  • 2

    Благодаря ответу Томаса Фритчса, который предложил основную идею, я смог решить проблему. Я буду использовать его код, чтобы ответить на свой вопрос.

    Проблема, с которой мне обычно приходилось сталкиваться, заключалась в том, что мне не разрешалось избавляться от класса MessageBody. Поэтому мне пришлось создать член messageBodyChoice в классе Message, чтобы иметь к нему прямой доступ.

    На этом этапе маршаллинг работает нормально, а немаршаллинг - нет. Файл XSD не содержит определения для MessageBody, поэтому JAXB никогда не сможет автоматически его демаршалировать.

    Чтобы сделать это вручную, я добавил следующий метод:

    void afterUnmarshal(Unmarshaller u, Object parent) { ... }
    

    (Смотрите этот пост для более подробной информации: Как я могу заставить JAXB вызывать метод после того, как он завершил демаршалинг XML-файла в объект?)

    Вы можете просто добавить этот метод к любому классу, который будет демонтирован / упорядочен без каких-либо других усилий. с помощью этого метода я смог инициализировать messageBody после демаршалинга.

    Решение в коде:

    Message.java

    @XmlAccessorType(XmlAccessType.NONE)
    @XmlType(name = "Message", propOrder = {
        "memberOne",
        "memberTwo",
        "messageBodyChoice"
    })
    public class Message{
    
        @XmlElement(required = true, type = String.class)
        @XmlJavaTypeAdapter(HexBinaryAdapter.class)
        @XmlSchemaType(name = "hexBinary")
        protected byte[] memberOne;
    
        @XmlSchemaType(name = "unsignedByte")
        protected short memberTwo;
    
        protected MessageBody messageBody;
    
        //This member is only needed for marshalling!!!
        @XmlElements({
            @XmlElement(name = "MessageTypeOne",   type = MessageTypeOne.class),
            @XmlElement(name = "MessageTypeTwo",   type = MessageTypeTwo.class),
            @XmlElement(name = "MessageTypeThree", type = MessageTypeThree.class)
        })
        protected MessageType messageBodyChoice;
    
        //...
    
        /* 
         * This setter ensures that messageBodyChoice always contains
         * the value of messageBody.getChoice()
         */
        public void setMessageBody(MessageBody messageBody){
            this.messageBody = messageBody;
            if(messageBody != null) 
                this.messageBodyChoice = messageBody.getChoice();
        }
    
        //...
    
        void afterUnmarshal(Unmarshaller u, Object parent) { 
            //at this point messageBody is null
            messageBody = new MessageBody();
            messageBody.setChoice(messageBodyChoice);
        }
    }
    

    Обратите внимание, что я изменил @XmlAccessorType на XmlAccessType.NONE. Дополнительная информация о @XmlAccessorType здесь.

    Это может выглядеть нечисто, но это единственный возможный способ избежать тега <MessageBody> в выводе XML.

    29.05.2017
  • Здорово, что ты все решил! Вы должны отметить свой ответ как принятый и, возможно, проголосуете за мой ответ. 29.05.2017
  • @Thomas Я не могу отметить свой ответ до завтра и уже пытался проголосовать за ваш ответ, но мне нужна еще одна репутация. Появляется сообщение: Спасибо за отзыв! Голоса, отданные теми, у кого репутация менее 15, записываются, но не меняют рейтинг публично отображаемых сообщений. 29.05.2017
  • Ах ладно нет проблем 29.05.2017
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..