JAXB Как заставить XSI: тип в массиве подклассов? (JBoss 4.2.3) - PullRequest
1 голос
/ 06 июля 2011

(обратите внимание; я совершенно новичок в веб-сервисах, поэтому следующее может быть глупым / неправильным, но, пожалуйста, будьте терпеливы)

В моем @SebMethod веб-сервисов я возвращаю массив абстрактной базыкласс (аннотированные сущности JAXB в JBoss 4.2.3).

Очевидно, что если информация о типе не закодирована для каждого элемента массива, это не удастся ...

Итак, как мне убедиться, что JAXBдобавляет атрибут xsi: type ?

Мой интерфейс WebService содержит следующую аннотацию, и я пробовал все допустимые комбинации:

@ SOAPBinding (style =RPC, parameterStyle = WRAPPED, use = LITERAL)

методы этого интерфейса принимают аннотации x2 параметров @WebParam (name = "...", mode = IN)

Другие методы с похожимиподписи, которые не возвращают гетерогенный массив, работают отлично.


Некоторые связанные вещи:

Похоже, JBoss использует типы, определенные в сигнатурах методов, чтобы решить, какие классы загружать вJAXBConтекст - если я изменяю тип возвращаемого значения на Object [], он выдает ошибку, утверждающую, что класс AbstractBase «ни один из его суперкласса не известен этому контексту».Я добавил фиктивные методы, возвращающие определенные подклассы, чтобы сгенерированный WSDL имел список всех из них.

, когда я пытаюсь написать тесты для этого, все в порядке для отдельных элементов, но JAXB выдает ошибкудля типов массива: невозможно маршалировать тип "[LAbstractBase;"как элемент, потому что в нем отсутствует аннотация @XmlRootElement

Из кода, подобного показанному ниже (примечание: AbstractBase, ConcreteOne и ConcreteTwo имеют аннотации @XmlRootElement)

private static final Class<?>[] CLASSES_TO_BE_BOUND = new Class<?>[]{
    //Note; adding AbstractBase[].class doesn't work either
    AbstractBase.class, ConcreteOne.class, ConcreteTwo.class
};

@Test
public void testXsiTypeAttributeIsIncludedInHeterogeneousArray()
{
    AbstractBase[] array = new AbstractBase[2];
    array[0] = new ConcreteOne();
    array[1] = new ConcreteTwo();
    Marshaller marshaller = createMarshaller();
    StringWriter sw = new StringWriter();
    marshaller.marshal(array, sw);
    String output = sw.toString();
    Assert.assertTrue(output.contains("xsi:type=\""));
}


private Marshaller createMarshaller() throws Exception {
    JAXBContext context = JAXBContext.newInstance(CLASSES_TO_BE_BOUND);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    return marshaller;
}

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


Редактировать: Собственный ответ

JBoss (4.2.3) делает что-то умное, но не слишком умное - оно будет обрабатывать возврат массивов, но не полиморфных массивов.Это немного поразило меня, когда я попытался заставить этот способ работать в своих тестах.

Вместо того, чтобы пытаться решить проблему JBoss WebService, я сделал свои тесты более всеобъемлющими - сделав массив простым членомКонтейнерный класс, а затем аннотировать получатель массива с помощью:

@XmlElementRefs({
    @XmlElementRef(type = ConcreteOne.class),
    @XmlElementRef(type = ConcreteTwo.class)
})
public AbstractBase[] getItems() { /*...*/ }

, который сработал, и возвращение этого в JBoss WebService также сработало!Хотя я использую:

@SOAPBinding(style = DOCUMENT, parameterStyle = BARE, use = LITERAL)

Так что это не добавляет атрибут xsi: type, но узлы документа правильно помечены:

<ConcreteOne>...</ConcreteOne>

В какой-то момент я изменю WebServiceиспользовать RPC, поскольку мне не очень нравится ограничение на один аргумент, но сейчас это работает нормально.

...