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.