I try to get hands on expirience with jaxb library to parse xml. Here is my code:
JmsConfig.class
@Configuration
public class JmsConfig {
@Value("${context.path}")
String contextPath;
@Value("${schema.location}")
FileSystemResource schema;
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(marshallingMessageConverter());
return factory;
}
@Bean
public MessageConverter marshallingMessageConverter() {
MarshallingMessageConverter marshallingMessageConverter = new MarshallingMessageConverter();
marshallingMessageConverter.setMarshaller(jaxb2Marshaller());
marshallingMessageConverter.setUnmarshaller(jaxb2Unmarshaller());
return marshallingMessageConverter;
}
@Bean
public Marshaller jaxb2Marshaller() {
return getJaxb2Marshaller();
}
@Bean
public Unmarshaller jaxb2Unmarshaller() {
return getJaxb2Marshaller();
}
private Jaxb2Marshaller getJaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath(contextPath);
jaxb2Marshaller.setSchema(schema);
jaxb2Marshaller.setMarshallerProperties(of(JAXB_FORMATTED_OUTPUT, true));
return jaxb2Marshaller;
}
}
JmsApplication
@SpringBootApplication
public class JmsApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(JmsApplication.class, args);
}
@Autowired
private JmsTemplate jmsTemplate;
@Value("${outbound.endpoint}")
private String destination;
@Override
public void run(String... args) throws Exception {
ObjectFactory of = new ObjectFactory();
ProductDto productDto = of.createProductDto();
productDto.setProductId(UUID.randomUUID().toString());
productDto.setProductName("Cool product");
JAXB.marshal(productDto, System.out);
jmsTemplate.convertAndSend(destination, productDto);
}
}
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/>
</parent>
<groupId>com.mikhail</groupId>
<artifactId>JMS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>JMS</name>
<description>JMS</description>
<properties>
<java.version>11</java.version>
<maven-jaxb2-plugin.version>0.15.1</maven-jaxb2-plugin.version>
<xml-bind-api.version>4.0.0</xml-bind-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.4.0-b180830.0359</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>${xml-bind-api.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>schemagen</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<packageName>xjc.generated</packageName>
<outputDirectory>${basedir}/target/generated-sources/xjc</outputDirectory>
<sources>${basedir}/src/main/resources/xsd</sources>
<xjbSources>
<xjbSource>${basedir}/src/main/resources/xjb/default.xjb</xjbSource>
</xjbSources>
</configuration>
</plugin>
</plugins>
</build>
So, the issue! When I try to send through JmsTemplate generated ProductDto object in xml format, Jaxb2Marshaller throws an error:
Caused by: javax.xml.bind.JAXBException: class xjc.generated.ProductDto nor any of its super class is known to this context. at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:572) ~[jaxb-runtime-2.3.6.jar:2.3.6] at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:452) ~[jaxb-runtime-2.3.6.jar:2.3.6] at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:298) ~[jaxb-runtime-2.3.6.jar:2.3.6] at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:226) ~[jaxb-runtime-2.3.6.jar:2.3.6] at org.springframework.oxm.jaxb.Jaxb2Marshaller.marshal(Jaxb2Marshaller.java:709) ~[spring-oxm-5.3.23.jar:5.3.23]
But if I use JAXB.marshal() I get the correct output in my console:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<productDto productId="1eb48960-0a60-42c1-98fd-0459451e0600">
<productName>Cool product</productName>
</productDto
So here is the generated class:
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element ref="{}productName"/>
* </sequence>
* <attribute ref="{}productId use="required""/>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"productName"
})
@XmlRootElement(name = "productDto")
public class ProductDto
implements Serializable
{
private final static long serialVersionUID = 1L;
@XmlElement(required = true)
protected String productName;
@XmlAttribute(name = "productId", required = true)
protected String productId;
/**
* Gets the value of the productName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getProductName() {
return productName;
}
/**
* Sets the value of the productName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setProductName(String value) {
this.productName = value;
}
/**
* Gets the value of the productId property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getProductId() {
return productId;
}
/**
* Sets the value of the productId property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setProductId(String value) {
this.productId = value;
}
}
I will be gratefull for any ideas!
