Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9b035dd
Bump mockito-inline from 3.11.1 to 3.11.2
dependabot[bot] Jun 22, 2021
6f89ae6
Bump mockito-inline from 3.11.1 to 3.11.2
dependabot[bot] Jun 22, 2021
367cf36
Merge pull request #243 from microsoftgraph/dependabot/gradle/org.moc…
baywet Jun 22, 2021
2bdca56
Merge pull request #244 from microsoftgraph/dependabot/maven/org.mock…
baywet Jun 22, 2021
dc596a8
Bump azure-core from 1.17.0 to 1.18.0
dependabot[bot] Jul 2, 2021
39fb4a1
Bump azure-core from 1.17.0 to 1.18.0
dependabot[bot] Jul 2, 2021
d6388ac
Merge pull request #245 from microsoftgraph/dependabot/gradle/com.azu…
baywet Jul 2, 2021
f8a44b0
Merge pull request #246 from microsoftgraph/dependabot/maven/com.azur…
baywet Jul 2, 2021
c201034
Sprout for fix which downcasts parametrized nested `IJsonBackedObject…
PrimosK Jul 13, 2021
8b7dc5b
Bumps patch version also in pom.xml
PrimosK Jul 13, 2021
43a34ed
Merge pull request #250 from PrimosK/patch-1
baywet Jul 13, 2021
7ecec8e
Applied proposed changes.
PrimosK Jul 13, 2021
e6c9423
Update CODEOWNERS
ramsessanchez Jul 14, 2021
5a4a79f
Merge pull request #251 from microsoftgraph/ramsessanchez-addingSelfT…
baywet Jul 14, 2021
59a3098
Fixes "Access to private field logger of class FallbackTypeAdapterFac…
PrimosK Jul 15, 2021
ba9993b
Improves the logic which makes sure that custom IJsonBackedObject typ…
PrimosK Jul 19, 2021
1305d42
Added unit test covering case in PR #249.
PrimosK Jul 19, 2021
3b6be7c
Moved `ODataTypeParametrizedIJsonBackedObjectAdapter` to it's own file.
PrimosK Jul 21, 2021
88eca42
Increased unit tests coverage.
PrimosK Jul 21, 2021
69df140
Removed DerivedClassIdentifier and related code from:
PrimosK Jul 21, 2021
29d9b8f
Merge pull request #249 from PrimosK/dev
ramsessanchez Jul 26, 2021
94b30f0
Bump target android SDK version to 31
ramsessanchez Jul 26, 2021
c35dc62
Merge pull request #254 from microsoftgraph/ramsessanchez-patch-1
baywet Jul 27, 2021
f6cec76
update to 2.0.8 from 2.0.7
ramsessanchez Aug 2, 2021
123b1bb
Bump from version 2.0.7 to 2.0.8
ramsessanchez Aug 2, 2021
c9c2f8c
Merge pull request #255 from microsoftgraph/rsh/updateVersions
baywet Aug 3, 2021
b579e11
fixed serialization problems for mime messages
Aug 4, 2021
161fa3e
Add support to set a setting to serialize null values using the Defau…
ddellsperger Aug 4, 2021
2444eca
added unit test for "text/plain" request bodies
Aug 5, 2021
8debce9
- fixes a linting issue for null check
baywet Aug 5, 2021
bb3f954
- adds missing javadoc comments
baywet Aug 5, 2021
d772567
Updated based on PR feedback
ddellsperger Aug 5, 2021
c55ac30
Merge pull request #258 from mmertens93/dev
ramsessanchez Aug 5, 2021
9744dff
Merge pull request #260 from ddellsperger/serialize-nulls
ramsessanchez Aug 5, 2021
2af4aae
- code linting
baywet Aug 6, 2021
1caf683
- adds javadoc comments for serializing null values parameters
baywet Aug 6, 2021
0b9319e
Merge pull request #262 from microsoftgraph/bugfix/linting-and-releas…
baywet Aug 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @baywet @ddyett @MichaelMainer @nikithauc @zengin
* @baywet @ddyett @MichaelMainer @nikithauc @zengin @ramsessanchez
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ apply plugin: "com.android.library"
apply plugin: "com.github.ben-manes.versions"

android {
compileSdkVersion 30
compileSdkVersion 31

defaultConfig {
versionCode 1
versionName "1.0"
minSdkVersion 26
targetSdkVersion 30
targetSdkVersion 31
}

buildTypes {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mavenGroupId = com.microsoft.graph
mavenArtifactId = microsoft-graph-core
mavenMajorVersion = 2
mavenMinorVersion = 0
mavenPatchVersion = 7
mavenPatchVersion = 8
mavenArtifactSuffix =

#These values are used to run functional tests
Expand Down
4 changes: 2 additions & 2 deletions gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ dependencies {
// Use JUnit test framework
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
testImplementation 'org.mockito:mockito-inline:3.11.1'
testImplementation 'org.mockito:mockito-inline:3.11.2'

api 'com.squareup.okhttp3:okhttp:4.9.1'

implementation 'com.google.guava:guava:30.1.1-jre'

implementation 'com.google.code.gson:gson:2.8.7'
api 'com.azure:azure-core:1.17.0'
api 'com.azure:azure-core:1.18.0'
}
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph-core</artifactId>
<version>2.0.2</version>
<version>2.0.8</version>
<packaging>pom</packaging>

<properties>
Expand All @@ -35,7 +35,7 @@
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core</artifactId>
<version>1.17.0</version>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand All @@ -46,8 +46,8 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.11.1</version>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
</project>
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repositories {

dependencies {
// Include the sdk as a dependency
implementation 'com.microsoft.graph:microsoft-graph-core:2.0.7'
implementation 'com.microsoft.graph:microsoft-graph-core:2.0.8'
// This dependency is only needed if you are using the TokenCrendentialAuthProvider
implementation 'com.azure:azure-identity:1.3.1'
}
Expand All @@ -37,7 +37,7 @@ Add the dependency in `dependencies` in pom.xml
<!-- Include the sdk as a dependency -->
<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph-core</artifactId>
<version>2.0.7</version>
<version>2.0.8</version>
<!-- This dependency is only needed if you are using the TokenCrendentialAuthProvider -->
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/microsoft/graph/http/CoreHttpProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,15 @@ public <Result, Body> Request getHttpRequest(@Nonnull final IHttpRequest request
}
} else {
logger.logDebug("Sending " + serializable.getClass().getName() + " as request body");
final String serializeObject = serializer.serializeObject(serializable);

String serializeObject = null;

if ("text/plain".equals(contenttype) && serializable instanceof String) {
serializeObject = (String)serializable;
} else {
serializeObject = serializer.serializeObject(serializable);
}

if(serializeObject == null) {
throw new ClientException("Error during serialization of request body, the result was null", null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class TelemetryHandler implements Interceptor{
/**
* Current SDK version
*/
public static final String VERSION = "v2.0.7";
public static final String VERSION = "v2.0.8";
/**
* Verion prefix
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

Expand Down Expand Up @@ -112,7 +111,7 @@ public static <T1, T2 extends BaseRequestBuilder<T1>> BaseCollectionPage<T1, T2>
final Class<?> responseClass = Class.forName(responseClassCanonicalName);
final JsonObject responseJson = new JsonObject();
responseJson.add("value", json);
final BaseCollectionResponse<T1> response = CollectionResponseSerializer.deserialize(responseJson, responseClass, logger);
final BaseCollectionResponse<T1> response = CollectionResponseDeserializer.deserialize(responseJson, responseClass, logger);
/** eg: com.microsoft.graph.requests.AttachmentCollectionRequestBuilder */
final String responseBuilderCanonicalName = responseClassCanonicalName
.substring(0, responseClassCanonicalName.length() - responseLength) + "RequestBuilder";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@
import com.microsoft.graph.http.BaseCollectionResponse;
import com.microsoft.graph.logger.ILogger;

/** Specialized serializer to handle collection responses */
public class CollectionResponseSerializer {
/** Specialized de-serializer to handle collection responses */
public class CollectionResponseDeserializer {
private static DefaultSerializer serializer;
/**
* Not available for instantiation
*/
private CollectionResponseSerializer() {}
private CollectionResponseDeserializer() {}
/**
* Deserializes the JsonElement
*
Expand Down Expand Up @@ -86,15 +86,7 @@ public static <T1> BaseCollectionResponse<T1> deserialize(@Nonnull final JsonEle
for(JsonElement sourceElement : sourceArray) {
if(sourceElement.isJsonObject()) {
final JsonObject sourceObject = sourceElement.getAsJsonObject();
Class<?> entityClass = serializer.getDerivedClass(sourceObject, baseEntityClass);
if(entityClass == null) {
if(baseEntityClass == null) {
logger.logError("Could not find target class for object " + sourceObject.toString(), null);
continue;
} else
entityClass = baseEntityClass; // it is possible the odata type is absent or we can't find the derived type (not in SDK yet)
}
final T1 targetObject = (T1)serializer.deserializeObject(sourceObject, entityClass);
final T1 targetObject = (T1)serializer.deserializeObject(sourceObject, baseEntityClass);
((IJsonBackedObject)targetObject).setRawObject(serializer, sourceObject);
list.add(targetObject);
} else if (sourceElement.isJsonPrimitive()) {
Expand Down
94 changes: 30 additions & 64 deletions src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@

package com.microsoft.graph.serializer;

import com.google.common.base.CaseFormat;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import com.microsoft.graph.logger.ILogger;

import java.io.IOException;
Expand All @@ -38,38 +36,55 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Map.Entry;

import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* The default serializer implementation for the SDK
*/
public class DefaultSerializer implements ISerializer {
private static final String graphResponseHeadersKey = "graphResponseHeaders";

private static final String GRAPH_RESPONSE_HEADERS_KEY = "graphResponseHeaders";

/**
* The logger
*/
private final ILogger logger;

/**
* The instance of the internal serializer
*/
private final Gson gson;

/**
* The logger
*/
private final ILogger logger;

/**
* Creates a DefaultSerializer
*
* @param logger the logger
*/
public DefaultSerializer(@Nonnull final ILogger logger) {
this.logger = Objects.requireNonNull(logger, "parameter logger cannot be null");
this.gson = GsonFactory.getGsonInstance(logger);
this(logger, false);
}


/**
* Creates a DefaultSerializer with an option to enable serializing of the null values.
*
* Serializing of null values can have side effects on the service behavior.
* Sending null values in a PATCH request might reset existing values on the service side.
* Sending null values in a POST request might prevent the service from assigning default values to the properties.
* It is not recommended to send null values to the service in general and this setting should only be used when serializing information for a local store.
*
* @param logger the logger
* @param serializeNulls the setting of whether or not to serialize the null values in the JSON object
*/
public DefaultSerializer(@Nonnull final ILogger logger, @Nonnull final boolean serializeNulls) {
this.logger = Objects.requireNonNull(logger, "parameter logger cannot be null");
this.gson = GsonFactory.getGsonInstance(logger, serializeNulls);
}

@Override
@Nullable
public <T> T deserializeObject(@Nonnull final String inputString, @Nonnull final Class<T> clazz, @Nullable final Map<String, List<String>> responseHeaders) {
Expand Down Expand Up @@ -104,16 +119,7 @@ public <T> T deserializeObject(@Nonnull final JsonElement rawElement, @Nonnull f
if (jsonObject instanceof IJsonBackedObject) {
logger.logDebug("Deserializing type " + clazz.getSimpleName());
final JsonObject rawObject = rawElement.isJsonObject() ? rawElement.getAsJsonObject() : null;

// If there is a derived class, try to get it and deserialize to it
T jo = jsonObject;
if (rawElement.isJsonObject()) {
final Class<?> derivedClass = this.getDerivedClass(rawObject, clazz);
if (derivedClass != null)
jo = (T) gson.fromJson(rawElement, derivedClass);
}

final IJsonBackedObject jsonBackedObject = (IJsonBackedObject) jo;
final IJsonBackedObject jsonBackedObject = (IJsonBackedObject) jsonObject;

if(rawElement.isJsonObject()) {
jsonBackedObject.setRawObject(this, rawObject);
Expand All @@ -123,9 +129,9 @@ public <T> T deserializeObject(@Nonnull final JsonElement rawElement, @Nonnull f

if (responseHeaders != null) {
JsonElement convertedHeaders = gson.toJsonTree(responseHeaders);
jsonBackedObject.additionalDataManager().put(graphResponseHeadersKey, convertedHeaders);
jsonBackedObject.additionalDataManager().put(GRAPH_RESPONSE_HEADERS_KEY, convertedHeaders);
}
return jo;
return jsonObject;
} else {
logger.logDebug("Deserializing a non-IJsonBackedObject type " + clazz.getSimpleName());
return jsonObject;
Expand Down Expand Up @@ -304,52 +310,12 @@ private void addAdditionalDataFromJsonObjectToJson (final Object item, final Jso
*/
private void addAdditionalDataFromManagerToJson(AdditionalDataManager additionalDataManager, JsonObject jsonNode) {
for (Map.Entry<String, JsonElement> entry : additionalDataManager.entrySet()) {
if(!entry.getKey().equals(graphResponseHeadersKey)) {
if(!entry.getKey().equals(GRAPH_RESPONSE_HEADERS_KEY)) {
jsonNode.add(entry.getKey(), entry.getValue());
}
}
}

private final static String ODATA_TYPE_KEY = "@odata.type";
/**
* 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<?> getDerivedClass(@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 = (odataType.substring(0, lastDotIndex) +
".models." +
CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,
odataType.substring(lastDotIndex + 1)))
.replace("#", "com.");
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;
}

/**
* Gets the logger in use
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.microsoft.graph.serializer;

import com.google.common.base.CaseFormat;
import com.google.gson.JsonObject;
import com.microsoft.graph.logger.ILogger;

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 = (odataType.substring(0, lastDotIndex) +
".models." +
CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,
odataType.substring(lastDotIndex + 1)))
.replace("#", "com.");
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;
}
}
Loading