Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to add a ModelConverter in a Spring project ? #1528

Closed
YLombardi opened this issue Oct 29, 2015 · 4 comments
Closed

How to add a ModelConverter in a Spring project ? #1528

YLombardi opened this issue Oct 29, 2015 · 4 comments
Labels

Comments

@YLombardi
Copy link

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 ?

@dilipkrish
Copy link
Contributor

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.

@YLombardi
Copy link
Author

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 ?

@webron webron added the Support label Oct 29, 2015
@fehguy fehguy closed this as completed Dec 25, 2016
@sagar-suri
Copy link

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.

@ssoffline
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants