Swagger Java annotations for XML: (a) lists (b) namespaces (c) enums

1,556 views
Skip to first unread message

Richard Walker

unread,
Feb 14, 2017, 8:11:39 PM2/14/17
to Swagger
Just getting started with using Swagger-Core Annotations on some JAX-RS services (using Jersey implementation).

Using the JerseyJaxrsConfig servlet to generate swagger.json. Using swagger-ui to see a "pretty" version of the annotations. (Using sample ApiOriginFilter to solve CORS issues.)

Pretty happy so far, but wondering how to tweak things in a few cases.

First, my setup:

I have this class/service:

/** REST web services for getting vocabularies. */
@Path("/api/resource")
@Api
public class GetVocabularies {

    /** Get all the current vocabularies.
     * @return The list of vocabularies, in either XML or JSON format. */
    @Path("vocabulary")
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @GET
    @ApiOperation(value = "Get all the current vocabularies.")
    public final List<Vocabulary> getVocabularies() { ... }

...
}

The Vocabulary class is generated using xjc from an XML Schema. So it has many JAXB annotations: @XmlRootElement , @XmlType, and @XmlAccessorType on the class, and @XmlElement/@XmlAttribute on the fields.

There is also a package-info.java file generated, which contains this:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://vocabs.ands.org.au/registry/schema/2017/01/vocabulary", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package au.org.ands.vocabs.registry.schema.vocabulary201701;

So ... that all generates the following fragments in swagger.json:

       "/api/resource/vocabulary" : {
          "get" : {
             "operationId" : "getVocabularies",
             "parameters" : [],
             "responses" : {
                "200" : {
                   "description" : "successful operation",
                   "schema" : {
                      "items" : {
                         "$ref" : "#/definitions/Vocabulary"
                      },
                     "type" : "array"
                   }
                }
             },
             "summary" : "Get all the current vocabularies.",
             "produces" : [
                "application/xml",
                "application/json"
             ],
             "description" : ""
          }
       },



