dan-s1 commented on code in PR #10850:
URL: https://github.com/apache/nifi/pull/10850#discussion_r2764926834


##########
nifi-extension-bundles/nifi-parquet-bundle/nifi-parquet-processors/src/test/java/org/apache/nifi/parquet/ParquetTestUtils.java:
##########
@@ -89,5 +93,247 @@ private static ParquetWriter<GenericRecord> 
createParquetWriter(final Schema sch
                 .build();
     }
 
+    /**
+     * Creates a parquet file with timestamp_millis logical type for testing 
NIFI-15548.
+     *
+     * @param numRecords Number of records to create
+     * @return The created parquet file
+     * @throws IOException if file creation fails
+     */
+    public static File createTimestampParquetFile(int numRecords) throws 
IOException {
+        // Create schema with timestamp_millis logical type
+        final Schema timestampSchema = 
LogicalTypes.timestampMillis().addToSchema(Schema.create(Schema.Type.LONG));
+
+        final Schema recordSchema = Schema.createRecord("TimestampRecord", 
null, "test", false);
+        recordSchema.setFields(java.util.List.of(

Review Comment:
   Include import for ` java.util.List` and shorten the code here and in the 
other places below this is used.
   ```suggestion
           recordSchema.setFields(List.of(
   ```



##########
nifi-extension-bundles/nifi-extension-utils/nifi-record-utils/nifi-avro-record-utils/src/main/java/org/apache/nifi/avro/AvroTypeUtil.java:
##########
@@ -1155,9 +1155,18 @@ private static Object normalizeValue(final Object value, 
final Schema avroSchema
                 final String logicalName = logicalType.getName();
                 if (LOGICAL_TYPE_DATE.equals(logicalName)) {
                     // date logical name means that the value is number of 
days since Jan 1, 1970
+                    // Handle both Integer (legacy) and LocalDate (newer Avro 
libraries)
+                    if (value instanceof LocalDate) {
+                        return java.sql.Date.valueOf((LocalDate) value);
+                    }
                     return java.sql.Date.valueOf(LocalDate.ofEpochDay((int) 
value));
                 } else if (LOGICAL_TYPE_TIME_MILLIS.equals(logicalName)) {
                     // time-millis logical name means that the value is number 
of milliseconds since midnight.
+                    // Handle both Integer (legacy) and LocalTime (newer Avro 
libraries)
+                    if (value instanceof LocalTime) {
+                        final LocalTime localTime = (LocalTime) value;
+                        return new Time(localTime.toNanoOfDay() / 1_000_000);
+                    }

Review Comment:
   Intellij suggests replacing with pattern variable
   ```suggestion
                      if (value instanceof LocalTime localTime) {
                           return new Time(localTime.toNanoOfDay() / 1_000_000);
                       }
   ```



##########
nifi-extension-bundles/nifi-extension-utils/nifi-record-utils/nifi-avro-record-utils/src/main/java/org/apache/nifi/avro/AvroTypeUtil.java:
##########
@@ -1171,10 +1180,23 @@ private static Object normalizeValue(final Object 
value, final Schema avroSchema
 
                 final String logicalName = logicalType.getName();
                 if (LOGICAL_TYPE_TIME_MICROS.equals(logicalName)) {
+                    // Handle both Long (legacy) and LocalTime (newer Avro 
libraries)
+                    if (value instanceof LocalTime) {
+                        final LocalTime localTime = (LocalTime) value;
+                        return new Time(localTime.toNanoOfDay() / 1_000_000);
+                    }

Review Comment:
   Intellij suggests using a pattern variable.
   ```suggestion
                       if (value instanceof LocalTime localTime) {
                           return new Time(localTime.toNanoOfDay() / 1_000_000);
                       }
   ```



##########
nifi-extension-bundles/nifi-parquet-bundle/nifi-parquet-processors/src/test/java/org/apache/nifi/parquet/TestParquetReader.java:
##########
@@ -217,6 +218,217 @@ public void testReaderWithAddListElementRecordsDisabled() 
throws IOException, In
                 "MapRecord[{name=Bob, favorite_number=1, 
favorite_colors=[blue, red, yellow]}]");
     }
 
+    /**
+     * Test for NIFI-15548: ParquetReader fails on timestamps.
+     * This test programmatically creates a parquet file with timestamp_millis 
logical type
+     * and verifies that the timestamp values can be read without 
ClassCastException.
+     */
+    @Test
+    public void testReadParquetWithTimestampMillis() throws IOException, 
MalformedRecordException {
+        final int numRecords = 5;
+        final File parquetFile = 
ParquetTestUtils.createTimestampParquetFile(numRecords);

Review Comment:
   Could you pass a File object annotated with a JUnit5 `TempDir` annotation so 
it would handle the cleanup of any files (hence not needing the finally 
statements) to delete the created file?



-- 
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]

Reply via email to