javajaxbspring-oxm

Jaxb2Marshaller subclasses scanning


I'm using maven-jaxb2-plugin to generate Java classes according to a WSDL. Generated Java classes are under package com.myapp.generated and for example, there is Jaxb2 generated class com.myapp.generated.SomeRequest:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "someRequestType"
})
@XmlRootElement(name = "someRequest")
public class SomeRequest
{
// generated code
}

which I'm extending then I have it in a different package:

package com.myapp.extended.someRequest;
class SomeRequestExtended extends com.myapp.generated.SomeRequest {
 // additional code
}

Then using Spring Boot (v2.2.9) / spring-oxm (v5.2.8) I specify Bean for Jaxb2Marshaller to scan that package:

@Bean
public Jaxb2Marshaller marshaller() {
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setPackagesToScan("com.myapp.extended.*");
    return marshaller;
}

During runtime, unfortunately, there is a problem it doesn't find it:

class package com.myapp.extended.someRequest.SomeRequestExtended; nor any of its super class is known to this context.
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:567) ~[na:1.8.0_201]
...

Does anyone know what is the reason, and how to make it scan specified packages to find the SomeRequestExtended class?


Solution

  • The reason is that the required XmlRootElement on JAXB classes is not inherited in subclasses because interface XmlRootElement doesn't have @Inherited annotation:

    package javax.xml.bind.annotation;
    
    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
    @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
    public @interface XmlRootElement {
        java.lang.String namespace() default "##default";
    
        java.lang.String name() default "##default";
    }
    

    To solve the issue, you can manually add/copy it from parent class to subclass:

    package com.myapp.extended.someRequest;
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "someRequestType"
    })
    @XmlRootElement(name = "someRequest")
    class SomeRequestExtended extends com.myapp.generated.SomeRequest {
     // additional code
    }
    

    Also make sure, that the @XmlAccessorType(XmlAccessType.FIELD) and @XmlType are still valid in subclass - in my example, the field should be visible, or you can change the definition to getter method using XmlAccessType.PUBLIC_MEMBER

    HINT: Additionally, if there is, and usually is, a file package-info.java generated by JAXB, then it should also be copied to a new package, like in my example to: package com.myapp.extended.someRequest; If not there might be problems when resolving classes by marshaller!