diff --git a/policy/src/main/java/dev/cel/policy/BUILD.bazel b/policy/src/main/java/dev/cel/policy/BUILD.bazel index 5fc24e33d..85b0f4d38 100644 --- a/policy/src/main/java/dev/cel/policy/BUILD.bazel +++ b/policy/src/main/java/dev/cel/policy/BUILD.bazel @@ -38,6 +38,7 @@ java_library( tags = [ ], deps = [ + ":required_fields_checker", ":source", "//:auto_value", "@maven//:com_google_errorprone_error_prone_annotations", @@ -89,6 +90,18 @@ java_library( ], ) +java_library( + name = "required_fields_checker", + srcs = [ + "RequiredFieldsChecker.java", + ], + visibility = ["//visibility:private"], + deps = [ + "//:auto_value", + "@maven//:com_google_guava_guava", + ], +) + java_library( name = "parser_context", srcs = [ diff --git a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java index 4d15c4d8b..c9b63bf3b 100644 --- a/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java +++ b/policy/src/main/java/dev/cel/policy/CelPolicyConfig.java @@ -15,15 +15,12 @@ package dev.cel.policy; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.ImmutableList.toImmutableList; -import static java.util.Arrays.stream; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; -import java.util.AbstractMap; import java.util.Arrays; import java.util.Optional; @@ -108,7 +105,7 @@ public abstract static class VariableDecl { /** Builder for {@link VariableDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -118,10 +115,10 @@ public abstract static class Builder { public abstract Builder setType(TypeDecl typeDecl); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields( - new AbstractMap.SimpleEntry<>("name", name()), - new AbstractMap.SimpleEntry<>("type", type())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("name", this::name), RequiredField.of("type", this::type)); } /** Builds a new instance of {@link VariableDecl}. */ @@ -148,7 +145,7 @@ public abstract static class FunctionDecl { /** Builder for {@link FunctionDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -158,10 +155,10 @@ public abstract static class Builder { public abstract Builder setOverloads(ImmutableSet overloads); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields( - new AbstractMap.SimpleEntry<>("name", name()), - new AbstractMap.SimpleEntry<>("overloads", overloads())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("name", this::name), RequiredField.of("overloads", this::overloads)); } /** Builds a new instance of {@link FunctionDecl}. */ @@ -200,7 +197,7 @@ public abstract static class OverloadDecl { /** Builder for {@link OverloadDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional id(); @@ -228,10 +225,10 @@ public Builder addArguments(TypeDecl... args) { public abstract Builder setReturnType(TypeDecl returnType); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields( - new AbstractMap.SimpleEntry<>("id", id()), - new AbstractMap.SimpleEntry<>("return", returnType())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("id", this::id), RequiredField.of("return", this::returnType)); } /** Builds a new instance of {@link OverloadDecl}. */ @@ -259,7 +256,7 @@ public abstract static class TypeDecl { /** Builder for {@link TypeDecl}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -283,8 +280,9 @@ public Builder addParams(Iterable params) { public abstract Builder setIsTypeParam(boolean isTypeParam); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields(new AbstractMap.SimpleEntry<>("type_name", name())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of(RequiredField.of("type_name", this::name)); } @CheckReturnValue @@ -319,7 +317,7 @@ public abstract static class ExtensionConfig { /** Builder for {@link ExtensionConfig}. */ @AutoValue.Builder - public abstract static class Builder { + public abstract static class Builder implements RequiredFieldsChecker { abstract Optional name(); @@ -329,8 +327,9 @@ public abstract static class Builder { public abstract Builder setVersion(Integer version); - ImmutableList getMissingRequiredFieldNames() { - return getMissingRequiredFields(new AbstractMap.SimpleEntry<>("name", name())); + @Override + public ImmutableList requiredFields() { + return ImmutableList.of(RequiredField.of("name", this::name)); } /** Builds a new instance of {@link ExtensionConfig}. */ @@ -352,13 +351,4 @@ public static ExtensionConfig of(String name, int version) { return newBuilder().setName(name).setVersion(version).build(); } } - - @SafeVarargs - private static ImmutableList getMissingRequiredFields( - AbstractMap.SimpleEntry>... requiredFields) { - return stream(requiredFields) - .filter(entry -> !entry.getValue().isPresent()) - .map(AbstractMap.SimpleEntry::getKey) - .collect(toImmutableList()); - } } diff --git a/policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java b/policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java new file mode 100644 index 000000000..e46b2822a --- /dev/null +++ b/policy/src/main/java/dev/cel/policy/RequiredFieldsChecker.java @@ -0,0 +1,49 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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 dev.cel.policy; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import java.util.Optional; +import java.util.function.Supplier; + +/** + * Interface to be implemented on a builder that can be used to verify all required fields being + * set. + */ +interface RequiredFieldsChecker { + + ImmutableList requiredFields(); + + default ImmutableList getMissingRequiredFieldNames() { + return requiredFields().stream() + .filter(entry -> !entry.fieldValue().get().isPresent()) + .map(RequiredField::displayName) + .collect(toImmutableList()); + } + + @AutoValue + abstract class RequiredField { + abstract String displayName(); + + abstract Supplier> fieldValue(); + + static RequiredField of(String displayName, Supplier> fieldValue) { + return new AutoValue_RequiredFieldsChecker_RequiredField(displayName, fieldValue); + } + } +}