Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 6 additions & 6 deletions src/main/java/com/microsoft/graph/http/CoreHttpProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,7 @@ public <Result, Body> Request getHttpRequest(@Nonnull final IHttpRequest request
// This ensures that the Content-Length header is properly set
if (request.getHttpMethod() == HttpMethod.POST) {
bytesToWrite = new byte[0];
if(contenttype == null) {
contenttype = BINARY_CONTENT_TYPE;
}
}
else {
} else {
bytesToWrite = null;
}
} else if (serializable instanceof byte[]) {
Expand Down Expand Up @@ -329,7 +325,11 @@ public void writeTo(BufferedSink sink) throws IOException {

@Override
public MediaType contentType() {
return MediaType.parse(mediaContentType);
if(mediaContentType == null || mediaContentType.isEmpty()) {
return null;
} else {
return MediaType.parse(mediaContentType);
}
}
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.microsoft.graph.serializer;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.UUID;

import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.microsoft.graph.logger.ILogger;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/** Deserializer for native EDM types from the service. Used for actions and functions that return native types for example. */
public class EdmNativeTypeSerializer {
/**
* Deserializes native EDM types from the service. Used for actions and functions that return native types for example.
* @param <T> Expected return type.
* @param json json to deserialize.
* @param type class of the expected return type.
* @param logger logger to use.
* @return the deserialized type or null.
*/
@Nullable
public static <T> T deserialize(@Nonnull final JsonElement json, @Nonnull final Class<T> type, @Nonnull final ILogger logger) {
if (json == null || type == null) {
return null;
} else if(json.isJsonPrimitive()) {
return getPrimitiveValue(json, type);
} else if(json.isJsonObject()) {
final JsonElement element = json.getAsJsonObject().get("@odata.null");
if(element != null && element.isJsonPrimitive()) {
return getPrimitiveValue(element, type);
} else {
return null;
}
}
return null;
}
@SuppressWarnings("unchecked")
private static <T> T getPrimitiveValue(final JsonElement json, final Class<T> type) {
if(type == Boolean.class) {
return (T) Boolean.valueOf(json.getAsBoolean());
} else if(type == String.class) {
return (T)json.getAsString();
} else if(type == Integer.class) {
return (T) Integer.valueOf(json.getAsInt());
} else if(type == UUID.class) {
return (T) UUID.fromString(json.getAsString());
} else if(type == Long.class) {
return (T) Long.valueOf(json.getAsLong());
} else if (type == Float.class) {
return (T) Float.valueOf(json.getAsFloat());
} else if (type == BigDecimal.class) {
return (T) json.getAsBigDecimal();
} else {
return null;
}
}
}
72 changes: 72 additions & 0 deletions src/main/java/com/microsoft/graph/serializer/GsonFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@

import com.microsoft.graph.core.TimeOfDay;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.GregorianCalendar;
import java.util.UUID;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
Expand Down Expand Up @@ -254,8 +256,78 @@ public TimeOfDay deserialize(final JsonElement json,
}
};

final JsonDeserializer<Boolean> booleanJsonDeserializer = new JsonDeserializer<Boolean>() {
@Override
public Boolean deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, Boolean.class, logger);
}
};

final JsonDeserializer<String> stringJsonDeserializer = new JsonDeserializer<String>() {
@Override
public String deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, String.class, logger);
}
};

final JsonDeserializer<BigDecimal> bigDecimalJsonDeserializer = new JsonDeserializer<BigDecimal>() {
@Override
public BigDecimal deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, BigDecimal.class, logger);
}
};

final JsonDeserializer<Integer> integerJsonDeserializer = new JsonDeserializer<Integer>() {
@Override
public Integer deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, Integer.class, logger);
}
};

final JsonDeserializer<Long> longJsonDeserializer = new JsonDeserializer<Long>() {
@Override
public Long deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, Long.class, logger);
}
};

final JsonDeserializer<UUID> uuidJsonDeserializer = new JsonDeserializer<UUID>() {
@Override
public UUID deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, UUID.class, logger);
}
};

final JsonDeserializer<Float> floatJsonDeserializer = new JsonDeserializer<Float>() {
@Override
public Float deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
return EdmNativeTypeSerializer.deserialize(json, Float.class, logger);
}
};

return new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(Boolean.class, booleanJsonDeserializer)
.registerTypeAdapter(String.class, stringJsonDeserializer)
.registerTypeAdapter(Float.class, floatJsonDeserializer)
.registerTypeAdapter(Integer.class, integerJsonDeserializer)
.registerTypeAdapter(BigDecimal.class, bigDecimalJsonDeserializer)
.registerTypeAdapter(UUID.class, uuidJsonDeserializer)
.registerTypeAdapter(Long.class, longJsonDeserializer)
.registerTypeAdapter(OffsetDateTime.class, calendarJsonSerializer)
.registerTypeAdapter(OffsetDateTime.class, calendarJsonDeserializer)
.registerTypeAdapter(GregorianCalendar.class, calendarJsonSerializer)
Expand Down
43 changes: 39 additions & 4 deletions src/test/java/com/microsoft/graph/http/CoreHttpProviderTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import com.google.gson.JsonPrimitive;

