From 46c4444c40218ee93852d1d39caead91eb10ff72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20R=C3=B6der?= Date: Sun, 17 Dec 2023 16:23:58 +0100 Subject: [PATCH] Added a better documentation to the GsonUtils class that makes clear which method expects the length of a String value and which doesn't. removed the error details property since it is not needed. updated the error reporting classes accordingly. --- .../java/org/hobbit/core/data/ErrorData.java | 34 +-------- .../org/hobbit/core/rabbit/GsonUtils.java | 49 +++++++++++-- src/main/java/org/hobbit/vocab/Algorithm.java | 1 - .../org/hobbit/core/rabbit/GsonUtilsTest.java | 73 ++++++++++++++----- 4 files changed, 100 insertions(+), 57 deletions(-) diff --git a/src/main/java/org/hobbit/core/data/ErrorData.java b/src/main/java/org/hobbit/core/data/ErrorData.java index 9a1dd85..4ce53de 100644 --- a/src/main/java/org/hobbit/core/data/ErrorData.java +++ b/src/main/java/org/hobbit/core/data/ErrorData.java @@ -23,19 +23,14 @@ public class ErrorData { protected String errorType; /** * A string that can be used as short label of an error (optional, the error - * type label will be used as default) + * type label might be used as default) */ protected String label; /** * A string that can be used as a short description of an error (optional, the - * error type description will be used as default). + * error type description might be used as default). */ protected String description; - /** - * A string that contains details about the error, e.g., a stack trace - * (optional). - */ - protected String details; /** * @return the containerId @@ -93,27 +88,12 @@ public void setDescription(String description) { this.description = description; } - /** - * @return the details - */ - public String getDetails() { - return details; - } - - /** - * @param details the details to set - */ - public void setDetails(String details) { - this.details = details; - } - @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((containerName == null) ? 0 : containerName.hashCode()); result = prime * result + ((description == null) ? 0 : description.hashCode()); - result = prime * result + ((details == null) ? 0 : details.hashCode()); result = prime * result + ((errorType == null) ? 0 : errorType.hashCode()); result = prime * result + ((label == null) ? 0 : label.hashCode()); return result; @@ -138,11 +118,6 @@ public boolean equals(Object obj) { return false; } else if (!description.equals(other.description)) return false; - if (details == null) { - if (other.details != null) - return false; - } else if (!details.equals(other.details)) - return false; if (errorType == null) { if (other.errorType != null) return false; @@ -172,14 +147,13 @@ public static ErrorData createFromException(Exception e, String containerName) { ErrorData result = new ErrorData(); result.containerName = containerName; result.errorType = HobbitErrors.UnhandledException.getURI(); - result.label = e.getClass().getName(); - result.description = e.getMessage(); + result.label = e.getMessage(); // Get the full stack trace StringWriter writer = new StringWriter(); PrintWriter pwriter = new PrintWriter(writer); e.printStackTrace(pwriter); pwriter.flush(); - result.details = writer.toString(); + result.description = writer.toString(); pwriter.close(); return result; diff --git a/src/main/java/org/hobbit/core/rabbit/GsonUtils.java b/src/main/java/org/hobbit/core/rabbit/GsonUtils.java index df006cd..126f888 100644 --- a/src/main/java/org/hobbit/core/rabbit/GsonUtils.java +++ b/src/main/java/org/hobbit/core/rabbit/GsonUtils.java @@ -1,5 +1,7 @@ package org.hobbit.core.rabbit; +import java.nio.ByteBuffer; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +36,34 @@ public static byte[] serializeObjectWithGson(Gson gson, T object) { return null; } + /** + * Deserialize a Java data object that was received as JSON with a command. + * First, the given byte array will be transformed into a String using the + * {@link RabbitMQUtils} class, before it will be deserialized using the given + * {@link Gson} object. + * + * @param The class that the data object should have. + * @param gson The Gson instance used to deserialize the JSON object. + * @param data The byte array that has been received. + * @param clazz The class that the data object should have. + * @param containsLength This flag indicates whether the given byte array + * contains the data with a preceeded int value containing + * the length of the next piece of data + * @return The deserialized object or null if an error occurred + */ + public static T deserializeObjectWithGson(Gson gson, byte[] data, Class clazz, + boolean containsLength) { + if (data != null) { + if (containsLength) { + return deserializeObjectWithGson(gson, ByteBuffer.wrap(data), clazz); + } else { + String dataString = RabbitMQUtils.readString(data); + return deserializeObjectWithGson(gson, dataString, clazz); + } + } + return null; + } + /** * Deserialize a Java data object that was received as JSON with a command. * First, the given byte array will be transformed into a String using the @@ -42,19 +72,24 @@ public static byte[] serializeObjectWithGson(Gson gson, T object) { * * @param The class that the data object should have. * @param gson The Gson instance used to deserialize the JSON object. - * @param data The byte array that has been received. + * @param data A ByteBuffer containing the data and the length of the data. * @param clazz The class that the data object should have. * @return The deserialized object or null if an error occurred */ - public static T deserializeObjectWithGson(Gson gson, byte[] data, Class clazz) { + public static T deserializeObjectWithGson(Gson gson, ByteBuffer data, Class clazz) { if (data != null) { String dataString = RabbitMQUtils.readString(data); - try { - return gson.fromJson(dataString, clazz); - } catch (Exception e) { - LOGGER.error("Error while parsing JSON data. Returning null."); - } + return deserializeObjectWithGson(gson, dataString, clazz); } return null; } + + protected static T deserializeObjectWithGson(Gson gson, String dataString, Class clazz) { + try { + return gson.fromJson(dataString, clazz); + } catch (Exception e) { + LOGGER.error("Error while parsing JSON data form String \"" + dataString + "\". Returning null.", e); + return null; + } + } } diff --git a/src/main/java/org/hobbit/vocab/Algorithm.java b/src/main/java/org/hobbit/vocab/Algorithm.java index fa9b224..221a980 100644 --- a/src/main/java/org/hobbit/vocab/Algorithm.java +++ b/src/main/java/org/hobbit/vocab/Algorithm.java @@ -22,7 +22,6 @@ public class Algorithm { public static final Resource Result = resource("Result"); // Properties sorted alphabetically - public static final Property errorDetails = property("errorDetails"); public static final Property instanceOf = property("instanceOf"); public static final Property parameter = property("parameter"); public static final Property produces = property("produces"); diff --git a/src/test/java/org/hobbit/core/rabbit/GsonUtilsTest.java b/src/test/java/org/hobbit/core/rabbit/GsonUtilsTest.java index a13874b..1d857f5 100644 --- a/src/test/java/org/hobbit/core/rabbit/GsonUtilsTest.java +++ b/src/test/java/org/hobbit/core/rabbit/GsonUtilsTest.java @@ -1,39 +1,74 @@ package org.hobbit.core.rabbit; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + import org.hobbit.core.data.ErrorData; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import com.google.gson.Gson; +@RunWith(Parameterized.class) public class GsonUtilsTest { - @Test - public void testErrorData() { - ErrorData original = new ErrorData(); - original.setErrorType("http://example.org/generalError"); - original.setContainerId("123"); + protected static Gson gson = new Gson(); + + protected Object original; + protected Class clazz; - Gson gson = new Gson(); - ErrorData received; + public GsonUtilsTest(Object original, Class clazz) { + super(); + this.original = original; + this.clazz = clazz; + } - received = GsonUtils.deserializeObjectWithGson(gson, GsonUtils.serializeObjectWithGson(gson, original), - ErrorData.class); + @Test + public void testDirect() { + Object received = GsonUtils.deserializeObjectWithGson(gson, GsonUtils.serializeObjectWithGson(gson, original), + ErrorData.class, false); Assert.assertEquals(original, received); + } - original.setLabel("Example label"); - received = GsonUtils.deserializeObjectWithGson(gson, GsonUtils.serializeObjectWithGson(gson, original), - ErrorData.class); + @Test + public void testWithLengthPrefix() { + byte[] data = GsonUtils.serializeObjectWithGson(gson, original); + ByteBuffer buffer = ByteBuffer.allocate(data.length + 4); + buffer.putInt(data.length); + buffer.put(data); + + Object received = GsonUtils.deserializeObjectWithGson(gson, buffer.array(), + ErrorData.class, true); Assert.assertEquals(original, received); + } + + @Parameters + public static List parameters() { + List testCases = new ArrayList<>(); + ErrorData original; + original = new ErrorData(); + original.setErrorType("http://example.org/generalError"); + original.setContainerId("123"); + testCases.add(new Object[] {original, original.getClass()}); + + original = new ErrorData(); + original.setErrorType("http://example.org/generalError"); + original.setContainerId("123"); + original.setLabel("Example label"); + testCases.add(new Object[] {original, original.getClass()}); + + original = new ErrorData(); + original.setErrorType("http://example.org/generalError"); + original.setContainerId("123"); + original.setLabel("Example label"); original.setDescription("Some description"); - received = GsonUtils.deserializeObjectWithGson(gson, GsonUtils.serializeObjectWithGson(gson, original), - ErrorData.class); - Assert.assertEquals(original, received); + testCases.add(new Object[] {original, original.getClass()}); - original.setDetails("A lot of details...."); - received = GsonUtils.deserializeObjectWithGson(gson, GsonUtils.serializeObjectWithGson(gson, original), - ErrorData.class); - Assert.assertEquals(original, received); + return testCases; } }