gnodet-bot commented on code in PR #26611:
URL: https://github.com/apache/camel/pull/26611#discussion_r4052676910
##########
core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java:
##########
@@ -2645,6 +2647,48 @@ private void setAiObservabilityProperties(
}
}
+ /**
+ * Creates a bean declared as <tt>#class:</tt> whose class has no public
no-arg constructor but a builder (such as a
+ * LangChain4j model or a Lombok class), by setting the properties of the
bean (dot style) on the builder before the
+ * bean is built, as such a bean cannot be configured after it is created.
+ *
+ * @return the created bean, or <tt>null</tt> if the bean is not created
via an inferred builder
+ */
+ private static Object createBeanViaInferredBuilder(
+ CamelContext camelContext, String name, Object value,
OrderedLocationProperties properties,
+ String optionPrefix, boolean failIfNotSet, boolean ignoreCase,
+ OrderedLocationProperties autoConfiguredProperties)
+ throws Exception {
+ if (!(value instanceof String text) || !text.startsWith("#class:")) {
+ return null;
+ }
+ String className =
camelContext.resolvePropertyPlaceholders(text.substring(7));
+ if (className.indexOf('#') != -1 || className.indexOf('(') != -1) {
+ // a factory method or constructor arguments say how to create the
bean
+ return null;
+ }
+ Class<?> type =
camelContext.getClassResolver().resolveMandatoryClass(className);
+ Object builder = PropertyBindingSupport.newBuilderInstance(type);
+ if (builder == null) {
+ return null;
+ }
+ String bm = PropertyBindingSupport.findBuilderMethod(builder, type,
null);
+ OrderedLocationProperties config =
MainHelper.extractProperties(properties, name + ".");
+ if (!config.isEmpty()) {
+ // the properties are set on the builder (and reported as
configured on the bean)
+ try {
+ MainHelper.setPropertiesOnTarget(camelContext, builder,
config, optionPrefix + name + ".", failIfNotSet,
+ ignoreCase, autoConfiguredProperties);
+ } catch (PropertyBindingException e) {
+ // the property names of a builder are not those of the bean,
so name what the builder accepts
+ throw new IllegalArgumentException(
+ e.getMessage() + ". " +
BeanModelHelper.builderPropertiesHint(builder, type), e);
Review Comment:
🐛 **Setter-only properties silently dropped (or fail) in the `camel.beans.*`
path.**
`createBeanViaInferredBuilder` extracts all `name.*` keys from `properties`
and passes them to `MainHelper.setPropertiesOnTarget` with the **builder** as
target. If a property is accepted by the bean's setter but not by the builder's
fluent method (like `label` in the `BeanModelHelper` test's `ChatModel`), two
outcomes are possible:
- With `isAutoConfigurationFailFast()=true` (default):
`PropertyBindingException` is thrown — the property is rejected even though the
bean would accept it.
- With `failFast=false`: the property is silently dropped — never set on
builder, never set on the created bean, because the keys were already consumed
by `extractProperties`.
The `BeanModelHelper` path handles this correctly via
`setRemainingProperties`, which sets builder-rejected properties on the created
bean. The `camel.beans.*` path has no equivalent fallback.
Minimal fix — after the builder call, set leftover properties on the created
bean:
```suggestion
LOG.debug("Creating bean: {} of type: {} via builder: {} ({})",
name, className, builder.getClass().getName(), bm);
Object bean =
org.apache.camel.support.ObjectHelper.invokeMethodSafe(bm, builder);
if (!config.isEmpty()) {
// properties the builder did not take may still be accepted by
the bean (e.g. post-build setters)
MainHelper.setPropertiesOnTarget(camelContext, bean, config,
optionPrefix + name + ".",
failIfNotSet, ignoreCase, autoConfiguredProperties);
}
return bean;
```
Note: `config` retains any entries `setPropertiesOnTarget` could not bind on
the builder only if the binding was done with `removeParameters=false`. The
current call uses `MainHelper.setPropertiesOnTarget` which may or may not
remove on success — confirm `config` is mutable and tracks unset keys, then
apply the remaining on the bean.
At minimum: add a test in `MainBeansInferredBuilderTest` that exercises a
setter-only property (not on the builder, only on the bean) to document — and
enforce — the intended behaviour.
--
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]