diff --git a/spring-vault-core/src/main/java/org/springframework/vault/annotation/PropertyMapping.java b/spring-vault-core/src/main/java/org/springframework/vault/annotation/PropertyMapping.java new file mode 100644 index 00000000..737eb19a --- /dev/null +++ b/spring-vault-core/src/main/java/org/springframework/vault/annotation/PropertyMapping.java @@ -0,0 +1,23 @@ +package org.springframework.vault.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that specifies how to map property names received from Vault to Spring environment. + */ +@Target({}) +@Retention(RetentionPolicy.RUNTIME) +public @interface PropertyMapping { + + /** + * Property name received from Vault. + */ + String from(); + + /** + * Property name to be set to Spring environment. + */ + String to(); +} diff --git a/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySource.java b/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySource.java index 245259bc..b5e20309 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySource.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySource.java @@ -15,6 +15,8 @@ */ package org.springframework.vault.annotation; +import org.springframework.context.annotation.Import; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; @@ -22,8 +24,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.springframework.context.annotation.Import; - /** * Annotation providing a convenient and declarative mechanism for adding a * {@link VaultPropertySource} to Spring's {@link org.springframework.core.env.Environment @@ -113,6 +113,11 @@ */ Renewal renewal() default Renewal.OFF; + /** + * Specify property names mapping from Vault to Spring environment. + */ + PropertyMapping[] propertyMappings() default {}; + enum Renewal { /** diff --git a/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySourceRegistrar.java b/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySourceRegistrar.java index 34304d32..6c312892 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySourceRegistrar.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/annotation/VaultPropertySourceRegistrar.java @@ -15,14 +15,7 @@ */ package org.springframework.vault.annotation; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - import org.jspecify.annotations.Nullable; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -45,6 +38,13 @@ import org.springframework.vault.core.util.PropertyTransformer; import org.springframework.vault.core.util.PropertyTransformers; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + /** * Registrar to register {@link org.springframework.vault.core.env.VaultPropertySource}s * based on {@link VaultPropertySource}. @@ -121,6 +121,7 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD String propertyNamePrefix = propertySource.getString("propertyNamePrefix"); Renewal renewal = propertySource.getEnum("renewal"); boolean ignoreSecretNotFound = propertySource.getBoolean("ignoreSecretNotFound"); + PropertyMapping[] propertyMappings = propertySource.getAnnotationArray("propertyMappings", PropertyMapping.class); Assert.isTrue(paths.length > 0, "At least one @VaultPropertySource(value) location is required"); @@ -129,6 +130,10 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD PropertyTransformer propertyTransformer = StringUtils.hasText(propertyNamePrefix) ? PropertyTransformers.propertyNamePrefix(propertyNamePrefix) : PropertyTransformers.noop(); + if (propertyMappings.length != 0) { + propertyTransformer = propertyTransformer.andThen(createMappingRulesBasedPropertyTransformer(propertyMappings)); + } + for (String propertyPath : paths) { if (!StringUtils.hasText(propertyPath)) { @@ -154,6 +159,16 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD } } + private PropertyTransformer createMappingRulesBasedPropertyTransformer(PropertyMapping[] mappings) { + Map rules = new HashMap<>(); + + for (PropertyMapping mapping : mappings) { + rules.put(mapping.from(), mapping.to()); + } + + return PropertyTransformers.mappingRulesBased(rules); + } + private String potentiallyResolveRequiredPlaceholders(String expression) { return this.environment != null ? this.environment.resolveRequiredPlaceholders(expression) : expression; } diff --git a/spring-vault-core/src/main/java/org/springframework/vault/core/util/PropertyTransformers.java b/spring-vault-core/src/main/java/org/springframework/vault/core/util/PropertyTransformers.java index 6edef8e4..fba4b1a8 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/core/util/PropertyTransformers.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/core/util/PropertyTransformers.java @@ -15,12 +15,12 @@ */ package org.springframework.vault.core.util; +import org.springframework.util.Assert; + import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; -import org.springframework.util.Assert; - /** * Implementations of {@link PropertyTransformer} that provide various useful property * transformation operations, prefixing, etc. @@ -53,6 +53,14 @@ public static PropertyTransformer propertyNamePrefix(String propertyNamePrefix) return KeyPrefixPropertyTransformer.forPrefix(propertyNamePrefix); } + /** + * @param mappingRules the rules to remap property names. + * @return {@link PropertyTransformer} to map property names as specified in mappings. + */ + public static PropertyTransformer mappingRulesBased(Map mappingRules) { + return MappingRulesBasedPropertyTransformer.forMappingRules(mappingRules); + } + /** * {@link PropertyTransformer} that passes the given properties through without * returning changed properties. @@ -159,4 +167,39 @@ public Map transformProperties(Map inp } + /** + * {@link PropertyTransformer} that maps property names based on specified mapping rules. + * Properties, not present in mapping rules, will not be remapped and will stay as is. + */ + public static class MappingRulesBasedPropertyTransformer implements PropertyTransformer { + + private final Map mappingRules; + + private MappingRulesBasedPropertyTransformer(Map mappingRules) { + this.mappingRules = mappingRules; + } + + /** + * Create a new {@link MappingRulesBasedPropertyTransformer} that maps property names as specified in mappings. + * @param mappingRules the property mapping rules. + * @return a new {@link MappingRulesBasedPropertyTransformer}. + */ + public static PropertyTransformer forMappingRules(Map mappingRules) { + return new MappingRulesBasedPropertyTransformer(mappingRules); + } + + @Override + public Map transformProperties(Map input) { + + Map target = new LinkedHashMap<>(input.size(), 1); + + for (Entry entry : input.entrySet()) { + String newKey = this.mappingRules.getOrDefault(entry.getKey(), entry.getKey()); + target.put(newKey, entry.getValue()); + } + + return target; + } + + } }