kongchen / swagger-maven-plugin

JAX-RS & SpringMVC supported maven build plugin, helps you generate Swagger JSON and API document in build phase.
http://kongchen.github.io/swagger-maven-plugin/
Apache License 2.0
761 stars 451 forks source link

byte[] operation responses / model properties modelled incorrectly #422

Open beaumkr opened 7 years ago

beaumkr commented 7 years ago

I ran into an issue that's well described in a known SpringFox bug:

https://github.com/springfox/springfox/issues/1605

TL;DR; a byte[] is modelled in swagger file as an Array of byte[]. => when using swagger codegen you'd end up with 'List<byte[]>' instead of simply 'byte[]'.

I fixed it by defining an additional ModelConverter that verifies if it's a byte[] and then returns a ByteArrayProperty:

`

import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.ArrayType; import com.fasterxml.jackson.databind.type.SimpleType; import io.swagger.converter.ModelConverter; import io.swagger.converter.ModelConverterContext; import io.swagger.jackson.AbstractModelConverter; import io.swagger.models.properties.ByteArrayProperty; import io.swagger.models.properties.Property; import io.swagger.util.Json;

import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Iterator;

public class ByteArrayFixerModelConverter extends AbstractModelConverter implements ModelConverter { public ByteArrayFixerModelConverter() { super(Json.mapper()); }

public Property resolveProperty(Type type, ModelConverterContext context, Annotation[] annotations,
        Iterator<ModelConverter> chain) {
    if(isByteArray(type)) {
        //bypass the chain! It would convert the ByteArrayProperty to an Array of ByteArrayProperty (bug in ModelModifier I think)
        return new ByteArrayProperty();
    }
    Property property = null;
    if (chain.hasNext()) {
        property = (chain.next()).resolveProperty(type, context, annotations, chain);
    }

    return property;

}

private boolean isByteArray(Type type) {
    boolean ret = type instanceof Class && type == byte[].class;
    if(!ret && type instanceof ArrayType){
        ArrayType at = (ArrayType) type;
        JavaType contentType = at.getContentType();
        if(contentType instanceof SimpleType){
            SimpleType st = (SimpleType) contentType;
            ret = st.getRawClass() == byte.class;
        }
    }
    return ret;
}

} `

and it helped returning my operation returns and my model properties having the correct format.

I guess this should be solved in the original Swagger ModelResolver/ModelConverter classes to handle this correctly but I'm not venturing in those :)

Maybe it would be a good idea to 'wrap' those modelresolvers or always include an extra modelresolver to fix this in the swagger maven plugin (which I like a lot!)

Breina commented 4 years ago

It does this for Request bodies as well. Here is the fix for version 2.0.10:

package com.awesome.swagger;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.SimpleType;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverterContext;
import io.swagger.v3.core.jackson.AbstractModelConverter;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.media.ByteArraySchema;
import io.swagger.v3.oas.models.media.Schema;

import java.lang.reflect.Type;
import java.util.Iterator;

public class ByteArrayFixerModelConverter extends AbstractModelConverter {

    public ByteArrayFixerModelConverter() {
        super(Json.mapper());
    }

    @Override
    public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
        if (isByteArray(type)) {
            //bypass the chain! It would convert the ByteArrayProperty to an Array of ByteArrayProperty (bug in ModelModifier I think)
            return new ByteArraySchema();
        }
        return chain.hasNext()
                ? chain.next().resolve(type, context, chain)
                : null;

    }

    private boolean isByteArray(AnnotatedType annotatedType) {
        Type type = annotatedType.getType();
        boolean ret = type instanceof Class && type == byte[].class;
        if (!ret && type instanceof ArrayType) {
            ArrayType at = (ArrayType) type;
            JavaType contentType = at.getContentType();
            if (contentType instanceof SimpleType) {
                SimpleType st = (SimpleType) contentType;
                ret = st.getRawClass() == byte.class;
            }
        }
        return ret;
    }

}
}

And don't forget to enable it in the maven configuration:

<plugin>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-maven-plugin</artifactId>
    <version>${swagger-version}</version>
    <configuration>
        <modelConverterClasses>com.awesome.swagger.ByteArrayFixerModelConverter</modelConverterClasses>
    </configuration>
</plugin>
inb18 commented 2 years ago

Hi , I am also facing the same issue with

com.github.kongchen swagger-maven-plugin 3.1.8 com.msb.rest.ByteArrayFixerModelConverter
campidelli-wcq commented 1 year ago

Same thing here, almost 7 years after 😆

Kiiv commented 4 months ago

Seems to be fixed in 2.2.22 at least