(обратите внимание; я совершенно новичок в веб-сервисах, поэтому следующее может быть глупым / неправильным, но, пожалуйста, будьте терпеливы)
В моем @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, поскольку мне не очень нравится ограничение на один аргумент, но сейчас это работает нормально.