voonhous commented on code in PR #19596:
URL: https://github.com/apache/hudi/pull/19596#discussion_r3774618510


##########
hudi-common/src/main/java/org/apache/hudi/common/avro/HoodieAvroUtils.java:
##########
@@ -124,6 +125,29 @@ public class HoodieAvroUtils {
 
   private static final Properties PROPERTIES = new Properties();
 
+  /**
+   * Resolves the Avro library version, preferring Maven's generated 
pom.properties over
+   * {@link Package#getImplementationVersion()}. The latter reads the jar 
manifest, which is
+   * present for a standalone avro-*.jar but is usually dropped for the avro 
package once its
+   * classes are merged into a shaded/fat jar.
+   */
+  private static String resolveAvroVersion() {
+    String avroPomPropertiesPath = 
"META-INF/maven/org.apache.avro/avro/pom.properties";
+    try (InputStream inputStream = 
Schema.class.getClassLoader().getResourceAsStream(avroPomPropertiesPath)) {

Review Comment:
   Thanks, the anchoring is what I had in mind and the `separatorIdx` rename 
reads better than my `bang`.
   
   One ordering problem in what landed, though. `LOG` is declared at 
`HoodieAvroUtils.java:132`, below `AVRO_VERSION` at `:120`. Static initializers 
run in textual order, so `LOG` is still null while `resolveAvroVersion()` 
executes in `<clinit>`. If anything in the try block throws (IOException out of 
`getResources`/`openStream`, or `IllegalArgumentException` out of 
`Properties.load` on a malformed entry), the catch's `LOG.warn(...)` NPEs and 
that propagates out of the class initializer as `ExceptionInInitializerError`, 
followed by a permanent `NoClassDefFoundError` for the rest of the JVM's life.
   
   That is the exact failure mode I described on the other thread, and it 
triggers on the broken-classpath path this PR exists to handle. My suggested 
snippet did not say where to put the field, so this one is on me.
   
   Please move the declaration above `AVRO_VERSION`:
   
   ```java
   public class HoodieAvroUtils {
   
     private static final Logger LOG = 
LoggerFactory.getLogger(HoodieAvroUtils.class);
   
     public static final String AVRO_VERSION = resolveAvroVersion();
   ```
   
   hudi-agent flagged the same thing at line 164, so that comment can be closed 
by the same change.
   



##########
hudi-common/src/main/java/org/apache/hudi/common/avro/HoodieAvroUtils.java:
##########
@@ -124,6 +125,29 @@ public class HoodieAvroUtils {
 
   private static final Properties PROPERTIES = new Properties();
 
+  /**
+   * Resolves the Avro library version, preferring Maven's generated 
pom.properties over
+   * {@link Package#getImplementationVersion()}. The latter reads the jar 
manifest, which is
+   * present for a standalone avro-*.jar but is usually dropped for the avro 
package once its
+   * classes are merged into a shaded/fat jar.
+   */
+  private static String resolveAvroVersion() {
+    String avroPomPropertiesPath = 
"META-INF/maven/org.apache.avro/avro/pom.properties";
+    try (InputStream inputStream = 
Schema.class.getClassLoader().getResourceAsStream(avroPomPropertiesPath)) {
+      if (inputStream != null) {
+        Properties avroProperties = new Properties();
+        avroProperties.load(inputStream);
+        String version = avroProperties.getProperty("version");
+        if (version != null) {
+          return version;
+        }
+      }
+    } catch (Exception ignored) {
+      // Ignoring the exception and falling back to the manifest-based version 
below
+    }
+    return Schema.class.getPackage().getImplementationVersion();

Review Comment:
   The guards on `gteqAvro1_9()` / `gteqAvro1_10()` / `gteqAvro1_12()` are what 
I was after, thanks.
   
   The other half of that ask is still open: `resolveAvroVersion()` returns 
null silently when both sources miss. Only the exception path logs today, and 
the `return Schema.class.getPackage() == null ? null : ...` line at the bottom 
hands back null with nothing written anywhere. Combined with the new guards, an 
unresolvable version now degrades quietly to pre-1.9 behaviour, which is a 
better outcome than the NPE but leaves no trace naming avro or the classpath, 
so nobody can diagnose it from a log.
   
   Please warn once at resolution time:
   
   ```java
       } catch (Exception e) {
         LOG.warn("Failed to resolve the avro version from {}, falling back to 
the jar manifest", path, e);
       }
       String manifestVersion = Schema.class.getPackage() == null
           ? null : Schema.class.getPackage().getImplementationVersion();
       if (manifestVersion == null) {
         LOG.warn("Could not resolve the avro version from {} nor from the jar 
manifest; "
             + "avro version checks will fall back to pre-1.9 behaviour. Check 
that avro is on the classpath.", path);
       }
       return manifestVersion;
   ```
   
   Note this needs the `LOG` declaration moved above `AVRO_VERSION` to work at 
all, see the other thread.
   



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