This is an automated email from the ASF dual-hosted git repository.
Croway pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new c0a3b3875128 CAMEL-23914: handle @@CamelMagicValue@@ property
conversion
c0a3b3875128 is described below
commit c0a3b38751280a9a5160bbb0bdb94a608799b559
Author: Marco Carletti <[email protected]>
AuthorDate: Mon Jul 6 10:29:14 2026 +0200
CAMEL-23914: handle @@CamelMagicValue@@ property conversion
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
.../PropertyConfigurerSupportMagicValueTest.java | 123 +++++++++++++++++++++
.../component/PropertyConfigurerSupport.java | 56 +++++++---
.../camel/main/download/ExportTypeConverter.java | 61 +++-------
.../dsl/yaml/validator/DummyTypeConverter.java | 61 +++-------
4 files changed, 195 insertions(+), 106 deletions(-)
diff --git
a/core/camel-core/src/test/java/org/apache/camel/support/PropertyConfigurerSupportMagicValueTest.java
b/core/camel-core/src/test/java/org/apache/camel/support/PropertyConfigurerSupportMagicValueTest.java
new file mode 100644
index 000000000000..e759a0141a2e
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/support/PropertyConfigurerSupportMagicValueTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+import java.time.Duration;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+import org.junit.jupiter.api.Test;
+
+import static
org.apache.camel.support.component.PropertyConfigurerSupport.MAGIC_VALUE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Tests that PropertyConfigurerSupport.property() handles the
@@CamelMagicValue@@ placeholder for all primitive/wrapper
+ * types, returning type-safe defaults instead of throwing
NumberFormatException. This covers the camel-launcher export
+ * scenario where optional kamelet properties (e.g. salesforce-source replayId
of type Long) are resolved to the magic
+ * placeholder.
+ */
+public class PropertyConfigurerSupportMagicValueTest extends
ContextTestSupport {
+
+ @Test
+ public void testMagicValueToLong() {
+ Long result = PropertyConfigurerSupport.property(context, Long.class,
MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals(1L, result);
+ }
+
+ @Test
+ public void testMagicValueToPrimitiveLong() {
+ long result = PropertyConfigurerSupport.property(context, long.class,
MAGIC_VALUE);
+ assertEquals(1L, result);
+ }
+
+ @Test
+ public void testMagicValueToInteger() {
+ Integer result = PropertyConfigurerSupport.property(context,
Integer.class, MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals(1, result);
+ }
+
+ @Test
+ public void testMagicValueToPrimitiveInt() {
+ int result = PropertyConfigurerSupport.property(context, int.class,
MAGIC_VALUE);
+ assertEquals(1, result);
+ }
+
+ @Test
+ public void testMagicValueToDouble() {
+ Double result = PropertyConfigurerSupport.property(context,
Double.class, MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals(1d, result);
+ }
+
+ @Test
+ public void testMagicValueToFloat() {
+ Float result = PropertyConfigurerSupport.property(context,
Float.class, MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals(1f, result);
+ }
+
+ @Test
+ public void testMagicValueToShort() {
+ Short result = PropertyConfigurerSupport.property(context,
Short.class, MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals((short) 1, result);
+ }
+
+ @Test
+ public void testMagicValueToByte() {
+ Byte result = PropertyConfigurerSupport.property(context, Byte.class,
MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals((byte) 0, result);
+ }
+
+ @Test
+ public void testMagicValueToBoolean() {
+ Boolean result = PropertyConfigurerSupport.property(context,
Boolean.class, MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals(Boolean.TRUE, result);
+ }
+
+ @Test
+ public void testMagicValueToPrimitiveBoolean() {
+ boolean result = PropertyConfigurerSupport.property(context,
boolean.class, MAGIC_VALUE);
+ assertEquals(true, result);
+ }
+
+ @Test
+ public void testMagicValueToDuration() {
+ Duration result = PropertyConfigurerSupport.property(context,
Duration.class, MAGIC_VALUE);
+ assertNotNull(result);
+ assertEquals(Duration.ofMillis(1), result);
+ }
+
+ @Test
+ public void testMagicValueToString() {
+ String result = PropertyConfigurerSupport.property(context,
String.class, MAGIC_VALUE);
+ assertEquals(MAGIC_VALUE, result);
+ }
+
+ @Test
+ public void testRegularLongConversion() {
+ Long result = PropertyConfigurerSupport.property(context, Long.class,
"42");
+ assertNotNull(result);
+ assertEquals(42L, result);
+ }
+}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/component/PropertyConfigurerSupport.java
b/core/camel-support/src/main/java/org/apache/camel/support/component/PropertyConfigurerSupport.java
index 80d6854da1a2..242fc9876288 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/component/PropertyConfigurerSupport.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/component/PropertyConfigurerSupport.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.support.component;
+import java.time.Duration;
import java.util.List;
import org.apache.camel.CamelContext;
@@ -65,22 +66,25 @@ public abstract class PropertyConfigurerSupport {
}
value = obj;
} else if (type == long.class || type == Long.class || type ==
int.class || type == Integer.class) {
- Object obj = null;
- // string to long/int then it may be a duration where we can
convert the value to milli seconds
- // it may be a time pattern, such as 5s for 5 seconds = 5000
- try {
- long num = TimeUtils.toMilliSeconds(text);
- if (type == int.class || type == Integer.class) {
- // need to cast to int
- obj = (int) num;
- } else {
- obj = num;
+ // skip duration conversion for magic export placeholder
+ if (!MAGIC_VALUE.equals(text)) {
+ Object obj = null;
+ // string to long/int then it may be a duration where we
can convert the value to milli seconds
+ // it may be a time pattern, such as 5s for 5 seconds =
5000
+ try {
+ long num = TimeUtils.toMilliSeconds(text);
+ if (type == int.class || type == Integer.class) {
+ // need to cast to int
+ obj = (int) num;
+ } else {
+ obj = num;
+ }
+ } catch (IllegalArgumentException e) {
+ // ignore
+ }
+ if (obj != null) {
+ value = obj;
}
- } catch (IllegalArgumentException e) {
- // ignore
- }
- if (obj != null) {
- value = obj;
}
}
}
@@ -95,10 +99,26 @@ public abstract class PropertyConfigurerSupport {
}
if (value != null) {
- try {
- if (MAGIC_VALUE.equals(value) && boolean.class == type) {
- value = "true";
+ if (MAGIC_VALUE.equals(value)) {
+ if (boolean.class == type || Boolean.class == type) {
+ return (T) Boolean.TRUE;
+ } else if (int.class == type || Integer.class == type) {
+ return (T) Integer.valueOf(1);
+ } else if (long.class == type || Long.class == type) {
+ return (T) Long.valueOf(1L);
+ } else if (double.class == type || Double.class == type) {
+ return (T) Double.valueOf(1d);
+ } else if (float.class == type || Float.class == type) {
+ return (T) Float.valueOf(1f);
+ } else if (short.class == type || Short.class == type) {
+ return (T) Short.valueOf((short) 1);
+ } else if (byte.class == type || Byte.class == type) {
+ return (T) Byte.valueOf((byte) 0);
+ } else if (Duration.class == type) {
+ return (T) Duration.ofMillis(1);
}
+ }
+ try {
return
camelContext.getTypeConverter().mandatoryConvertTo(type, value);
} catch (NoTypeConversionAvailableException e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
index a449c0692c03..1ec5c51cff7e 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ExportTypeConverter.java
@@ -16,13 +16,10 @@
*/
package org.apache.camel.main.download;
-import java.time.Duration;
-
import org.apache.camel.Exchange;
import org.apache.camel.TypeConversionException;
import org.apache.camel.converter.ObjectConverter;
import org.apache.camel.support.TypeConverterSupport;
-import org.apache.camel.support.component.PropertyConfigurerSupport;
import org.apache.camel.util.ObjectHelper;
/**
@@ -33,47 +30,23 @@ public class ExportTypeConverter extends
TypeConverterSupport {
@Override
public <T> T convertTo(Class<T> type, Exchange exchange, Object value)
throws TypeConversionException {
- if (PropertyConfigurerSupport.MAGIC_VALUE.equals(value)) {
- // attempt to convert to the given type using different common
inputs (boolean, numeric, string)
- if (boolean.class == type || Boolean.class == type) {
- return (T) Boolean.TRUE;
- } else if (type == int.class || type == Integer.class) {
- return (T) Integer.valueOf("1");
- } else if (type == long.class || type == Long.class) {
- return (T) Long.valueOf("1");
- } else if (type == double.class || type == Double.class) {
- return (T) Double.valueOf("1");
- } else if (type == float.class || type == Float.class) {
- return (T) Float.valueOf("1");
- } else if (type == short.class || type == Short.class) {
- return (T) Short.valueOf("1");
- } else if (type == byte.class || type == Byte.class) {
- return (T) Byte.valueOf("0");
- } else if (type == Duration.class) {
- return (T) Duration.ofMillis(1);
- } else if (type == String.class) {
- return (T) PropertyConfigurerSupport.MAGIC_VALUE;
- }
- } else {
- String s = value.toString();
- // regular values so convert normally
- if (boolean.class == type || Boolean.class == type) {
- return (T) ObjectHelper.toBoolean(s);
- } else if (type == int.class || type == Integer.class) {
- return (T) ObjectConverter.toInteger(s);
- } else if (type == long.class || type == Long.class) {
- return (T) ObjectConverter.toLong(s);
- } else if (type == double.class || type == Double.class) {
- return (T) ObjectConverter.toDouble(s);
- } else if (type == float.class || type == Float.class) {
- return (T) ObjectConverter.toFloat(s);
- } else if (type == short.class || type == Short.class) {
- return (T) ObjectConverter.toShort(s);
- } else if (type == byte.class || type == Byte.class) {
- return (T) ObjectConverter.toByte(s);
- } else if (type == String.class) {
- return (T) s;
- }
+ String s = value.toString();
+ if (boolean.class == type || Boolean.class == type) {
+ return (T) ObjectHelper.toBoolean(s);
+ } else if (type == int.class || type == Integer.class) {
+ return (T) ObjectConverter.toInteger(s);
+ } else if (type == long.class || type == Long.class) {
+ return (T) ObjectConverter.toLong(s);
+ } else if (type == double.class || type == Double.class) {
+ return (T) ObjectConverter.toDouble(s);
+ } else if (type == float.class || type == Float.class) {
+ return (T) ObjectConverter.toFloat(s);
+ } else if (type == short.class || type == Short.class) {
+ return (T) ObjectConverter.toShort(s);
+ } else if (type == byte.class || type == Byte.class) {
+ return (T) ObjectConverter.toByte(s);
+ } else if (type == String.class) {
+ return (T) s;
}
return null;
}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DummyTypeConverter.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DummyTypeConverter.java
index ae91557b4e86..bd3187328b36 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DummyTypeConverter.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DummyTypeConverter.java
@@ -16,13 +16,10 @@
*/
package org.apache.camel.dsl.yaml.validator;
-import java.time.Duration;
-
import org.apache.camel.Exchange;
import org.apache.camel.TypeConversionException;
import org.apache.camel.converter.ObjectConverter;
import org.apache.camel.support.TypeConverterSupport;
-import org.apache.camel.support.component.PropertyConfigurerSupport;
import org.apache.camel.util.ObjectHelper;
/**
@@ -33,47 +30,23 @@ public class DummyTypeConverter extends
TypeConverterSupport {
@Override
public <T> T convertTo(Class<T> type, Exchange exchange, Object value)
throws TypeConversionException {
- if (PropertyConfigurerSupport.MAGIC_VALUE.equals(value)) {
- // attempt to convert to the given type using different common
inputs (boolean, numeric, string)
- if (boolean.class == type || Boolean.class == type) {
- return (T) Boolean.TRUE;
- } else if (type == int.class || type == Integer.class) {
- return (T) Integer.valueOf("1");
- } else if (type == long.class || type == Long.class) {
- return (T) Long.valueOf("1");
- } else if (type == double.class || type == Double.class) {
- return (T) Double.valueOf("1");
- } else if (type == float.class || type == Float.class) {
- return (T) Float.valueOf("1");
- } else if (type == short.class || type == Short.class) {
- return (T) Short.valueOf("1");
- } else if (type == byte.class || type == Byte.class) {
- return (T) Byte.valueOf("0");
- } else if (type == Duration.class) {
- return (T) Duration.ofMillis(1);
- } else if (type == String.class) {
- return (T) PropertyConfigurerSupport.MAGIC_VALUE;
- }
- } else {
- String s = value.toString();
- // regular values so convert normally
- if (boolean.class == type || Boolean.class == type) {
- return (T) ObjectHelper.toBoolean(s);
- } else if (type == int.class || type == Integer.class) {
- return (T) ObjectConverter.toInteger(s);
- } else if (type == long.class || type == Long.class) {
- return (T) ObjectConverter.toLong(s);
- } else if (type == double.class || type == Double.class) {
- return (T) ObjectConverter.toDouble(s);
- } else if (type == float.class || type == Float.class) {
- return (T) ObjectConverter.toFloat(s);
- } else if (type == short.class || type == Short.class) {
- return (T) ObjectConverter.toShort(s);
- } else if (type == byte.class || type == Byte.class) {
- return (T) ObjectConverter.toByte(s);
- } else if (type == String.class) {
- return (T) s;
- }
+ String s = value.toString();
+ if (boolean.class == type || Boolean.class == type) {
+ return (T) ObjectHelper.toBoolean(s);
+ } else if (type == int.class || type == Integer.class) {
+ return (T) ObjectConverter.toInteger(s);
+ } else if (type == long.class || type == Long.class) {
+ return (T) ObjectConverter.toLong(s);
+ } else if (type == double.class || type == Double.class) {
+ return (T) ObjectConverter.toDouble(s);
+ } else if (type == float.class || type == Float.class) {
+ return (T) ObjectConverter.toFloat(s);
+ } else if (type == short.class || type == Short.class) {
+ return (T) ObjectConverter.toShort(s);
+ } else if (type == byte.class || type == Byte.class) {
+ return (T) ObjectConverter.toByte(s);
+ } else if (type == String.class) {
+ return (T) s;
}
return null;
}