This is an automated email from the ASF dual-hosted git repository.

apupier 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 aeaf7d9db100 CAMEL-25151: camel-bindy - a java.util.Date value longer 
than its pattern is parsed
aeaf7d9db100 is described below

commit aeaf7d9db100a66fe056acab7cffcffda381c8a6
Author: smjain <[email protected]>
AuthorDate: Wed Sep 30 07:51:13 2026 +0530

    CAMEL-25151: camel-bindy - a java.util.Date value longer than its pattern 
is parsed
    
    DateFormatFactory rejected every java.util.Date value with more characters
    than the pattern, to reject a date followed by other characters (such as
    20090901-10:32:30 for yyyyMMdd). But a pattern letter count is a minimum
    width: M/d/yyyy formats 12/25/2026, h:mm a formats 11:45 PM and MMMM
    formats September, so valid dates, including the ones Bindy writes itself,
    failed with "Date provided does not fit the pattern defined".
    CAMEL-11620 removed the same check from the java.time factories.
    
    A value longer than the pattern is now parsed with a ParsePosition and
    accepted when the whole value is used; otherwise the same FormatException
    is thrown as before. A value no longer than the pattern is parsed exactly
    as before.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../bindy/format/factories/DateFormatFactory.java  |  13 +-
 ...dyCsvDatePatternValueLongerThanPatternTest.java | 148 +++++++++++++++++++++
 2 files changed, 160 insertions(+), 1 deletion(-)

diff --git 
a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/format/factories/DateFormatFactory.java
 
b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/format/factories/DateFormatFactory.java
index d63e7da90540..1861a4fe97e5 100644
--- 
a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/format/factories/DateFormatFactory.java
+++ 
b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/format/factories/DateFormatFactory.java
@@ -17,6 +17,7 @@
 package org.apache.camel.dataformat.bindy.format.factories;
 
 import java.text.DateFormat;
+import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
@@ -84,7 +85,17 @@ public class DateFormatFactory extends AbstractFormatFactory 
{
                 return date;
 
             } else {
-                throw new FormatException("Date provided does not fit the 
pattern defined");
+                // A formatted date can be longer than its pattern (M, d, H or 
h with two digits, MMMM, EEEE, a),
+                // so a longer string is accepted when it is parsed 
completely. A date followed by other
+                // characters, such as 20090901-10:32:30 with the pattern 
yyyyMMdd, is still rejected
+                df.setLenient(false);
+                ParsePosition position = new ParsePosition(0);
+                date = df.parse(string, position);
+                if (date == null || position.getIndex() != string.length()) {
+                    throw new FormatException("Date provided does not fit the 
pattern defined");
+                }
+
+                return date;
             }
 
         }
diff --git 
a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDatePatternValueLongerThanPatternTest.java
 
b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDatePatternValueLongerThanPatternTest.java
new file mode 100644
index 000000000000..f126abcfb61b
--- /dev/null
+++ 
b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDatePatternValueLongerThanPatternTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.dataformat.bindy.csv;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.dataformat.bindy.annotation.CsvRecord;
+import org.apache.camel.dataformat.bindy.annotation.DataField;
+import org.apache.camel.dataformat.bindy.format.FormatException;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * A java.util.Date field is formatted with its pattern, and the formatted 
text can be longer than the pattern (M, d, h
+ * with two digits, MMMM, a). Such a value must be read back.
+ */
+public class BindyCsvDatePatternValueLongerThanPatternTest extends 
CamelTestSupport {
+
+    private static Date date(String text) throws Exception {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm", 
Locale.ENGLISH);
+        return df.parse(text);
+    }
+
+    @Test
+    public void testUnmarshalValuesLongerThanPattern() throws Exception {
+        String body = "12/25/2026;25.12.2026;December 25 2026;11:45 PM\r\n";
+        Row row = template.requestBody("direct:unmarshal", body, Row.class);
+        assertEquals(date("2026-12-25 00:00"), row.getUs());
+        assertEquals(date("2026-12-25 00:00"), row.getDe());
+        assertEquals(date("2026-12-25 00:00"), row.getLongMonth());
+        assertEquals(date("1970-01-01 23:45"), row.getTime());
+    }
+
+    @Test
+    public void testMarshalUnmarshalRoundTrip() throws Exception {
+        Row row = new Row();
+        row.setUs(date("2026-11-30 00:00"));
+        row.setDe(date("2026-10-15 00:00"));
+        row.setLongMonth(date("2026-09-30 00:00"));
+        row.setTime(date("1970-01-01 10:05"));
+
+        String csv = template.requestBody("direct:marshal", row, String.class);
+        assertEquals("11/30/2026;15.10.2026;September 30 2026;10:05 AM\r\n", 
csv);
+
+        Row back = template.requestBody("direct:unmarshal", csv, Row.class);
+        assertEquals(row.getUs(), back.getUs());
+        assertEquals(row.getDe(), back.getDe());
+        assertEquals(row.getLongMonth(), back.getLongMonth());
+        assertEquals(row.getTime(), back.getTime());
+    }
+
+    @Test
+    public void testUnmarshalLongerValueThatIsNotTheDateIsRejected() {
+        // a date followed by other characters, and a value that is not a 
valid date
+        for (String value : new String[] { "12/25/2026-01", "13/45/2026" }) {
+            String body = value + ";25.12.2026;December 25 2026;11:45 PM\r\n";
+            CamelExecutionException e = 
assertThrows(CamelExecutionException.class,
+                    () -> template.requestBody("direct:unmarshal", body, 
Row.class));
+            assertInstanceOf(FormatException.class, e.getCause().getCause(), 
value);
+            assertEquals("Date provided does not fit the pattern defined, 
position: 1, line: 1", e.getCause().getMessage(),
+                    value);
+        }
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                BindyCsvDataFormat format = new BindyCsvDataFormat(Row.class);
+                format.setLocale("en");
+                from("direct:marshal").marshal(format);
+                from("direct:unmarshal").unmarshal(format);
+            }
+        };
+    }
+
+    @CsvRecord(separator = ";")
+    public static class Row {
+
+        @DataField(pos = 1, pattern = "M/d/yyyy")
+        private Date us;
+
+        @DataField(pos = 2, pattern = "d.M.yyyy")
+        private Date de;
+
+        @DataField(pos = 3, pattern = "MMMM d yyyy")
+        private Date longMonth;
+
+        @DataField(pos = 4, pattern = "h:mm a")
+        private Date time;
+
+        public Date getUs() {
+            return us;
+        }
+
+        public void setUs(Date us) {
+            this.us = us;
+        }
+
+        public Date getDe() {
+            return de;
+        }
+
+        public void setDe(Date de) {
+            this.de = de;
+        }
+
+        public Date getLongMonth() {
+            return longMonth;
+        }
+
+        public void setLongMonth(Date longMonth) {
+            this.longMonth = longMonth;
+        }
+
+        public Date getTime() {
+            return time;
+        }
+
+        public void setTime(Date time) {
+            this.time = time;
+        }
+    }
+}

Reply via email to