and:

      "Vocabulary" : {
         "properties" : {
            "title" : {
               "xml" : {
                  "attribute" : true
               },
               "type" : "string"
            },
...
         "xml" : {
            "name" : "vocabulary"
         },
...
         "type" : "object"
    }

Now to my "issues", which are related to how swagger-ui presents the "Example Value" for XML.

Issue #1: XML wrapper element for the List<...>.

The "Example Value" looks like this:

<?xml version="1.0"?>
<vocabulary id="1" status="PUBLISHED" owner="string" slug="string" title="string" acronym="string" description="string" note="string" revision-cycle="string" creation-date="string" primary-language="string" licence="string">
...

But in fact what comes back from the service is (some content replaced with "..." where it's not relevant):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<vocabularies>
  <vocabulary xmlns="http://vocabs.ands.org.au/registry/schema/2017/01/vocabulary" id="1" status="published" owner="..." slug="..." title="..." acronym="..." description="..." revision-cycle="..." creation-date="..." primary-language="en" licence="CC-BY">
...

So there is a JAXB-generated "wrapper" element <vocabularies> around the list. (For lists like this, JAXB automatically generates a plural form of the XML element name during serialization. In this case, the generated plural form is correct ....)

I can get that to appear in swagger-ui's "Example Value" by saving the generated swagger.json and then editing it to add "xml" data so that it says:

      "/api/resource/vocabulary" : {
         "get" : {
            "operationId" : "getVocabularies",
            "parameters" : [],
            "responses" : {
               "200" : {
                  "description" : "successful operation",
                  "schema" : {
                     "items" : {
                        "$ref" : "#/definitions/Vocabulary"
                     },
                     "type" : "array",
                     "xml": {
                        "wrapped" : true,
                        "name" : "vocabularies"
                     }
                  }
               }
            },
            "summary" : "Get all the current vocabularies.",
            "produces" : [
               "application/xml",
               "application/json"
            ],
            "description" : ""
         }
      },

Issue #2: XML namespace for the Vocabulary.

The Example Value doesn't include the XML namespace for the Vocabulary element. It seems the @XmlSchema annotation in package-info.java is not taken into account.

Again, I can fix that thus in my modified swagger.json:

      "Vocabulary" : {
         "type" : "object",
         "xml" : {
            "name" : "vocabulary",
            "namespace" : "http://vocabs.ands.org.au/registry/schema/2017/01/vocabulary"
         },
         ...
   }

After making both modifications, the Example Value in swagger-ui now looks like this:


<?xml version="1.0"?>
<vocabularies>
  <vocabulary xmlns="http://vocabs.ands.org.au/registry/schema/2017/01/vocabulary" acronym="string" slug="string" note="string" status="PUBLISHED" creation-date="string" revision-cycle="string" title="string" primary-language="string" id="1" owner="string" licence="string" description="string">
    <top-concept>string</top-concept>
...

and this is correct.

Issue #3: values of enumerated types.

Well, not quite correct. I just noticed that the values of enumerated types are wrong. As you see, the correct values of the "status" attribute are in lowercase, and the Example Value gives an uppercase value. I could edit the values in the "enum" section of swagger.json to fix that. But the correct values are already in the generated enum class as annotations, e.g., @XmlEnumValue("published"). It seems they are not being used. (Note: for JSON, the service (via Jackson) returns the values in uppercase, so the JSON Example Value is correct! Confusing, slightly annoying, and something I may want to do something about!)

So my question: can I add more/modify existing Swagger-Core Annotations or otherwise modify my code so that the "correct" swagger.json is produced in the first place?

Richard.
--
Richard Walker
Australian National Data Service (ANDS)
101 Liversidge Street
The Australian National University
Acton ACT 2601, Australia
E: Richard...@ands.org.au
T: +61 2 6125 0584
W: www.ands.org.au

Richard Walker

unread,
Feb 14, 2017, 9:01:38 PM2/14/17
to Swagger
On Wednesday, February 15, 2017 at 12:11:39 PM UTC+11, Richard Walker wrote:
Issue #3: values of enumerated types.

(Note: for JSON, the service (via Jackson) returns the values in uppercase, so the JSON Example Value is correct! Confusing, slightly annoying, and something I may want to do something about!)

After a bit more experimenting, I was able to get the service itself to output JSON with the enum values in lowercase by overriding the default JSON serialization with my own ObjectMapper that has JaxbAnnotationModule applied. Now that only leaves what Swagger is doing.

I tried the same "trick" as per the example at:

https://github.com/swagger-api/swagger-core/issues/960#issuecomment-173330606

The enum values in the generated swagger.json are still in uppercase.

However, there was _another_ effect: some _but not all_ of the object definitions now begin with lowercase. E.g.:

      "vocabulary" : {
         "required" : [
            "related-entity"
         ],
         "xml" : {
            "name" : "vocabulary"
         },
         "type" : "object",
      ...

but:

      "Subject" : {
         "properties" : {
            "source" : {

               "xml" : {
                  "attribute" : true
               },
               "type" : "string"
            },
      ...

The Subject class is defined/generated by xjc as Vocabulary.Subject, i.e. it's a static nested class.

calde...@yahoo.com

unread,
Feb 15, 2017, 3:53:34 AM2/15/17
to swagger-sw...@googlegroups.com

--------------------------------------------
On Wed, 2/15/17, Richard Walker <richard.w...@gmail.com> wrote:

Subject: Re: Swagger Java annotations for XML: (a) lists (b) namespaces (c) enums
To: "Swagger" <swagger-sw...@googlegroups.com>
Date: Wednesday, February 15, 2017, 4:01 AM
--

You received this message because you are subscribed to the
Google Groups "Swagger" group.

To unsubscribe from this group and stop receiving emails
from it, send an email to swagger-swaggers...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
u toate imperfectiunile care rezultau din politica de forta si dictat tratatele semnate cu tara noastra in anii 1919-1920 au reprezentat recunoasterea internationala a statului unitar roman oferindu-i teoretic si garantiile necesare pentru mentinerea si consolidarea sa.

Richard Walker

unread,
Feb 15, 2017, 5:25:25 PM2/15/17
to Swagger
On Wednesday, February 15, 2017 at 12:11:39 PM UTC+11, Richard Walker wrote:
Issue #3: values of enumerated types.

Well, not quite correct. I just noticed that the values of enumerated types are wrong. As you see, the correct values of the "status" attribute are in lowercase, and the Example Value gives an uppercase value. I could edit the values in the "enum" section of swagger.json to fix that. But the correct values are already in the generated enum class as annotations, e.g., @XmlEnumValue("published"). It seems they are not being used.

I see now that this particular issue has already been reported:
https://github.com/swagger-api/swagger-core/issues/2092

Richard Walker

unread,
Mar 26, 2017, 8:05:28 PM3/26/17
to Swagger
On Wednesday, February 15, 2017 at 12:11:39 PM UTC+11, Richard Walker wrote:
Just getting started with using Swagger-Core Annotations on some JAX-RS services (using Jersey implementation).

Using the JerseyJaxrsConfig servlet to generate swagger.json. Using swagger-ui to see a "pretty" version of the annotations. (Using sample ApiOriginFilter to solve CORS issues.)

Pretty happy so far, but wondering how to tweak things in a few cases.

First, my setup:

<snip>
 
The Vocabulary class is generated using xjc from an XML Schema. So it has many JAXB annotations: @XmlRootElement , @XmlType, and @XmlAccessorType on the class, and @XmlElement/@XmlAttribute on the fields.

There is also a package-info.java file generated, which contains this:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://vocabs.ands.org.au/registry/schema/2017/01/vocabulary", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package au.org.ands.vocabs.registry.schema.vocabulary201701;

<snip>
 
Now to my "issues", which are related to how swagger-ui presents the "Example Value" for XML.

<snip>

Issue #2: XML namespace for the Vocabulary.

The Example Value doesn't include the XML namespace for the Vocabulary element. It seems the @XmlSchema annotation in package-info.java is not taken into account.

I think I need to file a GitHub issue for this.
But I have found a workaround that may be good enough for me: add the "-npa" command-line
option to the xjc command. Then, namespace properties are added at the class level, and
swagger-core then correctly adds them to the generated swagger.json.

The side effect of the -npa option is that package-info.java is no longer generated _at all_,
so I have to make one by hand. Not a big problem.

Reply all
Reply to author
Forward
0 new messages