Hi all.

I stumbled about a couple issues with using Swagger.io together with Jersey 
1.x and 2.x.

The issues can be seen using he following resource methods and the used 
model classes:
  @ApiOperation(value="Return List<Item>",
                notes="Let Jersey/JAXB do the element wrapping")
  @GET
  @Path("list")
  @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
  public List<Item> getModels() {
    return Arrays.asList(new Item("1", "foo"), new Item("2", "bar"));
  }


  @ApiOperation(value="Return Items, which contains List<Item>",
                notes="JAXB annotations are used so that the result is 
semantical equivalent to List<Iterm> been returned")
  @GET
  @Path("items")
  @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
  public Items getItems() {
    return new Items(Arrays.asList(new Item("1", "foo"), new Item("2", "bar"
)));
  }

@XmlRootElement(namespace="io.swagger.bug-test")
@XmlAccessorType(XmlAccessType.NONE)
public final class Item extends Object {
 @XmlAttribute(required=true)
 @XmlSchemaType(name="ID")
 private String id;


 @XmlElement(required=true)
 private String value;
...
}

@XmlRootElement(name="items")

@XmlAccessorType(XmlAccessType.NONE)
public final class Items extends Object {
 @XmlElement(namespace="io.swagger.bug-test")
 private List<Item> item;
...
}



If we now request the swagger.yaml file for this REST API, we get this:
swagger: "2.0"

paths:
  /list:
    get:
      summary: "Return List<Item>"
      description: "Let Jersey/JAXB do the element wrapping"
      operationId: "getModels"
      produces:
      - "application/json"
      - "application/xml"
      parameters: []
      responses:
        200:
          description: "successful operation"
          schema:
            type: "array"
            items:
              $ref: "#/definitions/Item"
  /items:
    get:
      summary: "Return Items, which contains List<Item>"
      description: "JAXB annotations are used so that the result is 
semantical equivalent\
        \ to List<Iterm> been returned"
      operationId: "getItems"
      produces:
      - "application/json"
      - "application/xml"
      parameters: []
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/Items"
definitions:
  Item:
    type: "object"
    required:
    - "value"
    properties:
      value:
        type: "string"
  Items:
    type: "object"
    properties:
      item:
        type: "array"
        xml:
          namespace: "io.swagger.bug-test"
        items:
          $ref: "#/definitions/Item"
    xml:
      name: "items"


Using Swagger-UI 2.2.x or 3.0.x produces equivalent JSON examples matching 
the actual server output.

Using Swagger-UI 2.2.x for the XML example produces incorrect examples:
GET /list


<?xml version="1.0"?>
<Inline Model>
  <value>string</value>
</Inline Model>


GET /items


<?xml version="1.0"?>
<items xmlns="io.swagger.bug-test">
  <item>
    <value>string</value>
  </item>
</items>


You can see that the "/list" case is producing totally corrupted XML, which 
has nearly nothing to do with the real one.
While the "/items" case is much better already, is it incorrect with 
respect to namespaces and lacks the id attribute of <item>.

Expected would have been:
GET /list



<?xml version="1.0" encoding="UTF-8"?>
<items>
  <ns:item xmlns:ns="io.swagger.bug-test" id="string">
    <value>string</value>
  </ns:item>
</items>




GET /items


<?xml version="1.0" encoding="UTF-8"?>
<items>
  <ns:item xmlns:ns="io.swagger.bug-test" id="string">
    <value>string</value>
  </ns:item>
</items>


The <items> and <value> elements have no namespace defined and so reside in 
the default empty namespace.  Just the <item> element belongs to the 
specified namespace {io.swagger.bug-test}.

As the Swagger-UI 3.x does not honor "xml" within the "items" section, I 
have moved it into the item definition itself as then 2.x and 3.x will use 
it.  This manual produces YAML produces the correct XML examples if we 
assume that the default namespace just applies to the XML element that 
defines it and to none of its children in contrast to normal XML:
swagger: "2.0"

paths:
  /list:
    get:
      summary: "Return List<Item>"
      description: "Let Jersey/JAXB do the element wrapping"
      operationId: "getModels"
      produces:
      - "application/json"
      - "application/xml"
      parameters: []
      responses:
        200:
          description: "successful operation"
          schema:
            type: "array"
            xml:
              wrapped: "true"
              name: "items"
            items:
              $ref: "#/definitions/Item"
  /items:
    get:
      summary: "Return Items, which contains List<Item>"
      description: "JAXB annotations are used so that the result is 
semantical equivalent\
        \ to List<Iterm> been returned"
      operationId: "getItems"
      produces:
      - "application/json"
      - "application/xml"
      parameters: []
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/Items"
definitions:
  Item:
    type: "object"
    required:
    - "value"
    properties:
      id:
        type: "string"
        xml:
          attribute: "true"
      value:
        type: "string"
    xml:
      name: "item"
      namespace: "io.swagger.bug-test"
  Items:
    type: "object"
    properties:
      item:
        type: "array"
        items:
          $ref: "#/definitions/Item"
    xml:
      name: "items"


With the above YAML specification the 2.x and 3.x Swagger UIs produce the 
following XML examples for both methods, which is much closer to the actual 
XML received:
<?xml version="1.0" encoding="UTF-8"?>

<items>
  <item xmlns="io.swagger.bug-test" id="string">
    <value>string</value>
  </item>
</items>


As reference the actual Jersey output is:
GET /list

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<items>
  <ns2:item xmlns:ns2="io.swagger.bug-test" id="1">
    <value>foo</value>
  </ns2:item>
  <ns2:item xmlns:ns2="io.swagger.bug-test" id="2">
    <value>bar</value>
  </ns2:item>
</items>



GET /items

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<items xmlns:ns2="io.swagger.bug-test">
  <ns2:item id="1">
    <value>foo</value>
  </ns2:item>
  <ns2:item id="2">
    <value>bar</value>
  </ns2:item>
</items>


As the issue also applies if the Jersey 1.x framework is been used and is 
independent of the Swagger UI version been used, would I think that the 
issue resides in the swagger-core and swagger-jaxrs packages.

The io.swagger.converter.ModelConverters.readAsProperty(Type) is been 
invoked for the response types, but has not means to pass this information 
to the MovelConverter.resolveProperty method, so that the 
io.swagger.jackson.ModelConverter can not add the "wrapped" flag.

Note also that if the name parameter to the @XmlRootElement of the Items 
class is left out, that the incorrect "Items" name is used instead by 
Swagger.

Also the @XmlAttribute annotations do not seem to be honoured.

And if no namespace is defined within any @XmlElement or @XmlRootElement, 
the one from the @XmlSchema is been used if any, otherwise the empty string 
is been used.  This is not correctly implemented by the Swagger side 
either, as well as if the namespace is explicitly set to an empty string 
with the @XmlSchema defined as package level.

So in summary:
- @XmlAttribute is not used by swagger-core
- namespace="" is not applied correctly if @XmlSchema is used at 
package-level
- @ApiOperation which return some collection, like List<Object>, lack "xml: 
{wrapped:true}" and the correct XML name for the wrapper
  This seems to be covered already by 
https://github.com/swager-api/swagger-core/issues/2334

  Regards,
    Michael

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to