From 2393b5de9125330ae40d8de243c3031f68aded82 Mon Sep 17 00:00:00 2001 From: "l.makhnorylov" Date: Mon, 24 Nov 2025 17:51:21 +0200 Subject: [PATCH 1/3] impl vault property source additional property transformers Signed-off-by: l.makhnorylov --- .../vault/annotation/VaultPropertySource.java | 7 ++++++ .../VaultPropertySourceRegistrar.java | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+) 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..d1bef4dc 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 @@ -23,6 +23,7 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Import; +import org.springframework.vault.core.util.PropertyTransformer; /** * Annotation providing a convenient and declarative mechanism for adding a @@ -113,6 +114,12 @@ */ Renewal renewal() default Renewal.OFF; + /** + * Specify additional property transformer classes + * {@link org.springframework.vault.core.util.PropertyTransformer}. + */ + Class[] propertyTransformers() 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..b43d9a18 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 @@ -39,6 +39,7 @@ import org.springframework.core.env.PropertySource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import org.springframework.vault.annotation.VaultPropertySource.Renewal; import org.springframework.vault.core.lease.domain.RequestedSecret; @@ -121,6 +122,7 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD String propertyNamePrefix = propertySource.getString("propertyNamePrefix"); Renewal renewal = propertySource.getEnum("renewal"); boolean ignoreSecretNotFound = propertySource.getBoolean("ignoreSecretNotFound"); + Class[] additionalPropertyTransformers = propertySource.getClassArray("propertyTransformers"); Assert.isTrue(paths.length > 0, "At least one @VaultPropertySource(value) location is required"); @@ -129,6 +131,10 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD PropertyTransformer propertyTransformer = StringUtils.hasText(propertyNamePrefix) ? PropertyTransformers.propertyNamePrefix(propertyNamePrefix) : PropertyTransformers.noop(); + if (additionalPropertyTransformers.length != 0) { + propertyTransformer = appendPropertyTransformers(propertyTransformer, additionalPropertyTransformers); + } + for (String propertyPath : paths) { if (!StringUtils.hasText(propertyPath)) { @@ -154,6 +160,22 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD } } + private PropertyTransformer appendPropertyTransformers(PropertyTransformer propertyTransformer, + Class[] additionalPropertyTransformers) { + for (Class propertyTransformerClass : additionalPropertyTransformers) { + propertyTransformer = propertyTransformer.andThen(createPropertyTransformer(propertyTransformerClass)); + } + return propertyTransformer; + } + + private PropertyTransformer createPropertyTransformer(Class cls) { + try { + return (PropertyTransformer) ReflectionUtils.accessibleConstructor(cls).newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Could not create property transformer " + cls.getName(), e); + } + } + private String potentiallyResolveRequiredPlaceholders(String expression) { return this.environment != null ? this.environment.resolveRequiredPlaceholders(expression) : expression; } From ce8f0eec1b71539b7357982fafc4854a59b16eaa Mon Sep 17 00:00:00 2001 From: "l.makhnorylov" Date: Sat, 6 Dec 2025 16:41:29 +0200 Subject: [PATCH 2/3] implement PropertyMappingBasedPropertyTransformer --- .../vault/annotation/PropertyMapping.java | 23 ++++++++ .../vault/annotation/VaultPropertySource.java | 10 ++-- .../VaultPropertySourceRegistrar.java | 36 +++--------- .../vault/core/util/PropertyTransformers.java | 57 ++++++++++++++++++- 4 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 spring-vault-core/src/main/java/org/springframework/vault/annotation/PropertyMapping.java 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 d1bef4dc..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,9 +24,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.springframework.context.annotation.Import; -import org.springframework.vault.core.util.PropertyTransformer; - /** * Annotation providing a convenient and declarative mechanism for adding a * {@link VaultPropertySource} to Spring's {@link org.springframework.core.env.Environment @@ -115,10 +114,9 @@ Renewal renewal() default Renewal.OFF; /** - * Specify additional property transformer classes - * {@link org.springframework.vault.core.util.PropertyTransformer}. + * Specify property names mapping from Vault to Spring environment. */ - Class[] propertyTransformers() default {}; + 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 b43d9a18..8cc1fb5f 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; @@ -39,13 +32,18 @@ import org.springframework.core.env.PropertySource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; import org.springframework.vault.annotation.VaultPropertySource.Renewal; import org.springframework.vault.core.lease.domain.RequestedSecret; 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.LinkedHashSet; +import java.util.Map; +import java.util.Set; + /** * Registrar to register {@link org.springframework.vault.core.env.VaultPropertySource}s * based on {@link VaultPropertySource}. @@ -122,7 +120,7 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD String propertyNamePrefix = propertySource.getString("propertyNamePrefix"); Renewal renewal = propertySource.getEnum("renewal"); boolean ignoreSecretNotFound = propertySource.getBoolean("ignoreSecretNotFound"); - Class[] additionalPropertyTransformers = propertySource.getClassArray("propertyTransformers"); + PropertyMapping[] propertyMappings = propertySource.getAnnotationArray("propertyMappings", PropertyMapping.class); Assert.isTrue(paths.length > 0, "At least one @VaultPropertySource(value) location is required"); @@ -131,8 +129,8 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD PropertyTransformer propertyTransformer = StringUtils.hasText(propertyNamePrefix) ? PropertyTransformers.propertyNamePrefix(propertyNamePrefix) : PropertyTransformers.noop(); - if (additionalPropertyTransformers.length != 0) { - propertyTransformer = appendPropertyTransformers(propertyTransformer, additionalPropertyTransformers); + if (propertyMappings.length != 0) { + propertyTransformer = propertyTransformer.andThen(PropertyTransformers.propertyMappingBased(propertyMappings)); } for (String propertyPath : paths) { @@ -160,22 +158,6 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD } } - private PropertyTransformer appendPropertyTransformers(PropertyTransformer propertyTransformer, - Class[] additionalPropertyTransformers) { - for (Class propertyTransformerClass : additionalPropertyTransformers) { - propertyTransformer = propertyTransformer.andThen(createPropertyTransformer(propertyTransformerClass)); - } - return propertyTransformer; - } - - private PropertyTransformer createPropertyTransformer(Class cls) { - try { - return (PropertyTransformer) ReflectionUtils.accessibleConstructor(cls).newInstance(); - } catch (Exception e) { - throw new IllegalStateException("Could not create property transformer " + cls.getName(), e); - } - } - 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..944ab4a3 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,15 @@ */ package org.springframework.vault.core.util; +import org.springframework.util.Assert; +import org.springframework.vault.annotation.PropertyMapping; + +import java.util.Collections; +import java.util.HashMap; 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 +56,14 @@ public static PropertyTransformer propertyNamePrefix(String propertyNamePrefix) return KeyPrefixPropertyTransformer.forPrefix(propertyNamePrefix); } + /** + * @param mappings the rules to remap property names. + * @return {@link PropertyTransformer} to map property names as specified in mappings. + */ + public static PropertyTransformer propertyMappingBased(PropertyMapping[] mappings) { + return PropertyMappingBasedPropertyTransformer.forPropertyMappings(mappings); + } + /** * {@link PropertyTransformer} that passes the given properties through without * returning changed properties. @@ -159,4 +170,46 @@ public Map transformProperties(Map inp } + /** + * {@link PropertyTransformer} based on {@link org.springframework.vault.annotation.PropertyMapping} annotaion rules. + */ + public static class PropertyMappingBasedPropertyTransformer implements PropertyTransformer { + + private final Map mappingRules; + + private PropertyMappingBasedPropertyTransformer(PropertyMapping[] mappings) { + + Map mappingRules = new HashMap<>(); + + for (PropertyMapping propertyMapping : mappings) { + mappingRules.put(propertyMapping.from(), propertyMapping.to()); + } + + this.mappingRules = Collections.unmodifiableMap(mappingRules); + } + + /** + * Create a new {@link PropertyMappingBasedPropertyTransformer} that maps property names as specified in mappings. + * @param mappings the property mapping rules. + * If key does not exist in input properties, property name will not be remapped + * @return a new {@link PropertyMappingBasedPropertyTransformer}. + */ + public static PropertyTransformer forPropertyMappings(PropertyMapping[] mappings) { + return new PropertyMappingBasedPropertyTransformer(mappings); + } + + @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; + } + + } } From 67cc3beb468b7a02d34ef4a5000964f42e6bf276 Mon Sep 17 00:00:00 2001 From: "l.makhnorylov" Date: Mon, 8 Dec 2025 15:24:14 +0200 Subject: [PATCH 3/3] untie PropertyTransformers from @PropertyMapping --- .../VaultPropertySourceRegistrar.java | 13 ++++++- .../vault/core/util/PropertyTransformers.java | 36 +++++++------------ 2 files changed, 25 insertions(+), 24 deletions(-) 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 8cc1fb5f..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 @@ -40,6 +40,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -130,7 +131,7 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD ? PropertyTransformers.propertyNamePrefix(propertyNamePrefix) : PropertyTransformers.noop(); if (propertyMappings.length != 0) { - propertyTransformer = propertyTransformer.andThen(PropertyTransformers.propertyMappingBased(propertyMappings)); + propertyTransformer = propertyTransformer.andThen(createMappingRulesBasedPropertyTransformer(propertyMappings)); } for (String propertyPath : paths) { @@ -158,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 944ab4a3..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 @@ -16,10 +16,7 @@ package org.springframework.vault.core.util; import org.springframework.util.Assert; -import org.springframework.vault.annotation.PropertyMapping; -import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; @@ -57,11 +54,11 @@ public static PropertyTransformer propertyNamePrefix(String propertyNamePrefix) } /** - * @param mappings the rules to remap property names. + * @param mappingRules the rules to remap property names. * @return {@link PropertyTransformer} to map property names as specified in mappings. */ - public static PropertyTransformer propertyMappingBased(PropertyMapping[] mappings) { - return PropertyMappingBasedPropertyTransformer.forPropertyMappings(mappings); + public static PropertyTransformer mappingRulesBased(Map mappingRules) { + return MappingRulesBasedPropertyTransformer.forMappingRules(mappingRules); } /** @@ -171,31 +168,24 @@ public Map transformProperties(Map inp } /** - * {@link PropertyTransformer} based on {@link org.springframework.vault.annotation.PropertyMapping} annotaion rules. + * {@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 PropertyMappingBasedPropertyTransformer implements PropertyTransformer { + public static class MappingRulesBasedPropertyTransformer implements PropertyTransformer { private final Map mappingRules; - private PropertyMappingBasedPropertyTransformer(PropertyMapping[] mappings) { - - Map mappingRules = new HashMap<>(); - - for (PropertyMapping propertyMapping : mappings) { - mappingRules.put(propertyMapping.from(), propertyMapping.to()); - } - - this.mappingRules = Collections.unmodifiableMap(mappingRules); + private MappingRulesBasedPropertyTransformer(Map mappingRules) { + this.mappingRules = mappingRules; } /** - * Create a new {@link PropertyMappingBasedPropertyTransformer} that maps property names as specified in mappings. - * @param mappings the property mapping rules. - * If key does not exist in input properties, property name will not be remapped - * @return a new {@link PropertyMappingBasedPropertyTransformer}. + * 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 forPropertyMappings(PropertyMapping[] mappings) { - return new PropertyMappingBasedPropertyTransformer(mappings); + public static PropertyTransformer forMappingRules(Map mappingRules) { + return new MappingRulesBasedPropertyTransformer(mappingRules); } @Override