Swagger-core: How to add a ModelConverter in a Spring project ?

Created on 29 Oct 2015  路  4Comments  路  Source: swagger-api/swagger-core

I have a project with Spring MVC and Spring boot.
I use Swagger springfox to document my json service. I have a class with java.sql.Time and java.util.Date attributes.
When I call the api, the class appears like this :

"TranslationLabel":{
    "properties":{
        "change_date":{
            "type":"string",
            "format":"date-time"
        },
        "change_time":{
            "$ref":"#/definitions/Time"
        }
    },
    "description":"Traduction de libell茅"
}

In swagger UI, the Model Schema is like this :

 {
  "change_date": "2015-10-29",
  "change_time": {
    "date": 0,
    "day": 0,
    "hours": 0,
    "minutes": 0,
    "month": 0,
    "seconds": 0,
    "time": 0,
    "timezoneOffset": 0,
    "year": 0
  }
}

I want to display the "change_time" like "15:31".
To do this, I think I need to use a ModelConverter. So I create a custom converter class based on this example : https://github.com/swagger-api/swagger-core/blob/master/modules/swagger-core/src/test/java/io/swagger/model/override/CustomConverterTest.java
But I don't find how to use it.

Here is my class :

class CustomConverter implements ModelConverter {
    @Override
    public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations,
                                    Iterator<ModelConverter> chain) {
        final JavaType jType = Json.mapper().constructType(type);
        if (jType != null) {
            final Class<?> cls = jType.getRawClass();
            if (cls.equals(Time.class)) {
                HashMap<PropertyBuilder.PropertyId, Object> map =
                        new HashMap<>();
                map.put(PropertyBuilder.PropertyId.FORMAT,"HH:mm");
                map.put(PropertyBuilder.PropertyId.TYPE,"time");
                map.put(PropertyBuilder.PropertyId.EXAMPLE,"12:30");
                return PropertyBuilder.build("Time", "hh:mm", map);
            } else {
                return chain.next().resolveProperty(type, context, annotations, chain);
            }
        } else {
            return null;
        }
    }

    @Override
    public Model resolve(Type type, ModelConverterContext context, Iterator<ModelConverter> chain) {
        return chain.next().resolve(type, context, chain);
    }
}

Now I need to add my converter to the ModelConverters.

ModelConverters converters = new ModelConverters();
converters.addConverter(new CustomConverter());

I did not find any documentation about where to put this code.
Where did I need to put this ?

Support

Most helpful comment

Springfox has a different way of acheiving this. You need to use the Docket.directmodelSubstitute(Time.class, String.class) to define an equivalent converter. However it doesn't support examples etc.

All 4 comments

Springfox has a different way of acheiving this. You need to use the Docket.directmodelSubstitute(Time.class, String.class) to define an equivalent converter. However it doesn't support examples etc.

Thanks for your answer.
I try your solution but with this, it display "change_time":"string" instead of "change_time":"hh:mm".
Is it possible to specify a format for the String ?

Hi Guys,

I am having a problem related to ModelConverters. My Swagger.json contains a generic class in the expanded form like below:

"JsonNode": {
"type": "object",
"properties": {
"floatingPointNumber": {
"type": "boolean",
"default": false
},
"valueNode": {
"type": "boolean",
"default": false
},
"bigInteger": {
"type": "boolean",
"default": false
},
"textual": {
"type": "boolean",
"default": false
},
"boolean": {
"type": "boolean",
"default": false
},
"containerNode": {
"type": "boolean",
"default": false
},
"missingNode": {
"type": "boolean",
"default": false
},
"object": {
"type": "boolean",
"default": false
},
"pojo": {
"type": "boolean",
"default": false
},
"number": {
"type": "boolean",
"default": false
},
"integralNumber": {
"type": "boolean",
"default": false
},
"short": {
"type": "boolean",
"default": false
},
"int": {
"type": "boolean",
"default": false
},
"long": {
"type": "boolean",
"default": false
},
"double": {
"type": "boolean",
"default": false
},
"bigDecimal": {
"type": "boolean",
"default": false
},
"float": {
"type": "boolean",
"default": false
},
"nodeType": {
"type": "string",
"enum": [
"ARRAY",
"BINARY",
"BOOLEAN",
"MISSING",
"NULL",
"NUMBER",
"OBJECT",
"POJO",
"STRING"
]
},
"binary": {
"type": "boolean",
"default": false
},
"array": {
"type": "boolean",
"default": false
},
"null": {
"type": "boolean",
"default": false
}
}
}

Now this is definitely what I don't want. In fact what I want is to prevent this specific class (com.fasterxml.jackson.databind.JsonNode) (and any other of my choice) to be ever expanded. So in order to do this I used the inbuilt function provided in the io.swagger.converter.ModelConverters class shown below:

public void addClassToSkip(String cls) {
LOGGER.warn("skipping class " + cls);
this.skippedClasses.add(cls);
}

Now having done this I can't seem to figure out where to actually inject the ModelConverters class, as I tried to add it to list of providers along with others but to no result. Can someone please help me with this. I have been looking for the answer for almost 3 days now.

Use a custom converter, this is a bug per my analysis, you can copy ModelResolver to your own code and do something like this.

ModelConverters.getInstance().addConverter(new ModelResolver(mapper));

Further in the ModelResolver modify following resolve method

private Model resolve(JavaType type, ModelConverterContext context, Iterator<ModelConverter> next) {
        if (type.isEnumType() || PrimitiveType.fromType(type) != null) {
            // We don't build models for primitive types
            return null;
        }

        if (type instanceof SimpleType && ((SimpleType) type).getRawClass().getName().startsWith("your classname")) {
            return yourConverter.resolve(type, context, next);
        }

It's a hack, issue is same as https://github.com/swagger-api/swagger-core/issues/2260

Was this page helpful?
0 / 5 - 0 ratings