如何从 XSD 模式生成 JAXB 数据格式?

How to generate JAXB data format from XSD schema?

当我尝试使用 JAXB 并提供 XSD 模式编组从 Apache Camel 中的数据库获取的数据时,出现错误

java.io.org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: java.util.LinkedHashMap to the required type: java.io.InputStream with value {id=5, number=5599, type=B3, ... }

当我尝试将消息发送到 ActiveMQ 时。我是集成新手,这是我的实习骆驼项目。当我将消息编组到 json 时,一切正常。我考虑过将消息转换为 json,然后再转换为 XML,但在我看来这不是我应该做的。我已经准备好 XSD 架构,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns:pc="com.release11.packages"
       targetNamespace="com.release11.materials">
<xs:import schemaLocation="packages.xsd"
           namespace="com.release11.packages"/>

<xs:simpleType name="materialTypeType">
    <xs:restriction base="xs:string">
        <xs:enumeration value="A1"/>
        <xs:enumeration value="A2"/>
        <xs:enumeration value="A3"/>
        <xs:enumeration value="B1"/>
        <xs:enumeration value="B2"/>
        <xs:enumeration value="B3"/>
        <xs:enumeration value="C1"/>
        <xs:enumeration value="C2"/>
        <xs:enumeration value="C3"/>
    </xs:restriction>
</xs:simpleType>

<xs:complexType name="materialType">
    <xs:sequence>
        <xs:element name="Id" type="xs:integer"/>
        <xs:element name="Number" type="xs:integer"/>
        <xs:element name="Type" type="materialTypeType"/>
        <xs:element name="Name" type="xs:string"/>
        <xs:element name="Description" type="xs:string"/>
        <xs:element name="Is_deleted" type="xs:boolean"/>
        <xs:element ref="pc:Packages" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="materialsType">
    <xs:sequence>
        <xs:element name="Material" type="materialType" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

<xs:element name="Materials" type="materialsType"/>

</xs:schema>

我试图在网上找到答案,但没有找到任何有用的答案,或者我无法理解答案,所以我需要有人向我解释一下。请帮助我。

这是我的代码:

public class InputAdapter {

public static void main(String[] args) throws Exception {

    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/Packages");
    dataSource.setUsername("uname");
    dataSource.setPassword("passwd");
    SimpleRegistry registry = new SimpleRegistry();
    registry.bind("dataSource", dataSource);

    ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL("tcp://127.0.0.1:61616");

    Connection connection = activeMQConnectionFactory.createConnection();
    connection.start();

    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    Destination destination = session.createQueue("MESSAGES_RAW");

    MessageProducer producer = session.createProducer(destination);
    producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

    CamelContext context = new DefaultCamelContext(registry);
    context.addComponent("activemq", JmsComponent.jmsComponentAutoAcknowledge(activeMQConnectionFactory));

    context.addRoutes(new RouteBuilder() {
        @Override
        public void configure() {
            JaxbDataFormat dataFormat = new JaxbDataFormat();
            dataFormat.setSchemaLocation("material.xsd");

            from("timer://foo?repeatCount=1")
                    .setBody(constant("SELECT * FROM material;"))
                    .to("jdbc:dataSource")
                    .split(body())
                    .marshal(dataFormat)
                    .to("activemq:queue:MESSAGES_RAW");
        }
    });
    context.start();
    Thread.sleep(1000);
    context.stop();
}
}

使用 CLI 工具从 XSD 生成 classes

你可以使用 pre-installed 附带的 xjc command-line 工具 JDK 8 来生成 jaxb classes.

示例:

xjc material.xsd

# With groupId
xjc -p <groupId> material.xsd

# With groupId and bindings configuration file
xjc -p <groupId> -b bindings.xjb material.xsd

使用 Maven 插件从 XSD 生成 classes

或者你可以使用 maven 插件来做同样的事情。默认情况下,插件将从 src/main/xsd 中查找模式 xsd 文件,并从 src/main/xjb

中查找绑定 xjb 文件
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxb2-maven-plugin</artifactId>
            <version>2.5.0</version>
            <executions>
                <execution>
                    <id>xjc</id>
                    <goals>
                        <goal>xjc</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <packageName>com.example.group</packageName>
            </configuration>
        </plugin>
    </plugins>
</build>

如果您使用的是 JDK 11 或更高版本,您还必须包含一些不再包含在 JDK.

中的相关依赖项
<dependencies>
    <dependency>
        <groupId>jakarta.xml.bind</groupId>
        <artifactId>jakarta.xml.bind-api</artifactId>
        <version>2.3.3</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-xjc</artifactId>
        <version>2.3.6</version>
    </dependency>
</dependencies>

使用这些 Maven 应该在 运行 mvn clean install 之后生成 classes 到 target/generated-sources/jaxb 文件夹。使用 Maven 插件,您最好为这些创建单独的 api-project 并将其添加为您的骆驼集成项目的依赖项。

骆驼中的用法

您可以通过使用 JAXBContext 实例创建 JaxbDataFormat 来将 jaxb 与 camel 一起使用。

JAXBContext jaxbContext = JAXBContext.newInstance(Materials.class);
JaxbDataFormat jaxbDataformat = new JaxbDataFormat(jaxbContext);

from("direct:marshalMaterials")
    .routeId("marshalMaterials")
    .marshal(jaxbDataformat)
    .log("${body}");

由于您要查询的数据库默认为 returns 地图列表,因此您必须将其转换为适当的 Jaxb 对象。您可以使用 generated ObjectFactory class 来生成不同的 jaxb class 实例。

对于 JDK 11,您可能还需要以下依赖项

<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>2.3.3</version>
</dependency>

<!-- versions obtained from dependency-management camel-bom -->
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
</dependency>

命名空间从 javax 更改为 jakarta

较新版本的 jaxb 使用 jakarta 命名空间而不是 javax 但是在撰写本文时使用 jakarta 命名空间有点问题,因为 jaxb2-maven-plugin 3.0.0+ 版本在 Maven 中央存储库中尚不可用,虽然有一些替代方案,但它们仍在进行中。

如果 xsd 不经常更改,则可能只生成 classes 并手动将命名空间更改为 jakarta。

绑定 XJB 文件

通过绑定 xjb 文件,您可以调整 classes 的生成方式,例如更改 class 或 属性 名称,防止嵌套 class 混乱等

示例:空绑定文件模板

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    version="2.1" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd">

    ...

</jaxb:bindings>