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

io.agrest.jaxrs3.openapi.modelconverter.AgEntityAwareModelConverter Maven / Gradle / Ivy

There is a newer version: 5.0.M19
Show newest version
package io.agrest.jaxrs3.openapi.modelconverter;

import io.agrest.PathConstants;
import io.agrest.meta.AgAttribute;
import io.agrest.meta.AgEntity;
import io.agrest.meta.AgIdPart;
import io.agrest.meta.AgRelationship;
import io.swagger.v3.core.converter.AnnotatedType;
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 java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @since 5.0
 */
public abstract class AgEntityAwareModelConverter extends AgModelConverter {

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

    protected Schema doResolveId(AgEntity entity, ModelConverterContext context, PropertyAccessChecker accessChecker) {
        switch (entity.getIdParts().size()) {
            case 0:
                return null;
            case 1:
                return doResolveSingleId(entity, context, accessChecker);
            default:
                return doResolveIdMap(entity, context, accessChecker);
        }
    }

    protected Schema doResolveSingleId(AgEntity entity, ModelConverterContext context, PropertyAccessChecker accessChecker) {
        AgIdPart idPart = entity.getIdParts().iterator().next();
        return accessChecker.allow(idPart) ? doResolveValue(idPart.getType(), context) : null;
    }

    protected Schema doResolveIdMap(AgEntity entity, ModelConverterContext context, PropertyAccessChecker accessChecker) {

        Map properties = new LinkedHashMap<>();

        List sortedIds = new ArrayList<>(entity.getIdParts());
        sortedIds.sort(Comparator.comparing(AgIdPart::getName));
        for (AgIdPart idPart : sortedIds) {
            if (accessChecker.allow(idPart)) {
                properties.put(idPart.getName(), doResolveValue(idPart.getType(), context));
            }
        }

        return properties.isEmpty() ? null : new ObjectSchema().properties(properties);
    }

    protected Schema doResolveAttribute(AgAttribute attribute, ModelConverterContext context, PropertyAccessChecker accessChecker) {
        return accessChecker.allow(attribute) ? doResolveValue(attribute.getType(), context) : null;
    }

    protected Schema doResolveRelationship(AgRelationship r, ModelConverterContext context, PropertyAccessChecker accessChecker) {

        if (!accessChecker.allow(r)) {
            return null;
        }

        AgEntity targetEntity = r.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 r.isToMany()
                ? new ArraySchema().items(relatedSchemaRef)
                : relatedSchemaRef;
    }

    protected Schema doResolveRelationshipRef(AgRelationship r, ModelConverterContext context, PropertyAccessChecker accessChecker) {

        if (!accessChecker.allow(r)) {
            return null;
        }

        // relationships in updates are resolved as refs to IDs.. The permission here is for writing a relationship,
        // not the ID, so since we just checked it above, always allow to proceed
        Schema idSchema = doResolveId(r.getTargetEntity(), context, PropertyAccessChecker.allowAll());
        if (idSchema != null) {
            return r.isToMany() ? new ArraySchema().items(idSchema) : idSchema;
        }

        return null;
    }

    protected Map doCollectProperties(
            Schema idSchema,
            List> attributesAndRelationships) {

        // property sorting should be stable and match that of DataResponse: "id" goes first, then a mix of
        // attributes and relationships in alphabetic order

        Map properties = new LinkedHashMap<>();

        if (idSchema != null) {
            properties.put(PathConstants.ID_PK_ATTRIBUTE, idSchema);
        }

        attributesAndRelationships.stream()
                .sorted(Map.Entry.comparingByKey())
                .forEach(e -> properties.put(e.getKey(), e.getValue()));

        return properties;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy