Croway commented on PR #1995:
URL: 
https://github.com/apache/camel-spring-boot/pull/1995#issuecomment-5811190708

   Hi @smongiar, thanks for looking into this. I tried to reproduce the startup 
failure before reviewing the fix, and I couldn't get it in the case the 
description mentions. Could you share the exact stack trace and the 
`camel.component.salesforce.*` properties (or env vars) your app uses?
   
   **Reproducer.** On current `main` (Spring Boot 4.1.1, Jackson 2.22.2), I 
started the salesforce starter with different extra properties. I then ran the 
same test with this PR's generator built in the same Maven run:
   
   | Extra property (`camel.component.salesforce.` …) | `main` | With this PR |
   |---|---|---|
   | *(none, the case in the description)* | starts | starts |
   | `config.api-version=62.0` | starts, apiVersion=62.0 | starts, **value 
silently dropped** |
   | `object-mapper=#bean:myMapper` | starts, bean injected | starts, bean 
injected |
   | `config.object-mapper=#bean:myMapper` | starts, bean injected | starts, 
**value silently dropped** |
   | `config.object-mapper.serializer-provider.generator.write-capabilities=x` 
| fails: `Failed to bind … to JacksonFeatureSet<StreamWriteCapability>` | 
starts, key ignored |
   | `config.object-mapper.property-naming-strategy=x` | fails: 
`ConverterNotFoundException … PropertyNamingStrategy` | starts, key ignored |
   
   So the `JacksonFeatureSet` error only shows up when a property key points 
inside the `ObjectMapper`'s own internals. When nothing is set, the context 
starts fine, and the existing `SalesforceComponentTest` on `main` already 
covers that.
   
   **Concerns with the current approach**
   1. Changing every non-enum `object` option to `String` breaks nested 
binding. `config.*`, `login-config.*`, `approval.*` (salesforce) and 
`http-configuration.*` (http) are no longer bound. Spring Boot ignores unknown 
fields by default, so the app still starts and the values are silently lost.
   2. It also applies to every `duration` option. For example, `Long 
backoffIncrement = 1000L` becomes `String backoffIncrement = "1000"`. That 
changes public getters/setters and the configuration metadata type across all 
starters.
   3. Only http and salesforce were regenerated. A full regeneration would also 
break handwritten code such as `ReactiveStreamsServiceAutoConfiguration`, which 
reads `getReactiveStreamsEngineConfiguration()` as a typed object.
   4. `SalesforceObjectMapperBindingTest` is annotated `@SpringBootApplication` 
in the same package as `SalesforceComponentTest`. It fails with `Found multiple 
@SpringBootConfiguration annotated classes`, so it doesn't test the fix.
   
   If there's a real trigger we're missing, for example a specific property, an 
env var, or the actuator `/configprops` endpoint, a narrower fix would be 
better. That would mean only stopping Spring Boot from binding into the 
`ObjectMapper`-typed options, instead of changing the generator for every 
component. If there isn't one, I'd suggest closing this PR.
   
   <details><summary>Reproducer test (drop into 
<code>components-starter/camel-salesforce-starter/src/test/java/org/apache/camel/component/salesforce/springboot/</code>)</summary>
   
   ```java
   package org.apache.camel.component.salesforce.springboot;
   
   import java.util.ArrayList;
   import java.util.List;
   
   import com.fasterxml.jackson.databind.ObjectMapper;
   import org.apache.camel.CamelContext;
   import org.apache.camel.component.salesforce.SalesforceComponent;
   import org.junit.jupiter.params.ParameterizedTest;
   import org.junit.jupiter.params.provider.ValueSource;
   import org.springframework.boot.WebApplicationType;
   import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
   import org.springframework.boot.builder.SpringApplicationBuilder;
   import org.springframework.context.ConfigurableApplicationContext;
   import org.springframework.context.annotation.Bean;
   import org.springframework.context.annotation.Configuration;
   
   /**
    * Reproducer for apache/camel-spring-boot#1995: does binding 
SalesforceComponentConfiguration fail on Spring Boot 4.1.1
    * / Jackson 2.2x because of the ObjectMapper-typed fields?
    */
   public class SalesforceObjectMapperBindingReproducerTest {
   
       private static final String BASE = "camel.component.salesforce.";
   
       @ParameterizedTest
       @ValueSource(strings = {
               "",                                                     // 
nothing object-mapper related (PR claim)
               "config.api-version=62.0",                              // 
descend into SalesforceEndpointConfig
               "object-mapper=#bean:myMapper",                         // bean 
reference, top level
               "config.object-mapper=#bean:myMapper",                  // bean 
reference, nested
               "object-mapper.serializer-provider.foo=bar",            // 
descend into ObjectMapper itself
               "config.object-mapper.serializer-provider.foo=bar",
               
"config.object-mapper.serializer-provider.generator.write-capabilities=x",
               "config.object-mapper.property-naming-strategy=x" })
       void startup(String extra) {
           List<String> props = new ArrayList<>(List.of(
                   "--" + BASE + "client-id=myClient", "--" + BASE + 
"client-secret=mySecret",
                   "--" + BASE + "refresh-token=myToken", "--" + BASE + 
"lazy-login=true"));
           if (!extra.isEmpty()) {
               props.add("--" + BASE + extra);
           }
           try (ConfigurableApplicationContext ctx = new 
SpringApplicationBuilder(App.class)
                   
.web(WebApplicationType.NONE).run(props.toArray(String[]::new))) {
               SalesforceComponent sf = 
ctx.getBean(CamelContext.class).getComponent("salesforce", 
SalesforceComponent.class);
               System.out.println("REPRO [" + extra + "] -> STARTED, 
config.objectMapper=" + (sf.getConfig() == null ? "n/a (no config)" : 
sf.getConfig().getObjectMapper())
                                  + ", config.apiVersion=" + (sf.getConfig() == 
null ? "n/a" : sf.getConfig().getApiVersion()));
           } catch (Exception e) {
               Throwable root = e;
               while (root.getCause() != null) {
                   root = root.getCause();
               }
               System.out.println("REPRO [" + extra + "] -> FAILED " + 
e.getClass().getSimpleName() + ": " + e.getMessage()
                                  + " | root: " + root);
           }
       }
   
       @Configuration
       @EnableAutoConfiguration
       static class App {
           @Bean
           ObjectMapper myMapper() {
               return new ObjectMapper();
           }
       }
   }
   ```
   
   To test with this PR, the generator has to be built in the same Maven run, 
otherwise the starter regenerates from the plugin already in `~/.m2`:
   `mvn verify -pl 
tooling/camel-spring-boot-generator-maven-plugin,components-starter/camel-salesforce-starter
 -Dtest=SalesforceObjectMapperBindingReproducerTest 
-Dsurefire.failIfNoSpecifiedTests=false`
   </details>
   
   _Claude Code on behalf of Croway_
   


-- 
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