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]