davsclaus commented on code in PR #1907:
URL: 
https://github.com/apache/camel-spring-boot/pull/1907#discussion_r3891922724


##########
components-starter/camel-jasypt-starter/src/main/java/org/apache/camel/component/jasypt/springboot/SpringBootJasyptPropertiesParser.java:
##########
@@ -70,14 +70,19 @@ public void 
onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
             for (PropertySource mutablePropertySources : 
event.getEnvironment().getPropertySources()) {
                 if (mutablePropertySources instanceof MapPropertySource 
mapPropertySource) {
                     mapPropertySource.getSource().forEach((key, value) -> {
-                        if (value instanceof OriginTrackedValue 
originTrackedValue &&
-                                originTrackedValue.getValue() instanceof 
String stringValue &&
-                                
stringValue.startsWith(JasyptPropertiesParser.JASYPT_PREFIX_TOKEN) &&
-                                
stringValue.endsWith(JasyptPropertiesParser.JASYPT_SUFFIX_TOKEN)) {
+                        String stringValue = 
EarlyResolutionPropertySources.asString(value);

Review Comment:
   Behavior change beyond the stated precedence fix, worth confirming intent: 
before this PR, the Jasypt parser only matched `OriginTrackedValue`-wrapped 
values (there was no `else if (value instanceof String)` branch here, unlike 
the other vault parsers). Routing through 
`EarlyResolutionPropertySources.asString()` now also matches plain `String` 
values, so Jasypt will start early-decrypting values it previously ignored. 
Probably a reasonable consistency fix, but it's a second, unannounced behavior 
change riding along with the precedence fix — might be worth calling out 
explicitly in the PR description, or splitting out.



##########
core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/EarlyResolutionPropertySources.java:
##########
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.boot;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.springframework.boot.origin.OriginTrackedValue;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.PropertySource;
+
+/**
+ * Helpers for early property resolution listeners that inject a flat {@link 
Properties} override via
+ * {@code PropertySources.addFirst}.
+ * <p/>
+ * Spring iterates property sources in precedence order (highest first). When 
the same key appears in multiple
+ * sources, callers must retain the first resolved value so the override map 
reflects Spring's normal precedence
+ * after it is added with {@code addFirst}.
+ */
+public final class EarlyResolutionPropertySources {
+
+    private EarlyResolutionPropertySources() {
+    }
+
+    /**
+     * Returns the string value from a property source entry, including {@link 
OriginTrackedValue} wrappers.
+     */
+    public static String asString(Object value) {
+        if (value instanceof OriginTrackedValue originTrackedValue
+                && originTrackedValue.getValue() instanceof String 
stringValue) {
+            return stringValue;
+        }
+        if (value instanceof String stringValue) {
+            return stringValue;
+        }
+        return null;
+    }
+
+    /**
+     * Stores a resolved value only when the key is not already present, 
preserving highest-precedence values
+     * collected while iterating property sources.
+     */
+    public static void putIfAbsent(Properties props, Object key, String 
resolvedValue) {
+        props.putIfAbsent(key.toString(), resolvedValue);
+    }
+
+    /**
+     * Returns whether a property source with higher precedence defines the 
same key.
+     */
+    public static boolean hasHigherPrecedenceProperty(
+            Iterable<PropertySource<?>> propertySources, PropertySource<?> 
currentPropertySource, Object key) {
+        for (PropertySource<?> propertySource : propertySources) {
+            if (propertySource == currentPropertySource) {
+                return false;
+            }
+            if (propertySource instanceof MapPropertySource && 
propertySource.containsProperty(key.toString())) {

Review Comment:
   This only inspects `MapPropertySource` instances, matching the pre-existing 
scanning loop in each parser, so a higher-precedence non-map source (e.g. 
command-line args via `SimpleCommandLinePropertySource`, which is an 
`EnumerablePropertySource` but not a `MapPropertySource`) defining the same key 
won't be detected here. Not a new bug introduced by this PR, but now that this 
logic lives in a shared helper named for general precedence handling, it might 
be worth a one-line doc note on the limitation so a future caller doesn't 
assume it covers all `PropertySource` types.



##########
core/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/EarlyResolutionPropertySourcesTest.java:
##########
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.boot;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.origin.OriginTrackedValue;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class EarlyResolutionPropertySourcesTest {
+
+    @Test
+    void shouldExtractStringFromOriginTrackedValue() {
+        OriginTrackedValue tracked = OriginTrackedValue.of("{{vault:secret}}");
+        
assertThat(EarlyResolutionPropertySources.asString(tracked)).isEqualTo("{{vault:secret}}");
+    }
+
+    @Test
+    void shouldPreserveHighestPrecedenceValueForDuplicateKeys() {

Review Comment:
   This is the test closest to the scenario the JIRA asks for ("duplicate keys 
across property sources"), but it goes through 
`collectResolved`/`collectResolvedWithPrecedenceGuard`, a hand-rolled loop 
defined in this test file that mimics the parsers' `onApplicationEvent` logic — 
it doesn't exercise any of the actual parser implementations. None of the 8 
modified parsers has a test proving that two *matching placeholders* for the 
same key across precedence-ordered sources resolve to the highest-precedence 
one (the `SpringBootHashicorpVaultPropertiesParserPrecedenceTest` added in this 
PR covers a different case: a higher-precedence *plain* value suppressing a 
lower-precedence *unresolved* placeholder). Would be good to add at least one 
test that drives a real parser's `onApplicationEvent` with two placeholders for 
the same key to close that gap, matching what the ticket explicitly requested.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to