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

software.amazon.smithy.diff.ChangedShape Maven / Gradle / Ivy

Go to download

This module detects differences between two Smithy models, identifying changes that are safe and changes that are backward incompatible.

The newest version!
/*
 * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package software.amazon.smithy.diff;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import software.amazon.smithy.model.FromSourceLocation;
import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.Trait;
import software.amazon.smithy.utils.Pair;

/**
 * Represents a changed shape.
 *
 * @param  The type of shape. Note that this may be just {@link Shape}
 *   in the event that the shape changed classes.
 */
public final class ChangedShape implements FromSourceLocation {
    private final S oldShape;
    private final S newShape;
    private final Map> traitDiff;

    public ChangedShape(S oldShape, S newShape) {
        this.oldShape = oldShape;
        this.newShape = newShape;
        traitDiff = Collections.unmodifiableMap(findTraitDifferences(oldShape, newShape));
    }

    /**
     * Gets the old shape value.
     *
     * @return Returns the old shape.
     */
    public S getOldShape() {
        return oldShape;
    }

    /**
     * Gets the new shape value.
     *
     * @return Returns the new shape.
     */
    public S getNewShape() {
        return newShape;
    }

    @Override
    public SourceLocation getSourceLocation() {
        return getNewShape().getSourceLocation();
    }

    /**
     * Gets the shape ID of the changed shape.
     *
     * @return Return the shape ID.
     */
    public ShapeId getShapeId() {
        return newShape.getId();
    }

    /**
     * Gets a stream of added traits.
     *
     * @return Returns the traits that were added.
     */
    public Stream addedTraits() {
        return traitDiff.values().stream()
                .filter(pair -> pair.getLeft() == null)
                .map(Pair::getRight);
    }

    /**
     * Gets a stream of removed traits.
     *
     * @return Returns the traits that were removed.
     */
    public Stream removedTraits() {
        return traitDiff.values().stream()
                .filter(pair -> pair.getRight() == null)
                .map(Pair::getLeft);
    }

    /**
     * Gets a stream of changed traits.
     *
     * @return Returns the traits that were changed.
     */
    public Stream> changedTraits() {
        return traitDiff.values().stream().filter(pair -> pair.getLeft() != null && pair.getRight() != null);
    }

    /**
     * Checks if the trait was added.
     *
     * @param trait Trait to check.
     * @return Returns true if the trait was added.
     */
    public boolean isTraitAdded(ShapeId trait) {
        return !oldShape.hasTrait(trait) && newShape.hasTrait(trait);
    }

    /**
     * Checks if the trait was removed.
     *
     * @param trait Trait to check.
     * @return Returns true if the trait was removed.
     */
    public boolean isTraitRemoved(ShapeId trait) {
        return oldShape.hasTrait(trait) && !newShape.hasTrait(trait);
    }

    /**
     * Checks if the given trait is in the old shape and new shape.
     *
     * @param trait Trait to check.
     * @return Returns true if the trait is in the old and new shape.
     */
    public boolean isTraitInBoth(ShapeId trait) {
        return oldShape.hasTrait(trait) && newShape.hasTrait(trait);
    }

    /**
     * Gets a changed trait of a specific type.
     *
     * @param traitType Type of trait to find.
     * @param  Type of trait to find.
     * @return Returns the optionally found old and new typed trait values.
     */
    @SuppressWarnings("unchecked")
    public  Optional> getChangedTrait(Class traitType) {
        return changedTraits()
                .filter(p -> traitType.isInstance(p.getLeft()) && traitType.isInstance(p.getRight()))
                .map(p -> (Pair) p)
                .findFirst();
    }

    /**
     * Gets the trait differences between the old and new shape.
     *
     * 

The returned map is a mapping of a trait name to a pair in which the * left side of the pair contains the nullable old trait value, and the * right side of the pair contains the nullable new trait value. The left * side will be null if the trait was added, the right side will be null * if the trait was removed, and both traits will be present if the trait * changed. * * @return Returns a map of each changed trait name to a pair of the old and new trait values. */ public Map> getTraitDifferences() { return traitDiff; } @Override public boolean equals(Object o) { if (this == o) { return true; } else if (!(o instanceof ChangedShape)) { return false; } else { // If the shapes are equal, then the changed traits are equal, so // there's no need to compare the traitDiff property. ChangedShape that = (ChangedShape) o; return Objects.equals(getOldShape(), that.getOldShape()) && Objects.equals(getNewShape(), that.getNewShape()); } } @Override public int hashCode() { return Objects.hash(getOldShape(), getNewShape()); } /** * Finds the trait differences between the old and new shape. * * @param oldShape Old shape. * @param newShape New shape. * @return Returns a map of each changed trait ID to a pair of the old and new trait values. */ private static Map> findTraitDifferences(Shape oldShape, Shape newShape) { Map> changes = new HashMap<>(); for (Trait oldTrait : oldShape.getAllTraits().values()) { Trait newTrait = newShape.findTrait(oldTrait.toShapeId()).orElse(null); if (newTrait == null) { changes.put(oldTrait.toShapeId(), (Pair.of(oldTrait, null))); } else if (!newTrait.equals(oldTrait)) { changes.put(newTrait.toShapeId(), Pair.of(oldTrait, newTrait)); } } // Find traits that were added. newShape.getAllTraits().values().stream() .filter(newTrait -> !oldShape.findTrait(newTrait.toShapeId()).isPresent()) .forEach(newTrait -> changes.put(newTrait.toShapeId(), Pair.of(null, newTrait))); return changes; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy