Маршалл JAXB и десортировка дочернего элемента без @XMLRootElement

Я пытаюсь упорядочить объект дочернего элемента, чтобы получить строку xml. И затем, используя эту строку xml, я также хотел бы Unmarshall.

Чтобы уточнить, я сгенерировал свои классы jaxb из xsd, и у меня нет никакого метода в ObjectFactory, который предоставит желаемый объект.

Определение xsd: IBUSStatusType является дочерним элементом корневого элемента IBUSMessage.

<?xml version = "1.0" encoding = "UTF-8"?>
<xsd:schema xmlns:xsd = "http://www.w3.org/2001/XMLSchema" xmlns:tns = "http://soa.myhealth.com/ibus/v1.1.0" targetNamespace = "http://soa.myhealth.com/ibus/v1.1.0" elementFormDefault = "qualified">
	<xsd:element name = "IBUSMessage" type = "tns:IBUSMessage"/>
	<xsd:complexType name = "IBUSMessage">
		<xsd:sequence>
			<xsd:element name = "Header" type = "tns:IBUSHeaderType"/>
			<xsd:element name = "Detail" type = "tns:IBUSVariantType"/>
			<xsd:element name = "Status" type = "tns:IBUSStatusType"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "IBUSHeaderType">
		<xsd:sequence>
			<xsd:element name = "Retry" type = "tns:RetryType" minOccurs = "0"/>
			<xsd:element name = "ReplyToStack" type = "tns:ReplyToStackType" minOccurs = "0" maxOccurs = "1"/>
			<xsd:element name = "TransactionContext" type = "tns:TransactionContextType"/>
			<xsd:element name = "systemType" type = "xsd:string" minOccurs = "0" maxOccurs = "1"/>
			<xsd:element name = "TestEnvironment" type = "tns:TestEnvironmentType" minOccurs = "0"/>
			<xsd:element name = "TransactionSetHeader" type = "tns:TransactionHeaderType" minOccurs = "0"/>
			<xsd:element name = "BeginningSegment" type = "tns:TransactionSegmentType" minOccurs = "0"/>
			<xsd:element name = "LegacySources" type = "tns:SourceType" minOccurs = "0"/>
			<xsd:element name = "Variables" type = "tns:IBUSVariantType" minOccurs = "0" maxOccurs = "1"/>
			<xsd:element name = "RoutingTable" type = "tns:RoutingTableType" minOccurs = "0" maxOccurs = "1"/>
			<xsd:element name = "OptionalHeaders" type = "tns:IBUSVariantType" minOccurs = "0" maxOccurs = "1"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "TestEnvironmentType">
		<xsd:sequence>
			<xsd:element name = "useStubbedService" type = "xsd:string" default = "false"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "TransactionContextType">
		<xsd:sequence>
			<xsd:element name = "source" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "actionName" type = "xsd:string"/>
			<xsd:element name = "serviceName" type = "xsd:string"/>
			<xsd:element name = "ActionClass" type = "tns:ActionClassType" minOccurs = "0"/>
			<xsd:element name = "MessageType" type = "tns:MessageResponseType" minOccurs = "0"/>
			<xsd:element name = "processDate" type = "xsd:date" minOccurs = "0"/>
			<xsd:element name = "processTime" type = "xsd:time" minOccurs = "0"/>
			<xsd:element name = "userId" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "unitOfWorkId" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "operationId" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "parentOperationId" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "uowGroupIndicator" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "uowGroupSize" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "transactionId" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "responseProtocol" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "aggregation" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "actionType" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "origSource" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "origSourceClass" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "requestIdentifier" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "generatedInterchangeControlNumber" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "generatedGroupControlNumber" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "generatedTransactionControlNumber" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "messageTimeout" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "ServiceVersion" type = "tns:VersionType" minOccurs = "0"/>
			<xsd:element name = "IBUSVersion" type = "tns:VersionType" fixed = "1.1.0"/>
		</xsd:sequence>
	</xsd:complexType>
	<!-- X12 Transactions ONLY -->
	<xsd:complexType name = "TransactionHeaderType">
		<xsd:sequence>
			<xsd:element name = "transactionSetIdentifierCode" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "transactionSetControlNumber" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "conventionReferenceNumber" type = "xsd:string" minOccurs = "0"/>
		</xsd:sequence>
	</xsd:complexType>
	<!-- X12 Transactions ONLY -->
	<xsd:complexType name = "TransactionSegmentType">
		<xsd:sequence>
			<xsd:element name = "structureCode" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "transactionIdentifier" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "transactionSetCreationDate" type = "xsd:date" minOccurs = "0"/>
			<xsd:element name = "transactionSetCreationTime" type = "xsd:time" minOccurs = "0"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "SourceType">
		<xsd:sequence maxOccurs = "unbounded">
			<xsd:element name = "name" type = "xsd:string"/>
			<xsd:element name = "action" type = "xsd:string"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "IBUSVariantType">
		<xsd:sequence>
			<xsd:any processContents = "skip" minOccurs = "0" maxOccurs = "unbounded"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "ReplyToStackType">
		<xsd:sequence>
			<xsd:element name = "ReplyTo" type = "tns:ReplyToStackEntry" minOccurs = "0" maxOccurs = "unbounded"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "ReplyToStackEntry">
		<xsd:sequence>
			<xsd:element name = "replyToQ" type = "xsd:string"/>
			<xsd:element name = "replyToQMgr" type = "xsd:string"/>
			<xsd:element name = "requestIdentifier" type = "xsd:string"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "IBUSStatusType">
		<xsd:sequence>
			<xsd:element name = "code" type = "xsd:string"/>
			<xsd:element name = "description" type = "xsd:string"/>
			<xsd:element name = "Messages" type = "tns:MessagesType" minOccurs = "0"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "MessagesType">
		<xsd:sequence>
			<xsd:element name = "Message" type = "tns:StatusMessageType" minOccurs = "0" maxOccurs = "unbounded"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "StatusMessageType">
		<xsd:sequence>
			<xsd:element name = "Reason" type = "tns:StatusPairType"/>
			<xsd:element name = "type" type = "xsd:string"/>
			<xsd:element name = "FollowUpAction" type = "tns:StatusPairType" minOccurs = "0"/>
			<xsd:element name = "Context" type = "tns:StatusPairType" minOccurs = "0"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "StatusPairType">
		<xsd:sequence>
			<xsd:element name = "description" type = "xsd:string"/>
			<xsd:element name = "code" type = "xsd:string"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:simpleType name = "ActionClassType">
		<xsd:restriction base = "xsd:string">
			<xsd:enumeration value = ""/>
			<xsd:enumeration value = "GUI"/>
			<xsd:enumeration value = "BATCH"/>
		</xsd:restriction>
	</xsd:simpleType>
	<xsd:simpleType name = "MessageResponseType">
		<xsd:restriction base = "xsd:string">
			<xsd:enumeration value = "ServiceRequest"/>
			<xsd:enumeration value = "ServiceResponse"/>
		</xsd:restriction>
	</xsd:simpleType>
	<xsd:simpleType name = "VersionType">
		<xsd:restriction base = "xsd:string">
			<xsd:pattern value = "[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}"/>
		</xsd:restriction>
	</xsd:simpleType>
	<xsd:complexType name = "RoutingTableType">
		<xsd:sequence>
			<xsd:element name = "Route" type = "tns:RouteType" minOccurs = "0" maxOccurs = "unbounded"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "RouteType">
		<xsd:sequence>
			<xsd:element name = "key" type = "xsd:string"/>
			<xsd:element name = "routeOverride" type = "xsd:string" minOccurs = "0"/>
			<xsd:element name = "routeAppend" type = "xsd:string" minOccurs = "0" maxOccurs = "unbounded"/>
		</xsd:sequence>
	</xsd:complexType>
	<xsd:complexType name = "RetryType">
		<xsd:sequence>
			<xsd:element name = "count" type = "xsd:long" minOccurs = "0"/>
			<xsd:element name = "delay" type = "xsd:long" minOccurs = "0"/>
		</xsd:sequence>
	</xsd:complexType>
</xsd:schema>

Я хочу упорядочить объект IBUSStatusType. Для этого мой код для сортировки выглядит следующим образом:

  public static StringWriter getStringFromIBUSStatusType(IBUSStatusType iBUSStatusType) throws JAXBException
  {
    StringWriter stringWriter = new StringWriter();
    JAXBContext jaxbContext = JAXBContext
        .newInstance(com.myhealth.soa.ibus.v1_1.ObjectFactory.class);
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
    marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
        new DefaultNamespacePrefixMapper());
    marshaller.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
    QName qName = new QName("com.myhealth.soa.ibus.v1_1", "iBUSStatusType");
    JAXBElement<IBUSStatusType> root = new JAXBElement<>(qName, IBUSStatusType.class, iBUSStatusType);
    marshaller.marshal(root, stringWriter);
    return stringWriter;
  }

Я получаю эту строку xml, когда я упорядочиваю объект IBUSStatusType:

<ns2:iBUSStatusType xmlns:tns = "http://soa.myhealth.com/ibus/v1.1.0" xmlns:ns2 = "com.myhealth.soa.ibus.v1_1"><tns:code>8</tns:code><tns:description>Completed With Warning</tns:description><tns:Messages><tns:Message><tns:Reason><tns:description>Subscriber's email missing</tns:description><tns:code>2187</tns:code></tns:Reason><tns:type>1</tns:type><tns:Context><tns:description>WARN</tns:description><tns:code>Policy=MissingSubscriberEmail</tns:code></tns:Context></tns:Message></tns:Messages></ns2:iBUSStatusType>

