diff --git a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel index 50b78c63b..0201a5807 100644 --- a/bundle/src/main/java/dev/cel/bundle/BUILD.bazel +++ b/bundle/src/main/java/dev/cel/bundle/BUILD.bazel @@ -73,7 +73,6 @@ java_library( "//common/types:type_providers", "//compiler:compiler_builder", "//extensions", - "//extensions:optional_library", "//parser:macro", "//runtime", "@maven//:com_google_errorprone_error_prone_annotations", @@ -103,6 +102,7 @@ java_library( ":environment", ":environment_exception", "//common:compiler_common", + "//common:container", "//common/formats:file_source", "//common/formats:parser_context", "//common/formats:yaml_helper", diff --git a/bundle/src/main/java/dev/cel/bundle/CelEnvironment.java b/bundle/src/main/java/dev/cel/bundle/CelEnvironment.java index 9f33032a8..b54e3ca51 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelEnvironment.java +++ b/bundle/src/main/java/dev/cel/bundle/CelEnvironment.java @@ -80,10 +80,9 @@ public abstract class CelEnvironment { public abstract String name(); /** - * An optional description of the config (example: location of the file containing the config - * content). + * Container, which captures default namespace and aliases for value resolution. */ - public abstract String container(); + public abstract CelContainer container(); /** * An optional description of the environment (example: location of the file containing the config @@ -124,7 +123,12 @@ public abstract static class Builder { public abstract Builder setDescription(String description); - public abstract Builder setContainer(String container); + public abstract Builder setContainer(CelContainer container); + + @CanIgnoreReturnValue + public Builder setContainer(String container) { + return setContainer(CelContainer.ofName(container)); + } @CanIgnoreReturnValue public Builder addExtensions(ExtensionConfig... extensions) { @@ -182,7 +186,7 @@ public static Builder newBuilder() { return new AutoValue_CelEnvironment.Builder() .setName("") .setDescription("") - .setContainer("") + .setContainer(CelContainer.ofName("")) .setVariables(ImmutableSet.of()) .setFunctions(ImmutableSet.of()); } @@ -195,8 +199,8 @@ public CelCompiler extend(CelCompiler celCompiler, CelOptions celOptions) CelCompilerBuilder compilerBuilder = celCompiler .toCompilerBuilder() + .setContainer(container()) .setTypeProvider(celTypeProvider) - .setContainer(CelContainer.ofName(container())) .addVarDeclarations( variables().stream() .map(v -> v.toCelVarDecl(celTypeProvider)) @@ -206,10 +210,6 @@ public CelCompiler extend(CelCompiler celCompiler, CelOptions celOptions) .map(f -> f.toCelFunctionDecl(celTypeProvider)) .collect(toImmutableList())); - if (!container().isEmpty()) { - compilerBuilder.setContainer(CelContainer.ofName(container())); - } - addAllCompilerExtensions(compilerBuilder, celOptions); applyStandardLibrarySubset(compilerBuilder); @@ -683,6 +683,38 @@ public static ExtensionConfig latest(String name) { } } + @AutoValue + abstract static class Alias { + abstract String alias(); + + abstract String qualifiedName(); + + static Builder newBuilder() { + return new AutoValue_CelEnvironment_Alias.Builder(); + } + + @AutoValue.Builder + abstract static class Builder implements RequiredFieldsChecker { + + abstract Optional alias(); + + abstract Optional qualifiedName(); + + abstract Builder setAlias(String alias); + + abstract Builder setQualifiedName(String qualifiedName); + + abstract Alias build(); + + @Override + public ImmutableList requiredFields() { + return ImmutableList.of( + RequiredField.of("alias", this::alias), + RequiredField.of("qualified_name", this::qualifiedName)); + } + } + } + @VisibleForTesting enum CanonicalCelExtension { BINDINGS((options, version) -> CelExtensions.bindings()), diff --git a/bundle/src/main/java/dev/cel/bundle/CelEnvironmentExporter.java b/bundle/src/main/java/dev/cel/bundle/CelEnvironmentExporter.java index d303e0528..129577107 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelEnvironmentExporter.java +++ b/bundle/src/main/java/dev/cel/bundle/CelEnvironmentExporter.java @@ -161,6 +161,9 @@ public static CelEnvironmentExporter.Builder newBuilder() { * */ public CelEnvironment export(Cel cel) { + CelEnvironment.Builder envBuilder = CelEnvironment.newBuilder(); + envBuilder.setContainer(cel.toCheckerBuilder().container()); + // Inventory is a full set of declarations and macros that are found in the configuration of // the supplied CEL instance. // @@ -171,8 +174,6 @@ public CelEnvironment export(Cel cel) { Set inventory = new HashSet<>(); collectInventory(inventory, cel); - - CelEnvironment.Builder envBuilder = CelEnvironment.newBuilder(); addExtensionConfigsAndRemoveFromInventory(envBuilder, inventory); addStandardLibrarySubsetAndRemoveFromInventory(envBuilder, inventory); addCustomDecls(envBuilder, inventory); diff --git a/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlParser.java b/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlParser.java index 3acb73fa5..8c19fcfa6 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlParser.java +++ b/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlParser.java @@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import dev.cel.bundle.CelEnvironment.Alias; import dev.cel.bundle.CelEnvironment.ExtensionConfig; import dev.cel.bundle.CelEnvironment.FunctionDecl; import dev.cel.bundle.CelEnvironment.LibrarySubset; @@ -35,6 +36,7 @@ import dev.cel.bundle.CelEnvironment.OverloadDecl; import dev.cel.bundle.CelEnvironment.TypeDecl; import dev.cel.bundle.CelEnvironment.VariableDecl; +import dev.cel.common.CelContainer; import dev.cel.common.CelIssue; import dev.cel.common.formats.CelFileSource; import dev.cel.common.formats.ParserContext; @@ -64,6 +66,8 @@ public final class CelEnvironmentYamlParser { private static final ExtensionConfig ERROR_EXTENSION_DECL = ExtensionConfig.of(ERROR); private static final FunctionSelector ERROR_FUNCTION_SELECTOR = FunctionSelector.create(ERROR, ImmutableSet.of()); + private static final Alias ERROR_ALIAS = + Alias.newBuilder().setAlias(ERROR).setQualifiedName(ERROR).build(); /** Generates a new instance of {@code CelEnvironmentYamlParser}. */ public static CelEnvironmentYamlParser newInstance() { @@ -88,6 +92,124 @@ public CelEnvironment parse(String environmentYamlSource, String description) return parser.parseYaml(environmentYamlSource, description); } + private CelContainer parseContainer(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + // Syntax variant 1: "container: `str`" + if (validateYamlType(node, YamlNodeType.STRING, YamlNodeType.TEXT)) { + return CelContainer.ofName(newString(ctx, node)); + } + + // Syntax variant 2: + // container + // name: str + // abbreviations: + // - a1 + // - a2 + // aliases: + // - alias: a1 + // qualified_name: q1 + // - alias: a2 + // qualified_name: q2 + if (!assertYamlType(ctx, valueId, node, YamlNodeType.MAP)) { + return CelContainer.ofName(ERROR); + } + + CelContainer.Builder builder = CelContainer.newBuilder(); + MappingNode variableMap = (MappingNode) node; + for (NodeTuple nodeTuple : variableMap.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + Node valueNode = nodeTuple.getValueNode(); + String keyName = ((ScalarNode) keyNode).getValue(); + switch (keyName) { + case "name": + builder.setName(newString(ctx, valueNode)); + break; + case "aliases": + ImmutableSet aliases = parseAliases(ctx, valueNode); + for (Alias alias : aliases) { + builder.addAlias(alias.alias(), alias.qualifiedName()); + } + break; + case "abbreviations": + builder.addAbbreviations(parseAbbreviations(ctx, valueNode)); + break; + default: + ctx.reportError(keyId, String.format("Unsupported container tag: %s", keyName)); + break; + } + } + + return builder.build(); + } + + private ImmutableSet parseAliases(ParserContext ctx, Node node) { + ImmutableSet.Builder aliasSetBuilder = ImmutableSet.builder(); + long valueId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return aliasSetBuilder.build(); + } + + SequenceNode variableListNode = (SequenceNode) node; + for (Node elementNode : variableListNode.getValue()) { + aliasSetBuilder.add(parseAlias(ctx, elementNode)); + } + + return aliasSetBuilder.build(); + } + + private Alias parseAlias(ParserContext ctx, Node node) { + long id = ctx.collectMetadata(node); + if (!assertYamlType(ctx, id, node, YamlNodeType.MAP)) { + return ERROR_ALIAS; + } + + Alias.Builder builder = Alias.newBuilder(); + MappingNode attrMap = (MappingNode) node; + for (NodeTuple nodeTuple : attrMap.getValue()) { + Node keyNode = nodeTuple.getKeyNode(); + long keyId = ctx.collectMetadata(keyNode); + Node valueNode = nodeTuple.getValueNode(); + String keyName = ((ScalarNode) keyNode).getValue(); + switch (keyName) { + case "alias": + builder.setAlias(newString(ctx, valueNode)); + break; + case "qualified_name": + builder.setQualifiedName(newString(ctx, valueNode)); + break; + default: + ctx.reportError(keyId, String.format("Unsupported alias tag: %s", keyName)); + break; + } + } + + if (!assertRequiredFields(ctx, id, builder.getMissingRequiredFieldNames())) { + return ERROR_ALIAS; + } + + return builder.build(); + } + + private ImmutableSet parseAbbreviations(ParserContext ctx, Node node) { + long valueId = ctx.collectMetadata(node); + if (!assertYamlType(ctx, valueId, node, YamlNodeType.LIST)) { + return ImmutableSet.of(ERROR); + } + + ImmutableSet.Builder builder = ImmutableSet.builder(); + SequenceNode nameListNode = (SequenceNode) node; + for (Node elementNode : nameListNode.getValue()) { + long elementId = ctx.collectMetadata(elementNode); + if (!assertYamlType(ctx, elementId, elementNode, YamlNodeType.STRING)) { + return ImmutableSet.of(ERROR); + } + + builder.add(((ScalarNode) elementNode).getValue()); + } + return builder.build(); + } + private ImmutableSet parseVariables(ParserContext ctx, Node node) { long valueId = ctx.collectMetadata(node); ImmutableSet.Builder variableSetBuilder = ImmutableSet.builder(); @@ -620,7 +742,7 @@ private CelEnvironment.Builder parseConfig(ParserContext ctx, Node node) { builder.setDescription(newString(ctx, valueNode)); break; case "container": - builder.setContainer(newString(ctx, valueNode)); + builder.setContainer(parseContainer(ctx, valueNode)); break; case "variables": builder.setVariables(parseVariables(ctx, valueNode)); diff --git a/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlSerializer.java b/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlSerializer.java index 687bf4ff9..81f206b94 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlSerializer.java +++ b/bundle/src/main/java/dev/cel/bundle/CelEnvironmentYamlSerializer.java @@ -16,10 +16,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import dev.cel.bundle.CelEnvironment.Alias; import dev.cel.bundle.CelEnvironment.LibrarySubset; import dev.cel.bundle.CelEnvironment.LibrarySubset.FunctionSelector; import dev.cel.bundle.CelEnvironment.LibrarySubset.OverloadSelector; +import dev.cel.common.CelContainer; import java.util.Comparator; +import java.util.Map; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.nodes.Node; @@ -55,6 +58,8 @@ private CelEnvironmentYamlSerializer() { CelEnvironment.LibrarySubset.FunctionSelector.class, new RepresentFunctionSelector()); this.multiRepresenters.put( CelEnvironment.LibrarySubset.OverloadSelector.class, new RepresentOverloadSelector()); + this.multiRepresenters.put(CelEnvironment.Alias.class, new RepresentAlias()); + this.multiRepresenters.put(CelContainer.class, new RepresentContainer()); } public static String toYaml(CelEnvironment environment) { @@ -72,7 +77,9 @@ public Node representData(Object data) { if (!environment.description().isEmpty()) { configMap.put("description", environment.description()); } - if (!environment.container().isEmpty()) { + if (!environment.container().name().isEmpty() + || !environment.container().abbreviations().isEmpty() + || !environment.container().aliases().isEmpty()) { configMap.put("container", environment.container()); } if (!environment.extensions().isEmpty()) { @@ -91,6 +98,43 @@ public Node representData(Object data) { } } + private final class RepresentContainer implements Represent { + + @Override + public Node representData(Object data) { + CelContainer container = (CelContainer) data; + ImmutableMap.Builder configMap = ImmutableMap.builder(); + if (!container.name().isEmpty()) { + configMap.put("name", container.name()); + } + if (!container.abbreviations().isEmpty()) { + configMap.put("abbreviations", container.abbreviations()); + } + if (!container.aliases().isEmpty()) { + ImmutableList.Builder aliases = ImmutableList.builder(); + for (Map.Entry entry : container.aliases().entrySet()) { + aliases.add( + Alias.newBuilder() + .setAlias(entry.getKey()) + .setQualifiedName(entry.getValue()) + .build()); + } + configMap.put("aliases", aliases.build()); + } + return represent(configMap.buildOrThrow()); + } + } + + private final class RepresentAlias implements Represent { + + @Override + public Node representData(Object data) { + Alias alias = (Alias) data; + return represent( + ImmutableMap.of("alias", alias.alias(), "qualified_name", alias.qualifiedName())); + } + } + private final class RepresentExtensionConfig implements Represent { @Override public Node representData(Object data) { diff --git a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentExporterTest.java b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentExporterTest.java index fd178857f..b9a81a662 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentExporterTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentExporterTest.java @@ -31,6 +31,7 @@ import dev.cel.bundle.CelEnvironment.OverloadDecl; import dev.cel.bundle.CelEnvironment.TypeDecl; import dev.cel.bundle.CelEnvironment.VariableDecl; +import dev.cel.common.CelContainer; import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOptions; import dev.cel.common.CelOverloadDecl; @@ -238,5 +239,26 @@ public void customVariables() { celEnvironment.variables().stream().map(VariableDecl::name).collect(toImmutableList())) .containsNoneOf("double", "null_type"); } + + @Test + public void container() { + Cel cel = + CelFactory.standardCelBuilder() + .setContainer( + CelContainer.newBuilder() + .setName("cntnr") + .addAbbreviations("foo.Bar", "baz.Qux") + .addAlias("nm", "user.name") + .addAlias("id", "user.id") + .build()) + .build(); + + CelEnvironmentExporter exporter = CelEnvironmentExporter.newBuilder().build(); + CelEnvironment celEnvironment = exporter.export(cel); + CelContainer container = celEnvironment.container(); + assertThat(container.name()).isEqualTo("cntnr"); + assertThat(container.abbreviations()).containsExactly("foo.Bar", "baz.Qux").inOrder(); + assertThat(container.aliases()).containsAtLeast("nm", "user.name", "id", "user.id").inOrder(); + } } diff --git a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentTest.java b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentTest.java index 56a4a241c..6a6eed34d 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentTest.java @@ -24,6 +24,7 @@ import dev.cel.bundle.CelEnvironment.LibrarySubset; import dev.cel.bundle.CelEnvironment.LibrarySubset.FunctionSelector; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelContainer; import dev.cel.common.CelOptions; import dev.cel.common.CelValidationException; import dev.cel.common.CelValidationResult; @@ -43,12 +44,33 @@ public void newBuilder_defaults() { assertThat(environment.source()).isEmpty(); assertThat(environment.name()).isEmpty(); assertThat(environment.description()).isEmpty(); - assertThat(environment.container()).isEmpty(); + assertThat(environment.container().name()).isEmpty(); + assertThat(environment.container().abbreviations()).isEmpty(); + assertThat(environment.container().aliases()).isEmpty(); assertThat(environment.extensions()).isEmpty(); assertThat(environment.variables()).isEmpty(); assertThat(environment.functions()).isEmpty(); } + @Test + public void container() { + CelEnvironment environment = + CelEnvironment.newBuilder() + .setContainer( + CelContainer.newBuilder() + .setName("cntr") + .addAbbreviations("foo.Bar", "baz.Qux") + .addAlias("nm", "user.name") + .addAlias("id", "user.id") + .build()) + .build(); + assertThat(environment.container().name()).isEqualTo("cntr"); + assertThat(environment.container().abbreviations()) + .containsExactly("foo.Bar", "baz.Qux"); + assertThat(environment.container().aliases()) + .containsExactly("nm", "user.name", "id", "user.id"); + } + @Test public void extend_allExtensions() throws Exception { ImmutableSet extensionConfigs = diff --git a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlParserTest.java b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlParserTest.java index fb51f3f87..d69d0517b 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlParserTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlParserTest.java @@ -33,6 +33,7 @@ import dev.cel.bundle.CelEnvironment.TypeDecl; import dev.cel.bundle.CelEnvironment.VariableDecl; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelContainer; import dev.cel.common.CelOptions; import dev.cel.common.CelSource; import dev.cel.common.ast.CelExpr; @@ -346,6 +347,36 @@ public void environment_setContainer() throws Exception { assertThat(environment.extend(CEL_WITH_MESSAGE_TYPES, CelOptions.DEFAULT)).isNotNull(); } + @Test + public void environment_setContainerWithAliasesAndAbbreviations() throws Exception { + String yamlConfig = + "container:\n" + + " name: 'google.rpc.context'\n" + + " abbreviations:\n" + + " - 'pkg3.lib3.Baz'\n" + + " - pkg4.lib4.Qux\n" + + " aliases:\n" + + " - alias: 'foo'\n" + + " qualified_name: 'pkg1.lib1.Foo'\n" + + " - alias: bar\n" + + " qualified_name: pkg2.lib2.Bar\n"; + + CelEnvironment environment = ENVIRONMENT_PARSER.parse(yamlConfig); + + assertThat(environment) + .isEqualTo( + CelEnvironment.newBuilder() + .setContainer( + CelContainer.newBuilder() + .setName("google.rpc.context") + .addAbbreviations("pkg3.lib3.Baz", "pkg4.lib4.Qux") + .addAlias("foo", "pkg1.lib1.Foo") + .addAlias("bar", "pkg2.lib2.Bar") + .build()) + .setSource(environment.source().get()) + .build()); + } + @Test public void environment_withInlinedVariableDecl() throws Exception { String yamlConfig = @@ -623,6 +654,24 @@ private enum EnvironmentParseErrorTestcase { "ERROR: :7:11: Unsupported overload selector tag: unknown_tag\n" + " | unknown_tag: 'test_value'\n" + " | ..........^"), + MISSING_ALIAS_FIELDS( + "container:\n" + + " name: 'test_container'\n" + + " aliases:\n" + + " - qualified_name: 'test_qualified_name'\n", + "ERROR: :4:7: Missing required attribute(s): alias\n" + + " | - qualified_name: 'test_qualified_name'\n" + + " | ......^"), + ILLEGAL_ALIAS_TAG( + "container:\n" + + " name: 'test_container'\n" + + " aliases:\n" + + " - alias: 'test_alias'\n" + + " qualified_name: 'test_qualified_name'\n" + + " unknown_tag: 'test_value'\n", + "ERROR: :6:7: Unsupported alias tag: unknown_tag\n" + + " | unknown_tag: 'test_value'\n" + + " | ......^"), ; private final String yamlConfig; diff --git a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlSerializerTest.java b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlSerializerTest.java index 2bd39ad1f..7e4be0912 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlSerializerTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelEnvironmentYamlSerializerTest.java @@ -28,6 +28,7 @@ import dev.cel.bundle.CelEnvironment.OverloadDecl; import dev.cel.bundle.CelEnvironment.TypeDecl; import dev.cel.bundle.CelEnvironment.VariableDecl; +import dev.cel.common.CelContainer; import java.io.IOException; import java.net.URL; import org.junit.Test; @@ -43,7 +44,13 @@ public void toYaml_success() throws Exception { CelEnvironment.newBuilder() .setName("dump_env") .setDescription("dump_env description") - .setContainer("test.container") + .setContainer( + CelContainer.newBuilder() + .setName("test.container") + .addAbbreviations("abbr1.Abbr1", "abbr2.Abbr2") + .addAlias("alias1", "qual.name1") + .addAlias("alias2", "qual.name2") + .build()) .addExtensions( ImmutableSet.of( ExtensionConfig.of("bindings"), diff --git a/common/src/main/java/dev/cel/common/CelContainer.java b/common/src/main/java/dev/cel/common/CelContainer.java index ccb1715ba..3c1ff7ada 100644 --- a/common/src/main/java/dev/cel/common/CelContainer.java +++ b/common/src/main/java/dev/cel/common/CelContainer.java @@ -16,11 +16,13 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Optional; @@ -32,12 +34,17 @@ public abstract class CelContainer { public abstract String name(); - abstract ImmutableMap aliases(); + abstract ImmutableMap aliasMap(); + + public abstract ImmutableMap aliases(); + public abstract ImmutableList abbreviations(); /** Builder for {@link CelContainer} */ @AutoValue.Builder public abstract static class Builder { + private final LinkedHashMap aliasMap = new LinkedHashMap<>(); + private final ArrayList abbreviations = new ArrayList<>(); private final LinkedHashMap aliases = new LinkedHashMap<>(); abstract String name(); @@ -45,7 +52,9 @@ public abstract static class Builder { /** Sets the fully-qualified name of the container. */ public abstract Builder setName(String name); + abstract Builder setAliasMap(ImmutableMap aliasMap); abstract Builder setAliases(ImmutableMap aliases); + abstract Builder setAbbreviations(ImmutableList abbreviations); /** See {@link #addAbbreviations(ImmutableSet)} for documentation. */ @CanIgnoreReturnValue @@ -134,6 +143,7 @@ public Builder addAbbreviations(ImmutableSet qualifiedNames) { String alias = qualifiedName.substring(index + 1); aliasAs(AliasKind.ABBREVIATION, qualifiedName, alias); + abbreviations.add(qualifiedName); } return this; @@ -165,12 +175,13 @@ public Builder addAbbreviations(ImmutableSet qualifiedNames) { @CanIgnoreReturnValue public Builder addAlias(String alias, String qualifiedName) { aliasAs(AliasKind.ALIAS, qualifiedName, alias); + aliases.put(alias, qualifiedName); return this; } private void aliasAs(AliasKind kind, String qualifiedName, String alias) { validateAliasOrThrow(kind, qualifiedName, alias); - aliases.put(alias, qualifiedName); + aliasMap.put(alias, qualifiedName); } private void validateAliasOrThrow(AliasKind kind, String qualifiedName, String alias) { @@ -185,7 +196,7 @@ private void validateAliasOrThrow(AliasKind kind, String qualifiedName, String a String.format("qualified name must not begin with a leading '.': %s", qualifiedName)); } - String aliasRef = aliases.get(alias); + String aliasRef = aliasMap.get(alias); if (aliasRef != null) { throw new IllegalArgumentException( String.format( @@ -206,6 +217,8 @@ private void validateAliasOrThrow(AliasKind kind, String qualifiedName, String a @CheckReturnValue public CelContainer build() { + setAliasMap(ImmutableMap.copyOf(aliasMap)); + setAbbreviations(ImmutableList.copyOf(abbreviations)); setAliases(ImmutableMap.copyOf(aliases)); return autoBuild(); } @@ -263,7 +276,9 @@ public ImmutableSet resolveCandidateNames(String typeName) { public Builder toBuilder() { Builder builder = autoToBuilder(); + builder.aliasMap.putAll(aliasMap()); builder.aliases.putAll(aliases()); + builder.abbreviations.addAll(abbreviations()); return builder; } @@ -284,7 +299,7 @@ private Optional findAlias(String name) { simple = name.substring(0, dot); qualifier = name.substring(dot); } - String alias = aliases().get(simple); + String alias = aliasMap().get(simple); if (alias == null) { return Optional.empty(); } diff --git a/testing/src/test/resources/environment/dump_env.yaml b/testing/src/test/resources/environment/dump_env.yaml index 8f6829838..6a885ea51 100644 --- a/testing/src/test/resources/environment/dump_env.yaml +++ b/testing/src/test/resources/environment/dump_env.yaml @@ -14,7 +14,16 @@ name: dump_env description: dump_env description -container: test.container +container: + name: test.container + abbreviations: + - abbr1.Abbr1 + - abbr2.Abbr2 + aliases: + - alias: alias1 + qualified_name: qual.name1 + - alias: alias2 + qualified_name: qual.name2 extensions: - name: bindings - name: encoders