import com.microsoft.graph.core.GraphErrorCodes;
import com.microsoft.graph.core.IBaseClient;
import com.microsoft.graph.logger.ILogger;
import com.microsoft.graph.logger.LoggerLevel;
import com.microsoft.graph.options.HeaderOption;
import com.microsoft.graph.options.Option;
import com.microsoft.graph.serializer.DefaultSerializer;
import com.microsoft.graph.serializer.ISerializer;

Expand All @@ -21,7 +23,9 @@
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

import okhttp3.Call;
import okhttp3.MediaType;
Expand All @@ -33,6 +37,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
Expand Down Expand Up @@ -63,14 +68,14 @@ public void testErrorResponse() throws Exception {
mProvider.send(mRequest, Object.class, null);
fail("Expected exception in previous statement");
} catch (final GraphServiceException e) {
assertTrue(e.getMessage().indexOf("truncated") > 0);
assertTrue(e.getMessage().indexOf("truncated") > 0);
assertEquals(expectedMessage, e.getServiceError().message);
}
}

@Test
public void testVerboseErrorResponse() throws Exception {
final GraphErrorCodes expectedErrorCode = GraphErrorCodes.INVALID_REQUEST;
final GraphErrorCodes expectedErrorCode = GraphErrorCodes.INVALID_REQUEST;
final String expectedMessage = "Test error!";
final GraphErrorResponse toSerialize = new GraphErrorResponse();
toSerialize.error = new GraphError();
Expand All @@ -97,8 +102,8 @@ public void testVerboseErrorResponse() throws Exception {
mProvider.send(mRequest, Object.class, null);
fail("Expected exception in previous statement");
} catch (final GraphServiceException e) {
assertFalse(e.getMessage().indexOf("truncated") > 0);
assertTrue(e.getMessage().indexOf("The raw request was invalid") < 0);
assertFalse(e.getMessage().indexOf("truncated") > 0);
assertTrue(e.getMessage().indexOf("The raw request was invalid") < 0);
}
}

Expand Down Expand Up @@ -139,6 +144,36 @@ public void testStreamToStringReturnsEmpty() {
String convertedData = CoreHttpProvider.streamToString(inputStream);
assertEquals("", convertedData);
}
@Test
public void emptyPostContentTypeIsNotReset() {
final String contentTypeValue = "application/json";
final HeaderOption ctype = new HeaderOption("Content-Type", contentTypeValue);
final ArrayList<Option> options = new ArrayList<>();
options.add(ctype);
final IHttpRequest absRequest = new BaseRequest<String>("https://localhost", mock(IBaseClient.class), options, String.class) {{
this.setHttpMethod(HttpMethod.POST);
}};
final ISerializer serializer = mock(ISerializer.class);
final ILogger logger = mock(ILogger.class);
mProvider = new CoreHttpProvider(serializer,
logger,
new OkHttpClient.Builder().build());
final Request request = mProvider.getHttpRequest(absRequest, String.class, null);
assertEquals(contentTypeValue, request.body().contentType().toString());
}
@Test
public void emptyPostContentTypeIsNotSet() {
final IHttpRequest absRequest = new BaseRequest<String>("https://localhost", mock(IBaseClient.class), Collections.emptyList(), String.class) {{
this.setHttpMethod(HttpMethod.POST);
}};
final ISerializer serializer = mock(ISerializer.class);
final ILogger logger = mock(ILogger.class);
mProvider = new CoreHttpProvider(serializer,
logger,
new OkHttpClient.Builder().build());
final Request request = mProvider.getHttpRequest(absRequest, String.class, null);
assertNull(request.body().contentType());
}


/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.microsoft.graph.serializer;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.math.BigDecimal;
import java.util.UUID;

import com.microsoft.graph.logger.DefaultLogger;

import org.junit.jupiter.api.Test;

public class EdmNativeTypeSerializerTests {
@Test
public void testBoolean() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":true}";
final Boolean result = serializer.deserializeObject(source, Boolean.class);

assertEquals(Boolean.valueOf(true), result);
}
@Test
public void testInteger() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12}";
final Integer result = serializer.deserializeObject(source, Integer.class);

assertEquals(Integer.valueOf(12), result);
}
@Test
public void testString() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":\"toto\"}";
final String result = serializer.deserializeObject(source, String.class);

assertEquals("toto", result);
}
@Test
public void testFloat() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12.5}";
final Float result = serializer.deserializeObject(source, Float.class);

assertEquals(Float.valueOf("12.5"), result);
}
@Test
public void testLong() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12}";
final Long result = serializer.deserializeObject(source, Long.class);

assertEquals(Long.valueOf(12), result);
}
@Test
public void testBigDecimal() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12}";
final BigDecimal result = serializer.deserializeObject(source, BigDecimal.class);

assertEquals(BigDecimal.valueOf(12), result);
}
@Test
public void testUUID() throws Exception {
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());

final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":\"0E6558C3-9640-4385-860A-2A894AC5C246\"}";
final UUID result = serializer.deserializeObject(source, UUID.class);

assertEquals(UUID.fromString("0E6558C3-9640-4385-860A-2A894AC5C246"), result);
}
}