Springfox/Swagger ignores @XmlElement annotation for nested objects

839 Views Asked by At

I have below schema.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="sampleRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Lookup" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="accountidtgroup">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="accountIDType" type="xs:string" />
                                        <xs:element name="accountIDValue" type="xs:string" />
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                            <xs:element name="sysPlanID" type="xs:string"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="sampleResponse">
        <xs:complexType>
            <xs:sequence>
                    <xs:element name="Dummy" type="xs:string"/>
                <xs:element name="OriginalReq">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element ref="sampleRequest"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

I generate classes out of it and all works fine except that the case of "Lookup" elements gets converted to lowercase(Technically speaking, it's the object name) in Swagger UI while it should actually be "Lookup". If I just remove/comment out the "OriginalReq" element in the sampleRequest, rebuild and restart my application, the case of "Lookup" element appears fine in the request. The important thing to notice here that "OriginalReq" element is actually a reference to the "sampleRequest" element itself and this is the root cause of the issue.

Here are my pom dependencies

<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

I did some investigation and earlier versions of springfox had issues with Jaxb annotations but it was fixed in later versions. The proof of which is that "Dummy" element in response appears in correct case and if I manually change it to something else in @XmlElement annotation, I can see the updated value which means that the annotation was honored but for Lookup element it doesn't work. So the issue is only in case of nested element having common element.

Has anyone run into similar issue before or if there is a workaround?

1

There are 1 best solutions below

0
On BEST ANSWER

Figured out a workaround for anyone who is in a similar situation.

The resolution is to add @JsonProperty annotation to the elements which have issue. And that's it. Swagger will recognize the annotation and display correct element case/name.

For those who are generating the classes from an xsd schema, there are a few more steps involved.

  1. Add below dependencies into your pom.xml dependencies section.
         <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.6</version>
        </dependency>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-basics-annotate</artifactId>
            <version>1.1.0</version>
        </dependency>
  1. Under the section where you configure the maven plugin for generating the classes, inside execution configuration you have to add the above two dependencies again and "-Xannotate" argument. It will look something like this.
<build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <schemaDirectory>${schema.src.dir}/abc</schemaDirectory>
                            <schemaIncludes>
                                <include>*.xsd</include>
                            </schemaIncludes>
                            <generatePackage>${generated.package.abc}</generatePackage>
                            <generateDirectory>${generated.dir}/abc</generateDirectory>
                            <cleanPackageDirectories>true</cleanPackageDirectories>
                            <bindings>
                                <binding>
                                    <fileset>
                                        <directory>${schema.binding.dir}/abc</directory>
                                        <includes>
                                            <include>bindings.xjb</include>
                                        </includes>
                                    </fileset>
                                </binding>
                            </bindings>
                            <extension>true</extension>
                            <args>
                                <arg>-Xannotate</arg>
                            </args>
                            <plugins>
                                <plugin>
                                    <groupId>org.jvnet.jaxb2_commons</groupId>
                                    <artifactId>jaxb2-basics</artifactId>
                                    <version>1.11.1</version>
                                </plugin>
                                <plugin>
                                    <groupId>org.jvnet.jaxb2_commons</groupId>
                                    <artifactId>jaxb2-basics-annotate</artifactId>
                                    <version>1.1.0</version>
                                </plugin>
                                <plugin>
                                    <groupId>com.fasterxml.jackson.core</groupId>
                                    <artifactId>jackson-annotations</artifactId>
                                    <version>2.8.6</version>
                                </plugin>
                            </plugins>
                        </configuration>
                    </execution>

Take a look at the arguments section and the plugin section below that.

  1. Now in your bindings file, you can use this plugin and configure conflicting elements like below.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE jaxb:bindings SYSTEM "../common/resources.dtd">
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:annox="http://annox.dev.java.net"
        jaxb:extensionBindingPrefixes="annox">

 <jaxb:bindings schemaLocation="&ApiPath;/schema.xsd">
  <jaxb:bindings node="//xs:element[@name='Lookup']">
                <annox:annotate target="field">@com.fasterxml.jackson.annotation.JsonProperty("Lookup")</annox:annotate>
           </jaxb:bindings>

Pay close attention to the namespace "annox" configured at the top.

Now if you run generate-resources, it would create @JsonProperty("your element name") on top of your member variable and swagger will work just fine.

If you want to read more about plugin https://github.com/highsource/jaxb2-annotate-plugin. It's a very widely used great open source. For Springfox, I tried testing with version 2.9.0 and 3.0.0 and it's still the same issue. At the time of me writing this, I think it's a bug in springfox library and I have raised this on Github but haven't gotten a response back yet. Here's the link https://github.com/springfox/springfox/issues/3605