Ну, теперь я хочу Unmarshall эту строку xml, которую я получил от процесса marshal. И код для Unmarshall:

  public static com.myhealth.soa.ibus.v1_1.IBUSStatusType getIBUSStatusType(String xml)
      throws JAXBException
  {
    JAXBContext jaxbContext = JAXBContext
        .newInstance(com.myhealth.soa.ibus.v1_1.ObjectFactory.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();     
    return ((JAXBElement<IBUSStatusType>) jaxbUnmarshaller
        .unmarshal(new StringReader(xml))).getValue();
  }

Я получаю эту ошибку, когда делаю unmarshall для сгенерированной строки xml:

javax.xml.bind.UnmarshalException: unexpected element (uri:"com.myhealth.soa.ibus.v1_1", local:"iBUSStatusType"). Expected elements are <{http://soa.myhealth.com/ibus/v1.1.0}IBUSMessage>

Теперь при условии, что мои пространства имен:

put("http://soa.myhealth.com/common/v1", "cmn");
put("http://soa.myhealth.com/MemberService/v1", "mems");
put("http://soa.myhealth.com/ibus/v1.1.0", "tns");
put("http://soa.myhealth.com/member/enrollment/v1", "menr");

Не могли бы вы поделиться целым xsd с пространствами имен. Кажется, у вас есть целевое пространство имен soa.myhealth.com/ibus/v1.1.0 в IBUSStatusType, но при создании QName qName = new QName("com.myhealth.soa.ibus.v1_1", "iBUSStatusType") при маршаллинге вы используете другое (com.myhealth.soa. ibus.v1_1).

Iurii Kvashuk 01.03.2019 15:56

@lurii Я обновил пост целым xsd.

naqib83 01.03.2019 16:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
2 267
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Просто посмотрите на вашу схему

<xsd:schema xmlns:xsd = "http://www.w3.org/2001/XMLSchema" xmlns:tns = "http://soa.myhealth.com/ibus/v1.1.0" targetNamespace = "http://soa.myhealth.com/ibus/v1.1.0" elementFormDefault = "qualified">
    <xsd:element name = "IBUSMessage" type = "tns:IBUSMessage"/>
    <xsd:complexType name = "IBUSMessage">
        <xsd:sequence>
            <xsd:element name = "Header" type = "tns:IBUSHeaderType"/>
            <xsd:element name = "Detail" type = "tns:IBUSVariantType"/>
            <xsd:element name = "Status" type = "tns:IBUSStatusType"/>
        </xsd:sequence>
    </xsd:complexType>

Есть пространство имен http://soa.myhealth.com/ibus/v1.1.0 И когда вы делаете unmarsalling, он ожидает http://soa.myhealth.com/ibus/v1.1.0 но ранее, когда вы выполняете сортировку, вы помещаете следующее пространство имен

QName qName = new QName("com.myhealth.soa.ibus.v1_1", "iBUSStatusType");

Они разные.

Хорошая точка зрения. Я изменил код на QName qName = new QName("soa.myhealth.com/ibus/v1.1.0", "IBUSStatusType"); но все равно не получилось

naqib83 01.03.2019 17:54
Ответ принят как подходящий

Ну наконец-то мы нашли решение. Я вставляю свое решение ниже. Я изменил код в соответствии с @Iurii, но проблема была в другом.

Итак, это изменение в маршаллинговой части. Второй параметр QName должен быть именем класса, а НЕ его объектом. Я пытался пройти по этой ссылке https://codenotfound.com/jaxb-marshal-element-missing-xmlrootelement-annotation.html, но не получилось. При изменении второго параметра QName на имя класса это сработало. И контекст должен быть сделан из этого класса, потому что у ObjectFactory его нет.

    JAXBContext jaxbContext = JAXBContext.newInstance(IBUSStatusType.class);
    
QName qName = new QName("http://soa.independenthealth.com/ibus/v1.1.0", "IBUSStatusType");
    
JAXBElement<IBUSStatusType> root = new JAXBElement<IBUSStatusType>(qName, IBUSStatusType.class, iBUSStatusType);
    

И в этом весь код Unmarshal. Нам пришлось изменить xml на node, прежде чем его распаковать. Импорт элемента: import org.w3c.dom.Element;

  public static IBUSStatusType getIBUSStatusType(String xml)
      throws JAXBException, SAXException, IOException, ParserConfigurationException
  {
    JAXBContext jaxbContext = JAXBContext
        .newInstance(IBUSStatusType.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();    
    
    Element node =  DocumentBuilderFactory
        .newInstance()
        .newDocumentBuilder()
        .parse(new ByteArrayInputStream(xml.getBytes()))
        .getDocumentElement();
    
    return ((JAXBElement<IBUSStatusType>) jaxbUnmarshaller.unmarshal(node, IBUSStatusType.class)).getValue();
  }

Другие вопросы по теме