You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by ie...@apache.org on 2021/03/04 13:06:43 UTC

[avro] branch master updated: AVRO-3014: Log a warning on ignored logicalType

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

iemejia pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new 72654bf  AVRO-3014: Log a warning on ignored logicalType
72654bf is described below

commit 72654bf73c9eefec06001ab2d1181fbfb127922c
Author: Ryan Skraba <ry...@skraba.com>
AuthorDate: Wed Feb 3 17:44:17 2021 +0100

    AVRO-3014: Log a warning on ignored logicalType
---
 .../avro/src/main/java/org/apache/avro/Schema.java |   9 ++
 .../java/org/apache/avro/TestSchemaWarnings.java   | 109 +++++++++++++++++++++
 2 files changed, 118 insertions(+)

diff --git a/lang/java/avro/src/main/java/org/apache/avro/Schema.java b/lang/java/avro/src/main/java/org/apache/avro/Schema.java
index ff603cd..d62f2e3 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/Schema.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/Schema.java
@@ -49,6 +49,10 @@ import java.util.Set;
 import org.apache.avro.util.internal.Accessor;
 import org.apache.avro.util.internal.Accessor.FieldAccessor;
 import org.apache.avro.util.internal.JacksonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.avro.LogicalType.LOGICAL_TYPE_PROP;
 
 /**
  * An abstract data type.
@@ -106,6 +110,7 @@ public abstract class Schema extends JsonProperties implements Serializable {
   }
 
   static final JsonFactory FACTORY = new JsonFactory();
+  static final Logger LOG = LoggerFactory.getLogger(Schema.class);
   static final ObjectMapper MAPPER = new ObjectMapper(FACTORY);
 
   private static final int NO_HASHCODE = Integer.MIN_VALUE;
@@ -1684,6 +1689,10 @@ public abstract class Schema extends JsonProperties implements Serializable {
           }
           f.aliases = parseAliases(field);
           fields.add(f);
+          if (fieldSchema.getLogicalType() == null && getOptionalText(field, LOGICAL_TYPE_PROP) != null)
+            LOG.warn(
+                "Ignored the {}.{}.logicalType property (\"{}\"). It should probably be nested inside the \"type\" for the field.",
+                name, fieldName, getOptionalText(field, "logicalType"));
         }
         result.setFields(fields);
       } else if (type.equals("enum")) { // enum
diff --git a/lang/java/avro/src/test/java/org/apache/avro/TestSchemaWarnings.java b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaWarnings.java
new file mode 100644
index 0000000..e14ec62
--- /dev/null
+++ b/lang/java/avro/src/test/java/org/apache/avro/TestSchemaWarnings.java
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ *     https://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.avro;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+
+import static org.apache.avro.LogicalType.LOGICAL_TYPE_PROP;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+
+public class TestSchemaWarnings {
+
+  private final static PrintStream originalErr = System.err;
+
+  /**
+   * The capturable replacement for the system err stream.
+   */
+  private final ByteArrayOutputStream capturedErr = new ByteArrayOutputStream();
+
+  @Before
+  public void setupStdErr() {
+    capturedErr.reset();
+    System.setErr(new PrintStream(capturedErr));
+  }
+
+  @AfterClass
+  public static void restoreStdErr() {
+    System.setErr(originalErr);
+  }
+
+  public String getCapturedStdErr() {
+    System.out.flush();
+    String stderr = new String(capturedErr.toByteArray(), StandardCharsets.UTF_8);
+    capturedErr.reset();
+    return stderr;
+  }
+
+  @Test
+  public void testWarnWhenTheLogicalTypeIsOnTheField() {
+    // A record with a single int field.
+    Schema s = SchemaBuilder.record("A").fields().requiredInt("a1").endRecord();
+
+    // Force reparsing the schema, and no warning should be logged.
+    s = new Schema.Parser().parse(s.toString());
+    assertThat(s.getField("a1").schema().getLogicalType(), nullValue());
+    assertThat(getCapturedStdErr(), is(""));
+
+    // Add the logical type annotation to the field (as opposed to the field schema)
+    // and parse it again. This is a common error, see AVRO-3014, AVRO-2015.
+    s.getField("a1").addProp(LOGICAL_TYPE_PROP, LogicalTypes.date().getName());
+    assertThat(s.getField("a1").schema().getLogicalType(), nullValue());
+
+    // Force reparsing the schema, and a warning should be logged.
+    s = new Schema.Parser().parse(s.toString());
+    assertThat(getCapturedStdErr(), containsString("Ignored the A.a1.logicalType property (\"date\"). It should"
+        + " probably be nested inside the \"type\" for the field."));
+    assertThat(s.getField("a1").schema().getLogicalType(), nullValue());
+
+    // Add the logical type annotation to the field schema. This doesn't change the
+    // logical type of an already parsed schema.
+    s.getField("a1").schema().addProp(LOGICAL_TYPE_PROP, LogicalTypes.date().getName());
+    assertThat(s.getField("a1").schema().getLogicalType(), nullValue());
+
+    // Force reparsing the schema. No warning should be logged, and the logical type
+    // should be applied.
+    s = new Schema.Parser().parse(s.toString());
+    assertThat(getCapturedStdErr(), is(""));
+    assertThat(s.getField("a1").schema().getLogicalType(), is(LogicalTypes.date()));
+
+  }
+
+  @Test
+  public void testWarnWhenTheLogicalTypeIsIgnored() {
+    // A record with a single int field.
+    Schema s = SchemaBuilder.record("A").fields().requiredLong("a1").endRecord();
+
+    // Add the logical type annotation to the field (as opposed to the field schema)
+    // and parse it again.
+    s.getField("a1").schema().addProp(LOGICAL_TYPE_PROP, LogicalTypes.date().getName());
+    // Force reparsing the schema. No warning should be logged, and the logical type
+    // should be applied.
+    s = new Schema.Parser().parse(s.toString());
+    assertThat(s.getField("a1").schema().getLogicalType(), nullValue());
+    assertThat(getCapturedStdErr(), containsString("Ignoring invalid logical type for name: date"));
+  }
+}