From 24b7d2bae39313d6b1d512b36e0577a600789326 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Tue, 31 Aug 2021 11:27:23 +0300 Subject: [PATCH 1/3] #300 DefaultSerializer can't unit class. --- .../graph/serializer/DefaultSerializer.java | 18 ++++++++++++------ .../serializer/DefaultSerializerTest.java | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java diff --git a/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java b/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java index bf520e224..39488d280 100644 --- a/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java +++ b/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java @@ -39,9 +39,11 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Map.Entry; +import java.util.function.Function; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -62,6 +64,15 @@ public class DefaultSerializer implements ISerializer { */ private final ILogger logger; + static Function oDataTypeToClassName = odataType -> { + + final int lastDotIndex = odataType.lastIndexOf("."); + return (odataType.substring(0, lastDotIndex).toLowerCase(Locale.ROOT) + + ".models." + + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, odataType.substring(lastDotIndex + 1))) + .replace("#", "com."); + }; + /** * Creates a DefaultSerializer * @@ -364,12 +375,7 @@ public Class getDerivedClass(@Nonnull final JsonObject jsonObject, @Nullable if (jsonObject.get(ODATA_TYPE_KEY) != null) { /** #microsoft.graph.user or #microsoft.graph.callrecords.callrecord */ final String odataType = jsonObject.get(ODATA_TYPE_KEY).getAsString(); - final int lastDotIndex = odataType.lastIndexOf("."); - final String derivedType = (odataType.substring(0, lastDotIndex) + - ".models." + - CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, - odataType.substring(lastDotIndex + 1))) - .replace("#", "com."); + final String derivedType = oDataTypeToClassName.apply(odataType); try { Class derivedClass = Class.forName(derivedType); //Check that the derived class inherits from the given parent class diff --git a/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java b/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java new file mode 100644 index 000000000..8b7f66474 --- /dev/null +++ b/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java @@ -0,0 +1,16 @@ +package com.microsoft.graph.serializer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Created by Valentin Popov valentin@archiva.ru on 30.08.2021. + */ +class DefaultSerializerTest { + + @Test + void oDataTypeToClassName() { + Assertions.assertEquals("com.microsoft.graph.models.Message", + DefaultSerializer.oDataTypeToClassName.apply("#Microsoft.Graph.Message")); + } +} From 038b8cb66e55ba18dbdcad3a2ea85353bdd93cb4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Tue, 31 Aug 2021 15:44:58 +0300 Subject: [PATCH 2/3] #300 DefaultSerializer can't unit class. --- .../graph/serializer/DefaultSerializer.java | 28 +++++++++++-------- .../serializer/DefaultSerializerTest.java | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java b/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java index 39488d280..71cd632e5 100644 --- a/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java +++ b/src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java @@ -64,15 +64,6 @@ public class DefaultSerializer implements ISerializer { */ private final ILogger logger; - static Function oDataTypeToClassName = odataType -> { - - final int lastDotIndex = odataType.lastIndexOf("."); - return (odataType.substring(0, lastDotIndex).toLowerCase(Locale.ROOT) + - ".models." + - CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, odataType.substring(lastDotIndex + 1))) - .replace("#", "com."); - }; - /** * Creates a DefaultSerializer * @@ -375,7 +366,7 @@ public Class getDerivedClass(@Nonnull final JsonObject jsonObject, @Nullable if (jsonObject.get(ODATA_TYPE_KEY) != null) { /** #microsoft.graph.user or #microsoft.graph.callrecords.callrecord */ final String odataType = jsonObject.get(ODATA_TYPE_KEY).getAsString(); - final String derivedType = oDataTypeToClassName.apply(odataType); + final String derivedType = oDataTypeToClassName(odataType); try { Class derivedClass = Class.forName(derivedType); //Check that the derived class inherits from the given parent class @@ -394,7 +385,22 @@ public Class getDerivedClass(@Nonnull final JsonObject jsonObject, @Nullable return null; } - /** + /** + * Convert {@code @odata.type} to proper java class name + * @param odataType to convert + * @return converted class name + */ + @VisibleForTesting + static String oDataTypeToClassName(@Nonnull String odataType) { + Objects.requireNonNull(odataType); + final int lastDotIndex = odataType.lastIndexOf("."); + return (odataType.substring(0, lastDotIndex).toLowerCase(Locale.ROOT) + + ".models." + + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, odataType.substring(lastDotIndex + 1))) + .replace("#", "com."); + } + + /** * Gets the logger in use * * @return a logger diff --git a/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java b/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java index 8b7f66474..4a7b28724 100644 --- a/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java +++ b/src/test/java/com/microsoft/graph/serializer/DefaultSerializerTest.java @@ -11,6 +11,6 @@ class DefaultSerializerTest { @Test void oDataTypeToClassName() { Assertions.assertEquals("com.microsoft.graph.models.Message", - DefaultSerializer.oDataTypeToClassName.apply("#Microsoft.Graph.Message")); + DefaultSerializer.oDataTypeToClassName("#Microsoft.Graph.Message")); } } From cf1e62156588480687f79dd03ebbc4230153e418 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Tue, 31 Aug 2021 15:54:36 +0300 Subject: [PATCH 3/3] #300 DerivedClassIdentifier can't unit class. --- .../serializer/DerivedClassIdentifier.java | 83 +++++++++++++++++++ .../DerivedClassIdentifierTest.java | 18 ++++ 2 files changed, 101 insertions(+) create mode 100644 src/main/java/com/microsoft/graph/serializer/DerivedClassIdentifier.java create mode 100644 src/test/java/com/microsoft/graph/serializer/DerivedClassIdentifierTest.java diff --git a/src/main/java/com/microsoft/graph/serializer/DerivedClassIdentifier.java b/src/main/java/com/microsoft/graph/serializer/DerivedClassIdentifier.java new file mode 100644 index 000000000..2d2fd1d8a --- /dev/null +++ b/src/main/java/com/microsoft/graph/serializer/DerivedClassIdentifier.java @@ -0,0 +1,83 @@ +package com.microsoft.graph.serializer; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.CaseFormat; +import com.google.gson.JsonObject; +import com.microsoft.graph.logger.ILogger; + +import java.util.Locale; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * This class provides methods to get the derived class corresponding to the OData type when deserializing payloads. + */ +public class DerivedClassIdentifier { + + private final static String ODATA_TYPE_KEY = "@odata.type"; + + private final ILogger logger; + + /** + * Creates a new instance of the dereived class identifier. + * + * @param logger The logger to use. + */ + public DerivedClassIdentifier(@Nonnull ILogger logger) { + this.logger = Objects.requireNonNull(logger, "logger parameter cannot be null"); + ; + } + + /** + * Get the derived class for the given JSON object + * This covers scenarios in which the service may return one of several derived types + * of a base object, which it defines using the odata.type parameter + * + * @param jsonObject the raw JSON object of the response + * @param parentClass the parent class the derived class should inherit from + * @return the derived class if found, or null if not applicable + */ + @Nullable + public Class identify(@Nonnull final JsonObject jsonObject, @Nullable final Class parentClass) { + Objects.requireNonNull(jsonObject, "parameter jsonObject cannot be null"); + //Identify the odata.type information if provided + if (jsonObject.get(ODATA_TYPE_KEY) != null) { + /** #microsoft.graph.user or #microsoft.graph.callrecords.callrecord */ + final String odataType = jsonObject.get(ODATA_TYPE_KEY).getAsString(); + final int lastDotIndex = odataType.lastIndexOf("."); + final String derivedType = oDataTypeToClassName(odataType); + try { + Class derivedClass = Class.forName(derivedType); + //Check that the derived class inherits from the given parent class + if (parentClass == null || parentClass.isAssignableFrom(derivedClass)) { + return derivedClass; + } + return null; + } catch (ClassNotFoundException e) { + logger.logDebug("Unable to find a corresponding class for derived type " + derivedType + ". Falling back to parent class."); + //If we cannot determine the derived type to cast to, return null + //This may happen if the API and the SDK are out of sync + return null; + } + } + //If there is no defined OData type, return null + return null; + } + + /** + * Convert {@code @odata.type} to proper java class name + * + * @param odataType to convert + * @return converted class name + */ + @VisibleForTesting + static String oDataTypeToClassName(@Nonnull String odataType) { + Objects.requireNonNull(odataType); + final int lastDotIndex = odataType.lastIndexOf("."); + return (odataType.substring(0, lastDotIndex).toLowerCase(Locale.ROOT) + + ".models." + + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, odataType.substring(lastDotIndex + 1))) + .replace("#", "com."); + } +} diff --git a/src/test/java/com/microsoft/graph/serializer/DerivedClassIdentifierTest.java b/src/test/java/com/microsoft/graph/serializer/DerivedClassIdentifierTest.java new file mode 100644 index 000000000..b73a29f25 --- /dev/null +++ b/src/test/java/com/microsoft/graph/serializer/DerivedClassIdentifierTest.java @@ -0,0 +1,18 @@ +package com.microsoft.graph.serializer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Created by Valentin Popov valentin@archiva.ru on 31.08.2021. + */ +class DerivedClassIdentifierTest { + + @Test + void oDataTypeToClassName() { + Assertions.assertEquals("com.microsoft.graph.models.Message", + DerivedClassIdentifier.oDataTypeToClassName("#Microsoft.Graph.Message")); + } +}