From 094304bdda608b3a273094d20474a8d3b92a3b29 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Mon, 31 Mar 2025 16:41:19 +0200 Subject: [PATCH] GH-1494: include prefix in config property names Fixes GH-1494 --- ...ConfigurationPropertiesSymbolProvider.java | 41 +++++++++++++++---- ...ingIndexerConfigurationPropertiesTest.java | 12 +++--- .../ConfigurationPropertiesExample.java | 2 +- ...iesExampleWithConfigurationAnnotation.java | 2 +- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ConfigurationPropertiesSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ConfigurationPropertiesSymbolProvider.java index 30b6e3f4e..490768424 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ConfigurationPropertiesSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ConfigurationPropertiesSymbolProvider.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -41,6 +42,7 @@ import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider; import org.springframework.ide.vscode.boot.java.utils.ASTUtils; import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint; @@ -84,7 +86,7 @@ public class ConfigurationPropertiesSymbolProvider implements SymbolProvider { if (!isComponentAnnotated) { String beanName = BeanUtils.getBeanNameFromType(type.getName().getFullyQualifiedName()); - Location location = new Location(doc.getUri(), doc.toRange(type.getStartPosition(), type.getLength())); + Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength())); WorkspaceSymbol symbol = new WorkspaceSymbol( ComponentSymbolProvider.beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, typeBinding.getName()), SymbolKind.Interface, @@ -107,7 +109,7 @@ public class ConfigurationPropertiesSymbolProvider implements SymbolProvider { .toArray(AnnotationMetadata[]::new); Bean beanDefinition = new Bean(beanName, typeBinding.getQualifiedName(), location, injectionPoints, supertypes, annotations, isConfiguration, symbol.getName()); - + indexConfigurationProperties(beanDefinition, type, context, doc); context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), symbol)); @@ -116,15 +118,38 @@ public class ConfigurationPropertiesSymbolProvider implements SymbolProvider { } public static void indexConfigurationProperties(Bean beanDefinition, AbstractTypeDeclaration abstractType, SpringIndexerJavaContext context, TextDocument doc) { + Optional prefixValue = Arrays.stream(beanDefinition.getAnnotations()) + .filter(annotation -> Annotations.CONFIGURATION_PROPERTIES.equals(annotation.getAnnotationType())) + .flatMap(annotation -> Arrays.stream(getPrefix(annotation))) + .map(attribute -> attribute.getName()) + .findFirst(); + + String prefix = ""; + if (prefixValue.isPresent()) { + prefix = prefixValue.get() + "."; + } + if (abstractType instanceof TypeDeclaration type) { - indexConfigurationPropertiesForType(beanDefinition, type, context, doc); + indexConfigurationPropertiesForType(beanDefinition, type, context, doc, prefix); } else if (abstractType instanceof RecordDeclaration record) { - indexConfigurationPropertiesForRecord(beanDefinition, record, context, doc); + indexConfigurationPropertiesForRecord(beanDefinition, record, context, doc, prefix); + } + } + + private static AnnotationAttributeValue[] getPrefix(AnnotationMetadata annotation) { + if (annotation.getAttributes().containsKey("prefix")) { + return annotation.getAttributes().get("prefix"); + } + else if (annotation.getAttributes().containsKey("value")) { + return annotation.getAttributes().get("value"); + } + else { + return new AnnotationAttributeValue[0]; } } - public static void indexConfigurationPropertiesForType(Bean beanDefinition, TypeDeclaration type, SpringIndexerJavaContext context, TextDocument doc) { + public static void indexConfigurationPropertiesForType(Bean beanDefinition, TypeDeclaration type, SpringIndexerJavaContext context, TextDocument doc, String prefix) { FieldDeclaration[] fields = type.getFields(); if (fields != null) { @@ -143,7 +168,7 @@ public class ConfigurationPropertiesSymbolProvider implements SymbolProvider { DocumentRegion nodeRegion = ASTUtils.nodeRegion(doc, field); Range range = doc.toRange(nodeRegion); - ConfigPropertyIndexElement configPropElement = new ConfigPropertyIndexElement(name.getFullyQualifiedName(), fieldType.resolveBinding().getQualifiedName(), range); + ConfigPropertyIndexElement configPropElement = new ConfigPropertyIndexElement(prefix + name.getFullyQualifiedName(), fieldType.resolveBinding().getQualifiedName(), range); beanDefinition.addChild(configPropElement); } @@ -157,7 +182,7 @@ public class ConfigurationPropertiesSymbolProvider implements SymbolProvider { } - public static void indexConfigurationPropertiesForRecord(Bean beanDefinition, RecordDeclaration record, SpringIndexerJavaContext context, TextDocument doc) { + public static void indexConfigurationPropertiesForRecord(Bean beanDefinition, RecordDeclaration record, SpringIndexerJavaContext context, TextDocument doc, String prefix) { @SuppressWarnings("unchecked") List fields = record.recordComponents(); @@ -173,7 +198,7 @@ public class ConfigurationPropertiesSymbolProvider implements SymbolProvider { DocumentRegion nodeRegion = ASTUtils.nodeRegion(doc, field); Range range = doc.toRange(nodeRegion); - ConfigPropertyIndexElement configPropElement = new ConfigPropertyIndexElement(name.getFullyQualifiedName(), fieldType.resolveBinding().getQualifiedName(), range); + ConfigPropertyIndexElement configPropElement = new ConfigPropertyIndexElement(prefix + name.getFullyQualifiedName(), fieldType.resolveBinding().getQualifiedName(), range); beanDefinition.addChild(configPropElement); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringIndexerConfigurationPropertiesTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringIndexerConfigurationPropertiesTest.java index 12fd9d1e1..c7e5e8502 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringIndexerConfigurationPropertiesTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringIndexerConfigurationPropertiesTest.java @@ -80,7 +80,7 @@ public class SpringIndexerConfigurationPropertiesTest { assertEquals(1, children.size()); ConfigPropertyIndexElement configPropElement = (ConfigPropertyIndexElement) children.get(0); - assertEquals("simpleConfigProp", configPropElement.getName()); + assertEquals("com.example.config.prefix.simple.simpleConfigProp", configPropElement.getName()); assertEquals("java.lang.String", configPropElement.getType()); } @@ -98,7 +98,7 @@ public class SpringIndexerConfigurationPropertiesTest { assertEquals(1, children.size()); ConfigPropertyIndexElement configPropElement = (ConfigPropertyIndexElement) children.get(0); - assertEquals("simpleConfigProp", configPropElement.getName()); + assertEquals("com.example.config.prefix.simple2.simpleConfigProp", configPropElement.getName()); assertEquals("java.lang.String", configPropElement.getType()); } @@ -116,11 +116,11 @@ public class SpringIndexerConfigurationPropertiesTest { assertEquals(2, children.size()); ConfigPropertyIndexElement configPropElement1 = (ConfigPropertyIndexElement) children.get(0); - assertEquals("name", configPropElement1.getName()); + assertEquals("com.example.config.record.prefix.name", configPropElement1.getName()); assertEquals("java.lang.String", configPropElement1.getType()); ConfigPropertyIndexElement configPropElement2 = (ConfigPropertyIndexElement) children.get(1); - assertEquals("duration", configPropElement2.getName()); + assertEquals("com.example.config.record.prefix.duration", configPropElement2.getName()); assertEquals("int", configPropElement2.getType()); } @@ -138,11 +138,11 @@ public class SpringIndexerConfigurationPropertiesTest { assertEquals(2, children.size()); ConfigPropertyIndexElement configPropElement1 = (ConfigPropertyIndexElement) children.get(0); - assertEquals("name", configPropElement1.getName()); + assertEquals("com.example.config.record.prefix2.name", configPropElement1.getName()); assertEquals("java.lang.String", configPropElement1.getType()); ConfigPropertyIndexElement configPropElement2 = (ConfigPropertyIndexElement) children.get(1); - assertEquals("duration", configPropElement2.getName()); + assertEquals("com.example.config.record.prefix2.duration", configPropElement2.getName()); assertEquals("int", configPropElement2.getType()); } diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExample.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExample.java index e36c4e54d..2757fd1d3 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExample.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExample.java @@ -2,7 +2,7 @@ package com.example.configproperties; import org.springframework.boot.context.properties.ConfigurationProperties; -@ConfigurationProperties(prefix = "com.example.config.prefix.simple") +@ConfigurationProperties("com.example.config.prefix.simple") public class ConfigurationPropertiesExample { private String simpleConfigProp = "default config value"; diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExampleWithConfigurationAnnotation.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExampleWithConfigurationAnnotation.java index 2b6dc11ae..746bb7220 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExampleWithConfigurationAnnotation.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-configuration-properties-indexing/src/main/java/com/example/configproperties/ConfigurationPropertiesExampleWithConfigurationAnnotation.java @@ -4,7 +4,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration -@ConfigurationProperties(prefix = "com.example.config.prefix.simple2") +@ConfigurationProperties(value = "com.example.config.prefix.simple2") public class ConfigurationPropertiesExampleWithConfigurationAnnotation { private String simpleConfigProp = "default config value";