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

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-fury.git


The following commit(s) were added to refs/heads/main by this push:
     new ab8f4804 feat(java): carry read objects when deserialization fail for 
better trouble shooting (#1420)
ab8f4804 is described below

commit ab8f48040df7d0faef6710af8e26598cd053ccfe
Author: Shawn Yang <shawn.ck.y...@gmail.com>
AuthorDate: Sat Mar 23 14:54:26 2024 +0800

    feat(java): carry read objects when deserialization fail for better trouble 
shooting (#1420)
    
    This PR carry read objects when deserialization fail for better trouble
    shooting.
    
    Closes #1419
---
 .../src/main/java/org/apache/fury/Fury.java        | 29 +++++++++++-
 .../org/apache/fury/collection/ObjectArray.java    |  8 ++++
 .../fury/exception/DeserializationException.java   | 54 ++++++++++++++++++++++
 .../org/apache/fury/resolver/MapRefResolver.java   |  4 ++
 .../src/test/java/org/apache/fury/FuryTest.java    | 27 +++++++++++
 5 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/java/fury-core/src/main/java/org/apache/fury/Fury.java 
b/java/fury-core/src/main/java/org/apache/fury/Fury.java
index 3dc1c16b..407ae725 100644
--- a/java/fury-core/src/main/java/org/apache/fury/Fury.java
+++ b/java/fury-core/src/main/java/org/apache/fury/Fury.java
@@ -26,17 +26,20 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import javax.annotation.concurrent.NotThreadSafe;
 import org.apache.fury.builder.JITContext;
+import org.apache.fury.collection.ObjectArray;
 import org.apache.fury.config.CompatibleMode;
 import org.apache.fury.config.Config;
 import org.apache.fury.config.FuryBuilder;
 import org.apache.fury.config.Language;
 import org.apache.fury.config.LongEncoding;
+import org.apache.fury.exception.DeserializationException;
 import org.apache.fury.memory.MemoryBuffer;
 import org.apache.fury.memory.MemoryUtils;
 import org.apache.fury.resolver.ClassInfo;
@@ -59,6 +62,7 @@ import org.apache.fury.type.Generics;
 import org.apache.fury.type.Type;
 import org.apache.fury.util.ExceptionUtils;
 import org.apache.fury.util.LoggerFactory;
+import org.apache.fury.util.Platform;
 import org.apache.fury.util.Preconditions;
 import org.apache.fury.util.StringUtils;
 import org.slf4j.Logger;
@@ -747,6 +751,9 @@ public final class Fury implements BaseFury {
         obj = readRef(buffer);
       }
       return obj;
+    } catch (Throwable t) {
+      handleReadFailed(t);
+      throw new IllegalStateException("unreachable");
     } finally {
       resetRead();
       jitContext.unlock();
@@ -769,6 +776,17 @@ public final class Fury implements BaseFury {
     }
   }
 
+  private void handleReadFailed(Throwable t) {
+    if (refResolver instanceof MapRefResolver) {
+      ObjectArray readObjects = ((MapRefResolver) 
refResolver).getReadObjects();
+      // carry with read objects for better trouble shooting.
+      List<Object> objects = Arrays.asList(readObjects.objects).subList(0, 
readObjects.size);
+      throw new DeserializationException(objects, t);
+    } else {
+      Platform.throwException(t);
+    }
+  }
+
   private Object xdeserializeInternal(MemoryBuffer buffer) {
     Object obj;
     int nativeObjectsStartOffset = buffer.readInt();
@@ -1051,6 +1069,9 @@ public final class Fury implements BaseFury {
       } else {
         return null;
       }
+    } catch (Throwable t) {
+      handleReadFailed(t);
+      throw new IllegalStateException("unreachable");
     } finally {
       resetRead();
       jitContext.unlock();
@@ -1124,6 +1145,9 @@ public final class Fury implements BaseFury {
         classResolver.readClassDefs(buffer);
       }
       return readRef(buffer);
+    } catch (Throwable t) {
+      handleReadFailed(t);
+      throw new IllegalStateException("unreachable");
     } finally {
       resetRead();
       jitContext.unlock();
@@ -1190,8 +1214,9 @@ public final class Fury implements BaseFury {
         buf.pointTo(oldBytes, 0, oldBytes.length);
       }
       return o;
-    } catch (IOException e) {
-      throw new RuntimeException(e);
+    } catch (Throwable t) {
+      handleReadFailed(t);
+      throw new IllegalStateException("unreachable");
     } finally {
       resetBuffer();
     }
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/collection/ObjectArray.java 
b/java/fury-core/src/main/java/org/apache/fury/collection/ObjectArray.java
index 33a3d8ca..578f9c56 100644
--- a/java/fury-core/src/main/java/org/apache/fury/collection/ObjectArray.java
+++ b/java/fury-core/src/main/java/org/apache/fury/collection/ObjectArray.java
@@ -109,4 +109,12 @@ public final class ObjectArray {
       }
     }
   }
