Skip to content

Commit

Permalink
Merge pull request #259 from microsoftgraph/dev
Browse files Browse the repository at this point in the history
release 2.0.8
  • Loading branch information
baywet authored Aug 6, 2021
2 parents 4abc150 + 0b9319e commit 4b07e04
Show file tree
Hide file tree
Showing 25 changed files with 572 additions and 116 deletions.
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

0 comments on commit 4b07e04

Please sign in to comment.