Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indent

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those damn tabs keep creeping on me. Thanks for noticing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub makes it easy to show these because of weird tab width choice, whether it is a good or a bad thing.

I am really curious to know as to why VSCode is not applying .editorconfig on save for you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd be interesting to see if using VS code on this repo (just check-out this branch to the commit before I fixed that mixed indent style), hitting ctrl + S on the file, it fixes it automatically for you. I had to do an explicit ctrl + h.
Here is the extension I'm using https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me give it a try.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turns out space conversion is not available on save: https://github.com/editorconfig/editorconfig-vscode#supported-properties.

If all your projects are using spaces, you may want to configure editor.insertSpaces in vscode settings. editor.renderWhitespace also helps in visualizing space types, so that you can tell when you need to hit that extra ctrl+h.

There is also this extension, but it ignores the space configuration in .editorconfig. It always applies 4 spaces: https://marketplace.visualstudio.com/items?itemName=redlin.remove-tabs-on-save

Visual Studio applies the .editorconfig spacing rules on save for C# files, so my expectation was similar with VSCode.

IntellijIDEA doesn't apply tab->space on save though it inserts new line at the end. But if you format the code, it does the conversion and respects the .editorconfig rules (tested with 8 spaces).

Maybe a little friction on Java development in VSCode to "share" in that BarcelonaJUG conference ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative to Ctrl+H for tabs to spaces is: Command Palette (F1 or Ctrl+Shift+P) -> Convert Indentation to Spaces, which respects .editorconfig.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into it! This is probably another case of Vincent getting confused by the tools. I do have auto final line insertion on save in TypeScript and yaml but this is probably because of other extensions. I do also have white space trim on save for all languages I believe?
I'll try to make the ctrl shift p alternative a habit and maybe if I get tired of doing that I'll go pr the editor config extension.

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);
}
}