Skip to content

Commit

Permalink
Remove non-idiomatic ShapeVisitor builder
Browse files Browse the repository at this point in the history
We previously had a builder that could create a ShapeVisitor from a
bunch of closures. This is actually not very idiomatic Java when
compared to just implementing an anonymous class that implements
ShapeVisitor.Default.
  • Loading branch information
mtdowling committed May 4, 2020
1 parent eeea998 commit 41d93b6
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 191 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ reference lookups. ([#287](https://github.com/awslabs/smithy/pull/287))
`Pattern` class. ([#315](https://github.com/awslabs/smithy/pull/315))
* Removed the `Triple` class from `smithy-utils`. ([#313](https://github.com/awslabs/smithy/pull/313))
* Normalized class names for OpenAPI `SecurityScemeConverter` implementations. ([#291](https://github.com/awslabs/smithy/pull/291))
* Removed `software.amazon.smithy.model.shapes.Shape#visitor` and
`software.amazon.smithy.model.shapes.ShapeVisitor$Builder`. Use
`software.amazon.smithy.model.shapes.ShapeVisitor$Default` instead [BC].

#### Deprecation cleanup

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* 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.
Expand All @@ -16,22 +16,19 @@
package software.amazon.smithy.linters;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.NodeMapper;
import software.amazon.smithy.model.shapes.FloatShape;
import software.amazon.smithy.model.shapes.IntegerShape;
import software.amazon.smithy.model.shapes.LongShape;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.NumberShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeType;
import software.amazon.smithy.model.shapes.ShapeVisitor;
import software.amazon.smithy.model.shapes.ShortShape;
import software.amazon.smithy.model.shapes.StringShape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.shapes.UnionShape;
import software.amazon.smithy.model.validation.AbstractValidator;
Expand Down Expand Up @@ -111,15 +108,27 @@ private ShouldHaveUsedTimestampValidator(Config config) {

@Override
public List<ValidationEvent> validate(Model model) {
ShapeVisitor<List<ValidationEvent>> visitor = Shape.<List<ValidationEvent>>visitor()
.when(StringShape.class, s -> validateSimpleShape(s, patterns))
.when(ShortShape.class, s -> validateSimpleShape(s, patterns))
.when(IntegerShape.class, s -> validateSimpleShape(s, patterns))
.when(LongShape.class, s -> validateSimpleShape(s, patterns))
.when(FloatShape.class, s -> validateSimpleShape(s, patterns))
.when(StructureShape.class, shape -> validateStructure(shape, model, patterns))
.when(UnionShape.class, shape -> validateUnion(shape, model, patterns))
.orElse(ListUtils.of());
ShapeVisitor<List<ValidationEvent>> visitor = new ShapeVisitor.Default<List<ValidationEvent>>() {
@Override
protected List<ValidationEvent> getDefault(Shape shape) {
if (shape.isStringShape() || shape instanceof NumberShape) {
return validateSimpleShape(shape, patterns);
} else {
return Collections.emptyList();
}
}

@Override
public List<ValidationEvent> structureShape(StructureShape shape) {
return validateStructure(shape, model, patterns);
}

@Override
public List<ValidationEvent> unionShape(UnionShape shape) {
return validateUnion(shape, model, patterns);
}
};

return model.shapes().flatMap(shape -> shape.accept(visitor).stream()).collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* 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.
Expand All @@ -15,14 +15,13 @@

package software.amazon.smithy.linters;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeVisitor;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.shapes.UnionShape;
import software.amazon.smithy.model.validation.AbstractValidator;
Expand All @@ -43,11 +42,12 @@ public Provider() {

@Override
public List<ValidationEvent> validate(Model model) {
ShapeVisitor<List<ValidationEvent>> visitor = Shape.<List<ValidationEvent>>visitor()
.when(UnionShape.class, shape -> validateNames(model, shape, shape.getMemberNames()))
.when(StructureShape.class, shape -> validateNames(model, shape, shape.getMemberNames()))
.orElseGet(Collections::emptyList);
return model.shapes().flatMap(shape -> shape.accept(visitor).stream()).collect(Collectors.toList());
List<ValidationEvent> events = new ArrayList<>();
model.shapes(StructureShape.class)
.forEach(shape -> events.addAll(validateNames(model, shape, shape.getMemberNames())));
model.shapes(UnionShape.class)
.forEach(shape -> events.addAll(validateNames(model, shape, shape.getMemberNames())));
return events;
}

private List<ValidationEvent> validateNames(Model model, Shape shape, Collection<String> memberNames) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* 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.
Expand Down Expand Up @@ -42,6 +42,7 @@
* compared in the context of a Model that forbids shape ID conflicts.
*/
public abstract class Shape implements FromSourceLocation, Tagged, ToShapeId, Comparable<Shape> {

private final ShapeId id;
private final Map<ShapeId, Trait> traits;
private final transient SourceLocation source;
Expand Down Expand Up @@ -115,16 +116,6 @@ public final ShapeType getType() {
*/
public abstract <R> R accept(ShapeVisitor<R> cases);

/**
* Creates a {@link ShapeVisitor.Builder}.
*
* @param <R> Return type of the visitor.
* @return Shape visitor builder.
*/
public static <R> ShapeVisitor.Builder<R> visitor() {
return new ShapeVisitor.Builder<>();
}

/**
* Get the {@link ShapeId} of the shape.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* 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.
Expand All @@ -15,20 +15,11 @@

package software.amazon.smithy.model.shapes;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import software.amazon.smithy.utils.SmithyBuilder;

/**
* Shape visitor pattern.
*
* @param <R> Return type of the visitor.
* @see Default
* @see Shape#visitor()
* @see Builder
*/
public interface ShapeVisitor<R> {

Expand Down Expand Up @@ -76,89 +67,6 @@ public interface ShapeVisitor<R> {

R timestampShape(TimestampShape shape);

/**
* Creates a {@link ShapeVisitor} used to dispatch to functions based
* on a model type.
*
* @param <R> Return value from each case.
*/
final class Builder<R> implements SmithyBuilder<ShapeVisitor<R>> {

private Map<Class<? extends Shape>, Function<? extends Shape, R>> functions = new HashMap<>();
private Function<Shape, R> orElse = shape -> {
throw new IllegalStateException("Unexpected shape: " + shape.getClass().getCanonicalName());
};

Builder() {}

@Override
@SuppressWarnings("unchecked")
public ShapeVisitor<R> build() {
return new Default<R>() {
protected R getDefault(Shape shape) {
Function<Shape, R> f = (Function<Shape, R>) functions.get(shape.getClass());
return f != null ? f.apply(shape) : orElse.apply(shape);
}
};
}

/**
* Register a case for unhandled shapes and builds the Cases.
*
* @param f Function to use for unhandled visitor.
* @return Returns the built {@link ShapeVisitor}
*/
public ShapeVisitor<R> orElseGet(Function<Shape, R> f) {
orElse = Objects.requireNonNull(f);
return build();
}

/**
* Register a case for unhandled shapes and builds the Cases.
*
* @param f Supplier to use for unhandled visitor.
* @return Returns the built {@link ShapeVisitor}
*/
public ShapeVisitor<R> orElseGet(Supplier<R> f) {
return orElseGet(shape -> f.get());
}

/**
* Return a value for all unhandled nodes.
*
* @param defaultValue Default value to return for unhandled visitor.
* @return Returns the built {@link ShapeVisitor}
*/
public ShapeVisitor<R> orElse(R defaultValue) {
return orElseGet(shape -> defaultValue);
}

/**
* Register a case for unhandled shapes that throws an exception.
*
* @param e Exception to throw if an unhandled case is encountered.
* @return Returns the built {@link ShapeVisitor}
*/
public ShapeVisitor<R> orElseThrow(RuntimeException e) {
return orElseGet(shape -> {
throw e;
});
}

/**
* Invoked when a specific shape type is encountered.
*
* @param type Shape type to handle.
* @param f Function that accepts the shape and returns R.
* @param <T> The shape type being handled.
* @return Returns the visitor builder.
*/
public <T extends Shape> Builder<R> when(Class<T> type, Function<T, R> f) {
functions.put(type, Objects.requireNonNull(f));
return this;
}
}

/**
* Creates {@link ShapeVisitor} that return a value when necessary
* when visiting shapes.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* 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.
Expand All @@ -21,6 +21,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -87,10 +88,13 @@ private List<ValidationEvent> validateSingleReference(
ReferencesTrait trait,
ResourceShape target
) {
return shape.accept(Shape.<List<ValidationEvent>>visitor()
.when(StructureShape.class, s -> validateStructureRef(model, reference, s, trait, target))
.when(StringShape.class, s -> validateStringShapeRef(reference, s, trait, target))
.orElse(ListUtils.of()));
if (shape.asStructureShape().isPresent()) {
return validateStructureRef(model, reference, shape.asStructureShape().get(), trait, target);
} else if (shape.asStringShape().isPresent()) {
return validateStringShapeRef(reference, shape.asStringShape().get(), trait, target);
} else {
return Collections.emptyList();
}
}

private List<ValidationEvent> validateStringShapeRef(
Expand Down

This file was deleted.

0 comments on commit 41d93b6

Please sign in to comment.