+
+  @Override
+  public String toString() {
+    if (size == 0) {
+      return "[]";
+    }
+    return Arrays.asList(objects).subList(0, size).toString();
+  }
 }
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java
 
b/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java
new file mode 100644
index 00000000..11d9691a
--- /dev/null
+++ 
b/java/fury-core/src/main/java/org/apache/fury/exception/DeserializationException.java
@@ -0,0 +1,54 @@
+/*
+ * 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.fury.exception;
+
+import java.util.List;
+
+public class DeserializationException extends FuryException {
+
+  private List<Object> readObjects;
+
+  public DeserializationException(String message) {
+    super(message);
+  }
+
+  public DeserializationException(Throwable cause) {
+    super(cause);
+  }
+
+  public DeserializationException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  // if `readObjects` too big, generate message lazily to avoid big string 
creation cost.
+  public DeserializationException(List<Object> readObjects, Throwable cause) {
+    super(cause);
+    this.readObjects = readObjects;
+  }
+
+  @Override
+  public String getMessage() {
+    if (readObjects == null) {
+      return super.getMessage();
+    } else {
+      return "Deserialize failed, read objects are: " + readObjects;
+    }
+  }
+}
diff --git 
a/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java 
b/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
index fbfcfebc..b04d24a1 100644
--- a/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
+++ b/java/fury-core/src/main/java/org/apache/fury/resolver/MapRefResolver.java
@@ -211,6 +211,10 @@ public final class MapRefResolver implements RefResolver {
     }
   }
 
+  public ObjectArray getReadObjects() {
+    return readObjects;
+  }
+
   @Override
   public void reset() {
     resetWrite();
diff --git a/java/fury-core/src/test/java/org/apache/fury/FuryTest.java 
b/java/fury-core/src/test/java/org/apache/fury/FuryTest.java
index a4c34ba7..8baf980d 100644
--- a/java/fury-core/src/test/java/org/apache/fury/FuryTest.java
+++ b/java/fury-core/src/test/java/org/apache/fury/FuryTest.java
@@ -56,6 +56,7 @@ import org.apache.fury.annotation.Ignore;
 import org.apache.fury.builder.Generated;
 import org.apache.fury.config.FuryBuilder;
 import org.apache.fury.config.Language;
+import org.apache.fury.exception.FuryException;
 import org.apache.fury.exception.InsecureException;
 import org.apache.fury.memory.MemoryBuffer;
 import org.apache.fury.memory.MemoryUtils;
@@ -663,4 +664,30 @@ public class FuryTest extends FuryTestBase {
     assert buffer != null;
     assertTrue(buffer.size() < 1000 * 1000);
   }
+
+  @Data
+  static class PrintReadObject {
+    public PrintReadObject() {
+      throw new RuntimeException();
+    }
+
+    public PrintReadObject(boolean b) {}
+  }
+
+  @Test
+  public void testPrintReadObjectsWhenFailed() {
+    Fury fury =
+        Fury.builder()
+            .withRefTracking(true)
+            .withCodegen(false)
+            .requireClassRegistration(false)
+            .build();
+    PrintReadObject o = new PrintReadObject(true);
+    try {
+      serDe(fury, ImmutableList.of(ImmutableList.of("a", "b"), o));
+      Assert.fail();
+    } catch (FuryException e) {
+      Assert.assertTrue(e.getMessage().contains("[a, b]"));
+    }
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@fury.apache.org
For additional commands, e-mail: commits-h...@fury.apache.org

Reply via email to