diff --git a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java index d8ba8c984c..d7f08dedf0 100644 --- a/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java +++ b/headless-services/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java @@ -11,6 +11,7 @@ package org.springframework.ide.vscode.commons.util; import java.util.Collection; +import java.util.Collections; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.function.Supplier; @@ -78,6 +79,11 @@ public Object parse(String str) throws Exception { throw errorOnParse(createErrorMessage(str, values.getElements())); } } + + protected final Collection getAllKnownValues() { + PartialCollection partialCollection = this.values.get(); + return partialCollection == null ? Collections.emptyList() : this.values.get().getElements(); + } protected boolean hasMatchingValue(String str, Collection values) { return values.contains(str); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java index 354a13888e..fe9d3a87b4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java @@ -44,6 +44,7 @@ import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint; import org.springframework.ide.vscode.boot.metadata.util.DeprecationUtil; import org.springframework.ide.vscode.boot.metadata.util.PropertyDocUtils; +import org.springframework.ide.vscode.boot.properties.reconcile.BootEnumValueParser; import org.springframework.ide.vscode.commons.java.Flags; import org.springframework.ide.vscode.commons.java.IField; import org.springframework.ide.vscode.commons.java.IJavaElement; @@ -55,7 +56,6 @@ import org.springframework.ide.vscode.commons.util.ArrayUtils; import org.springframework.ide.vscode.commons.util.Assert; import org.springframework.ide.vscode.commons.util.CollectionUtil; -import org.springframework.ide.vscode.commons.util.EnumValueParser; import org.springframework.ide.vscode.commons.util.LazyProvider; import org.springframework.ide.vscode.commons.util.MimeTypes; import org.springframework.ide.vscode.commons.util.Renderables; @@ -272,7 +272,7 @@ public ValueParser getValueParser(Type type) { //Note, technically if 'enumValues is empty array' this means something different // from when it is null. An empty array means a type that has no values, so // assigning anything to it is an error. - return new EnumValueParser(niceTypeName(type), getBareValues(enumValues)); + return new BootEnumValueParser(niceTypeName(type), getBareValues(enumValues)); } if (isMap(type)) { //Trying to parse map types from scalars is not possible. Thus we diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/BootEnumValueParser.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/BootEnumValueParser.java new file mode 100644 index 0000000000..bc9c901a2e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/BootEnumValueParser.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2025 Broadcom, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.properties.reconcile; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.ide.vscode.commons.util.EnumValueParser; +import org.springframework.ide.vscode.commons.util.StringUtil; + +/** + * Boot property values allow relaxed parsing via canonical names. + * + * @author Alex Boyko + */ +public class BootEnumValueParser extends EnumValueParser { + + private Set canonicalValues; + + private static String getCanonicalName(String name) { + StringBuilder canonicalName = new StringBuilder(name.length()); + name.chars() + .filter(Character::isLetterOrDigit) + .map(Character::toLowerCase) + .forEach((c) -> canonicalName.append((char) c)); + return canonicalName.toString(); + } + + public BootEnumValueParser(String typeName, String[] values) { + super(typeName, values); + this.canonicalValues = Arrays.stream(values).map(BootEnumValueParser::getCanonicalName).collect(Collectors.toSet()); + } + + @Override + public Object parse(String str) throws Exception { + // IMPORTANT: check the text FIRST before fetching values + // from the hints provider, as the hints provider may be expensive when + // resolving values + if (!StringUtil.hasText(str)) { + throw errorOnBlank(createBlankTextErrorMessage()); + } + + if (canonicalValues.contains(getCanonicalName(str))) { + return str; + } else { + throw errorOnParse(createErrorMessage(str, getAllKnownValues())); + } + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java index 69aa34d43d..414b7068b5 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java @@ -5014,6 +5014,7 @@ private void doCollectionOfEnumReconcileTest(String collectionType) throws Excep "my:\n" + " colors:\n" + " - red\n" + + " - r-e-d\n" + // Canonical name is "red" from "r-e-d" hence it is okay in Boot as well " - green\n" + " - BLUE\n" + " - not-a-color\n"