davsclaus commented on code in PR #26709: URL: https://github.com/apache/camel/pull/26709#discussion_r4068695939
########## core/camel-support/src/main/java/org/apache/camel/support/compile/BindToRegistryCompilePostProcessor.java: ########## @@ -0,0 +1,105 @@ +/* + * 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.support.compile; + +import java.util.function.Supplier; + +import org.apache.camel.BindToRegistry; +import org.apache.camel.CamelConfiguration; +import org.apache.camel.CamelContext; +import org.apache.camel.Configuration; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.spi.CamelBeanPostProcessor; +import org.apache.camel.spi.CompilePostProcessor; +import org.apache.camel.support.PluginHelper; +import org.apache.camel.util.ObjectHelper; + +/** + * Binds a compiled class annotated with {@link BindToRegistry} or {@link Configuration} (or that is a + * {@link CamelConfiguration}) to the registry, using the {@link CamelBeanPostProcessor} so the Camel dependency + * injection annotations on the class are processed as well. As the class may be compiled again (live reload) the + * previous bean is unbound first. + */ +public class BindToRegistryCompilePostProcessor implements CompilePostProcessor { + + private final boolean lazyBean; + + public BindToRegistryCompilePostProcessor() { + this(false); + } + + /** + * @param lazyBean whether to bind every {@link BindToRegistry} bean lazily (created on first use), as if + * {@link BindToRegistry#lazy()} was set + */ + public BindToRegistryCompilePostProcessor(boolean lazyBean) { + this.lazyBean = lazyBean; + } + + @Override + public void postCompile(CamelContext camelContext, String name, Class<?> clazz, byte[] byteCode, Object instance) + throws Exception { + + BindToRegistry bir = clazz.getAnnotation(BindToRegistry.class); + Configuration cfg = clazz.getAnnotation(Configuration.class); + + // special for lazy beans which we must create on-demand + if (instance == null && bir != null && (lazyBean || bir.lazy())) { + final String beanName = bir.value(); Review Comment: Good catch — and it went a bit further than the empty-name case. The lazy path bound the supplier under the loader-supplied `name` (the class FQCN) and never used `bir.value()` as the registry id, so `@BindToRegistry(value = "named-lazy", lazy = true) class NamedLazy` was only findable as `NamedLazy`, and an unnamed one in a package only as `com.foo.MyBean` — while the eager path (`DefaultCamelBeanPostProcessor.bindToRegistry`) uses the value or the simple class name. Verified with a scratch test before fixing. The code came verbatim from camel-kamelet-main (CAMEL-22056), where CLI sources sit in the default package so FQCN == simple name and it went unnoticed. Fixed in 0fcffb29b37a the way `PackageScanHelper` does it: registry id = `bir.value()`, else `clazz.getSimpleName()`; `unbind(id)` before binding (so a reload replaces the previous supplier instead of leaving it as a second entry under the same key); `name` (FQCN) stays the bean-post-processing name. `testLazyBeanWithoutRegisteredPostProcessor` covers a named and an unnamed lazy Groovy class, and the 4.23 upgrade guide notes the naming change for `--lazy-bean` users with packaged classes. _Claude Code on behalf of davsclaus_ ########## components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyDefaultCompilePostProcessorTest.java: ########## @@ -0,0 +1,87 @@ +/* + * 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.language.groovy; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spi.CompilePostProcessor; +import org.apache.camel.spi.SimpleFunction; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Without any {@link CompilePostProcessor} in the registry (as in a camel-main, Spring Boot or Quarkus application, + * unlike camel-jbang) the compiler falls back to the built-in processors for the Camel annotations. + */ +public class GroovyDefaultCompilePostProcessorTest extends CamelTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + DefaultGroovyScriptCompiler compiler = new DefaultGroovyScriptCompiler(); + compiler.setCamelContext(context); + compiler.setScriptPattern("file:src/test/resources/camel-groovy-default/*"); + context.addService(compiler); + + return context; + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:mask") + .setBody().simple("${maskEmail(${body})}") + .to("mock:result"); + + from("direct:order") + .convertBodyTo(Order.class) + .setBody().simple("${body.id}") + .to("mock:result"); + } + }; + } + + @Test + public void testBindToRegistryWithoutRegisteredPostProcessor() throws Exception { + assertTrue(context.getRegistry().findByType(CompilePostProcessor.class).isEmpty()); + assertInstanceOf(SimpleFunction.class, context.getRegistry().lookupByName("mask-email-function")); + + getMockEndpoint("mock:result").expectedBodiesReceived("j***@example.com"); + template.sendBody("direct:mask", "[email protected]"); + MockEndpoint.assertIsSatisfied(context); + } + + @Test + public void testConverterWithoutRegisteredPostProcessor() throws Exception { + assertNotNull(context.getTypeConverterRegistry().lookup(Order.class, String.class)); + + getMockEndpoint("mock:result").expectedBodiesReceived("123"); + template.sendBody("direct:order", " 123 "); + MockEndpoint.assertIsSatisfied(context); Review Comment: Added in 0fcffb29b37a: `OrderEventNotifier.groovy` (an `EventNotifierSupport` subclass) and `testEventNotifierWithoutRegisteredPostProcessor`, which asserts the instance is in `getManagementStrategy().getEventNotifiers()` and that it counted the completed exchange. One note: the compiler only instantiates classes with a class-level annotation (a plain Groovy class is not touched, as documented), so the notifier carries `@BindToRegistry` to be picked up — same as it would in a user project. _Claude Code on behalf of davsclaus_ -- 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]
