damianwajser/spring-rest-commons-options

View on GitHub
src/main/java/com/github/damianwajser/utils/JsonSchemmaUtils.java

Summary

Maintainability
A
2 hrs
Test Coverage
package com.github.damianwajser.utils;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;

public final class JsonSchemmaUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(JsonSchemmaUtils.class);

    private JsonSchemmaUtils() {
    }

    private static Optional<JsonSchema> getSchemma(Optional<Class<?>> clazz) {
        Optional<JsonSchema> opt = Optional.empty();
        if(clazz.isPresent()) {
            opt = getSchemma(clazz.get());
        }
        return opt;
    }
    private static Optional<JsonSchema> getSchemma(Class<?> clazz) {
        ObjectMapper mapper = new ObjectMapper();
        Optional<JsonSchema> schema = Optional.empty();
        SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
        Optional<Class<?>> realClazz = ReflectionUtils.getGenericClass(clazz);
        boolean iterable = Iterable.class.isAssignableFrom(clazz) && realClazz.isPresent();
        if (iterable) {
            clazz = realClazz.get();
        }

        try {
            mapper.acceptJsonFormatVisitor(clazz, visitor);
            JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(mapper);
            schema = Optional.ofNullable(schemaGen.generateSchema(clazz));
            if (iterable) {
                // TODO: decirle que es una collection
            }
        } catch (JsonMappingException e) {
            LOGGER.error("Se produjo un error al crear el JsonSchemma para la clase {}", clazz.getSimpleName(), e);
        }
        return schema;
    }

    public static Optional<JsonSchema> getSchemma(Method m, Class<?> controller, boolean isRequest) {
        Optional<JsonSchema> schemma;
        if (isRequest) {
            schemma = getRequestSchemma(m, controller);
        } else {
            schemma = getResponseSchemma(m, controller);
        }
        return schemma;
    }

    private static Optional<JsonSchema> getResponseSchemma(Method m, Class<?> parametrizedClass) {
        Optional<JsonSchema> schemma = Optional.empty();
        // obtengo el tipo real de retorno por si es generic
        Optional<Type> returnType = ReflectionUtils.getRealType(m.getGenericReturnType(), parametrizedClass);
        if (returnType.isPresent()) {
            // el return type puede ser una colleccion para eso obtengo la clase real del
            // parametro a traves de reflection utils
            Optional<Class<?>> realClass = ReflectionUtils.getClass(returnType.get());
            if (realClass.isPresent()) {
                if (Iterable.class.isAssignableFrom(realClass.get())) {
                    // si es una collection tengo que saber si es generic, para eso le pido la clase
                    // al return type
                    if (ParameterizedType.class.isAssignableFrom(returnType.get().getClass()))
                        returnType = ReflectionUtils.getGenericType((ParameterizedType) returnType.get());
                }

                schemma = getSchemma(ReflectionUtils.getClass(returnType.orElse(null)).orElse(realClass.get()));
            } else {
                LOGGER.error("No existe una real class para: {}", returnType);
            }
        }
        return schemma;
    }

    private static Optional<JsonSchema> getRequestSchemma(Method m, Class<?> controller) {
        List<Parameter> p = ReflectionUtils.getParametersBody(m);
        Optional<JsonSchema> schemma = Optional.empty();
        if (!p.isEmpty()) {
            Optional<Type> t = ReflectionUtils.getRealType(p.get(0).getParameterizedType(), controller);
            if (t.isPresent()) {
                Optional<Class<?>> c = ReflectionUtils.getClass(t.get());
                if (c.isPresent()) {
                    schemma = getSchemma(c.get());
                } else {
                    schemma = getSchemma(t.getClass());
                }
            } else {
                schemma = getSchemma(ReflectionUtils.getClass(p.get(0).getParameterizedType()));
            }
        }
        return schemma;
    }
}