All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.agrest.openapi.modelconverter.AgEntityModelConverter Maven / Gradle / Ivy

There is a newer version: 4.10
Show newest version
package io.agrest.openapi.modelconverter;

import io.agrest.PathConstants;
import io.agrest.meta.*;
import io.agrest.openapi.TypeWrapper;
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.util.PrimitiveType;
import io.swagger.v3.core.util.RefUtils;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.cayenne.di.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Provides OpenAPI Schema conversions for Agrest entity objects
 */
public class AgEntityModelConverter extends AgModelConverter {

    private static final Logger LOGGER = LoggerFactory.getLogger(AgEntityModelConverter.class);

    public static final String BINDING_ENTITY_PACKAGES = "openapi-entity";

    private final AgDataMap dataMap;
    private final List entityPackages;

    public AgEntityModelConverter(
            @Inject AgDataMap dataMap,
            @Inject(BINDING_ENTITY_PACKAGES) List entityPackages) {
        this.dataMap = Objects.requireNonNull(dataMap);
        this.entityPackages = Objects.requireNonNull(entityPackages);
    }

    @Override
    protected boolean willResolve(AnnotatedType type, ModelConverterContext context, TypeWrapper wrapped) {

        if (wrapped != null) {

            Package p = wrapped.getRawClass().getPackage();

            // Since AgDataMap would lazily compile an entity from any Java class,
            // we need to start with a more deterministic filter for the model classes
            return p != null && entityPackages.contains(p.getName());
        }

        return false;
    }

    @Override
    protected Schema doResolve(AnnotatedType type, ModelConverterContext context, Iterator chain, TypeWrapper wrapped) {

        LOGGER.debug("resolve AgEntity ({}}", wrapped);

        AgEntity agEntity = dataMap.getEntity(wrapped.getRawClass());
        String name = agEntity.getName();

        // ensure stable property ordering
        Map properties = new LinkedHashMap<>();

        // TODO: multi-key ids must be exposed as maps
        if (agEntity.getIdParts().size() == 1) {
            AgIdPart id = agEntity.getIdParts().iterator().next();
            properties.put(PathConstants.ID_PK_ATTRIBUTE, doResolveValue(id.getType(), context));
        }

        List sortedAttributes = new ArrayList<>(agEntity.getAttributes());
        sortedAttributes.sort(Comparator.comparing(AgAttribute::getName));
        for (AgAttribute a : sortedAttributes) {
            properties.put(a.getName(), doResolveValue(a.getType(), context));
        }

        List sortedRelationships = new ArrayList<>(agEntity.getRelationships());
        sortedRelationships.sort(Comparator.comparing(AgRelationship::getName));
        for (AgRelationship r : sortedRelationships) {
            properties.put(r.getName(), doResolveRelationship(r, context));
        }

        Schema schema = new ObjectSchema().name(name).properties(properties);
        return onSchemaResolved(type, context, schema);
    }

    protected Schema doResolveValue(Class type, ModelConverterContext context) {
        Schema primitive = PrimitiveType.createProperty(type);
        return primitive != null
                ? primitive
                : context.resolve(new AnnotatedType().type(type));
    }

    protected Schema doResolveRelationship(AgRelationship relationship, ModelConverterContext context) {

        AgEntity targetEntity = relationship.getTargetEntity();

        // ensure related entity and any other entities reachable from it are resolved
        context.resolve(new AnnotatedType().type(targetEntity.getType()));

        // link to resolved entity
        Schema relatedSchemaRef = new Schema().$ref(RefUtils.constructRef(targetEntity.getName()));
        return relationship.isToMany()
                ? new ArraySchema().items(relatedSchemaRef)
                : relatedSchemaRef;
    }

    // implementing equals/hashCode to be able to detect previously installed converters in the static context

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AgEntityModelConverter that = (AgEntityModelConverter) o;
        return dataMap.equals(that.dataMap) &&
                entityPackages.equals(that.entityPackages);
    }

    @Override
    public int hashCode() {
        return Objects.hash(dataMap, entityPackages);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy