Skip to content

Commit efa5a49

Browse files
authored
Merge pull request #167 from microsoftgraph/bugfix/default-post-content-type-and-primitive-types
bugfix/default post content type and primitive types
2 parents 886811a + b812269 commit efa5a49

File tree

5 files changed

+253
-10
lines changed

5 files changed

+253
-10
lines changed

src/main/java/com/microsoft/graph/http/CoreHttpProvider.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,7 @@ public <Result, Body> Request getHttpRequest(@Nonnull final IHttpRequest request
268268
// This ensures that the Content-Length header is properly set
269269
if (request.getHttpMethod() == HttpMethod.POST) {
270270
bytesToWrite = new byte[0];
271-
if(contenttype == null) {
272-
contenttype = BINARY_CONTENT_TYPE;
273-
}
274-
}
275-
else {
271+
} else {
276272
bytesToWrite = null;
277273
}
278274
} else if (serializable instanceof byte[]) {
@@ -329,7 +325,11 @@ public void writeTo(BufferedSink sink) throws IOException {
329325

330326
@Override
331327
public MediaType contentType() {
332-
return MediaType.parse(mediaContentType);
328+
if(mediaContentType == null || mediaContentType.isEmpty()) {
329+
return null;
330+
} else {
331+
return MediaType.parse(mediaContentType);
332+
}
333333
}
334334
};
335335
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.microsoft.graph.serializer;
2+
3+
import java.lang.reflect.Type;
4+
import java.math.BigDecimal;
5+
import java.util.UUID;
6+
7+
import com.google.gson.JsonElement;
8+
import com.google.gson.JsonParseException;
9+
import com.microsoft.graph.logger.ILogger;
10+
11+
import javax.annotation.Nonnull;
12+
import javax.annotation.Nullable;
13+
14+
/** Deserializer for native EDM types from the service. Used for actions and functions that return native types for example. */
15+
public class EdmNativeTypeSerializer {
16+
/**
17+
* Deserializes native EDM types from the service. Used for actions and functions that return native types for example.
18+
* @param <T> Expected return type.
19+
* @param json json to deserialize.
20+
* @param type class of the expected return type.
21+
* @param logger logger to use.
22+
* @return the deserialized type or null.
23+
*/
24+
@Nullable
25+
public static <T> T deserialize(@Nonnull final JsonElement json, @Nonnull final Class<T> type, @Nonnull final ILogger logger) {
26+
if (json == null || type == null) {
27+
return null;
28+
} else if(json.isJsonPrimitive()) {
29+
return getPrimitiveValue(json, type);
30+
} else if(json.isJsonObject()) {
31+
final JsonElement element = json.getAsJsonObject().get("@odata.null");
32+
if(element != null && element.isJsonPrimitive()) {
33+
return getPrimitiveValue(element, type);
34+
} else {
35+
return null;
36+
}
37+
}
38+
return null;
39+
}
40+
@SuppressWarnings("unchecked")
41+
private static <T> T getPrimitiveValue(final JsonElement json, final Class<T> type) {
42+
if(type == Boolean.class) {
43+
return (T) Boolean.valueOf(json.getAsBoolean());
44+
} else if(type == String.class) {
45+
return (T)json.getAsString();
46+
} else if(type == Integer.class) {
47+
return (T) Integer.valueOf(json.getAsInt());
48+
} else if(type == UUID.class) {
49+
return (T) UUID.fromString(json.getAsString());
50+
} else if(type == Long.class) {
51+
return (T) Long.valueOf(json.getAsLong());
52+
} else if (type == Float.class) {
53+
return (T) Float.valueOf(json.getAsFloat());
54+
} else if (type == BigDecimal.class) {
55+
return (T) json.getAsBigDecimal();
56+
} else {
57+
return null;
58+
}
59+
}
60+
}

src/main/java/com/microsoft/graph/serializer/GsonFactory.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@
3838

3939
import com.microsoft.graph.core.TimeOfDay;
4040
import java.lang.reflect.Type;
41+
import java.math.BigDecimal;
4142
import java.text.ParseException;
4243
import java.time.OffsetDateTime;
4344
import java.util.Arrays;
4445
import java.util.EnumSet;
4546
import java.util.GregorianCalendar;
47+
import java.util.UUID;
4648

4749
import javax.xml.datatype.DatatypeFactory;
4850
import javax.xml.datatype.Duration;
@@ -254,8 +256,78 @@ public TimeOfDay deserialize(final JsonElement json,
254256
}
255257
};
256258

259+
final JsonDeserializer<Boolean> booleanJsonDeserializer = new JsonDeserializer<Boolean>() {
260+
@Override
261+
public Boolean deserialize(final JsonElement json,
262+
final Type typeOfT,
263+
final JsonDeserializationContext context) throws JsonParseException {
264+
return EdmNativeTypeSerializer.deserialize(json, Boolean.class, logger);
265+
}
266+
};
267+
268+
final JsonDeserializer<String> stringJsonDeserializer = new JsonDeserializer<String>() {
269+
@Override
270+
public String deserialize(final JsonElement json,
271+
final Type typeOfT,
272+
final JsonDeserializationContext context) throws JsonParseException {
273+
return EdmNativeTypeSerializer.deserialize(json, String.class, logger);
274+
}
275+
};
276+
277+
final JsonDeserializer<BigDecimal> bigDecimalJsonDeserializer = new JsonDeserializer<BigDecimal>() {
278+
@Override
279+
public BigDecimal deserialize(final JsonElement json,
280+
final Type typeOfT,
281+
final JsonDeserializationContext context) throws JsonParseException {
282+
return EdmNativeTypeSerializer.deserialize(json, BigDecimal.class, logger);
283+
}
284+
};
285+
286+
final JsonDeserializer<Integer> integerJsonDeserializer = new JsonDeserializer<Integer>() {
287+
@Override
288+
public Integer deserialize(final JsonElement json,
289+
final Type typeOfT,
290+
final JsonDeserializationContext context) throws JsonParseException {
291+
return EdmNativeTypeSerializer.deserialize(json, Integer.class, logger);
292+
}
293+
};
294+
295+
final JsonDeserializer<Long> longJsonDeserializer = new JsonDeserializer<Long>() {
296+
@Override
297+
public Long deserialize(final JsonElement json,
298+
final Type typeOfT,
299+
final JsonDeserializationContext context) throws JsonParseException {
300+
return EdmNativeTypeSerializer.deserialize(json, Long.class, logger);
301+
}
302+
};
303+
304+
final JsonDeserializer<UUID> uuidJsonDeserializer = new JsonDeserializer<UUID>() {
305+
@Override
306+
public UUID deserialize(final JsonElement json,
307+
final Type typeOfT,
308+
final JsonDeserializationContext context) throws JsonParseException {
309+
return EdmNativeTypeSerializer.deserialize(json, UUID.class, logger);
310+
}
311+
};
312+
313+
final JsonDeserializer<Float> floatJsonDeserializer = new JsonDeserializer<Float>() {
314+
@Override
315+
public Float deserialize(final JsonElement json,
316+
final Type typeOfT,
317+
final JsonDeserializationContext context) throws JsonParseException {
318+
return EdmNativeTypeSerializer.deserialize(json, Float.class, logger);
319+
}
320+
};
321+
257322
return new GsonBuilder()
258323
.excludeFieldsWithoutExposeAnnotation()
324+
.registerTypeAdapter(Boolean.class, booleanJsonDeserializer)
325+
.registerTypeAdapter(String.class, stringJsonDeserializer)
326+
.registerTypeAdapter(Float.class, floatJsonDeserializer)
327+
.registerTypeAdapter(Integer.class, integerJsonDeserializer)
328+
.registerTypeAdapter(BigDecimal.class, bigDecimalJsonDeserializer)
329+
.registerTypeAdapter(UUID.class, uuidJsonDeserializer)
330+
.registerTypeAdapter(Long.class, longJsonDeserializer)
259331
.registerTypeAdapter(OffsetDateTime.class, calendarJsonSerializer)
260332
.registerTypeAdapter(OffsetDateTime.class, calendarJsonDeserializer)
261333
.registerTypeAdapter(GregorianCalendar.class, calendarJsonSerializer)

src/test/java/com/microsoft/graph/http/CoreHttpProviderTests.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import com.google.gson.JsonPrimitive;
99

1010
import com.microsoft.graph.core.GraphErrorCodes;
11+
import com.microsoft.graph.core.IBaseClient;
1112
import com.microsoft.graph.logger.ILogger;
1213
import com.microsoft.graph.logger.LoggerLevel;
1314
import com.microsoft.graph.options.HeaderOption;
15+
import com.microsoft.graph.options.Option;
1416
import com.microsoft.graph.serializer.DefaultSerializer;
1517
import com.microsoft.graph.serializer.ISerializer;
1618

@@ -21,7 +23,9 @@
2123
import java.io.InputStream;
2224
import java.net.URL;
2325
import java.nio.charset.StandardCharsets;
26+
import java.util.ArrayList;
2427
import java.util.Arrays;
28+
import java.util.Collections;
2529

2630
import okhttp3.Call;
2731
import okhttp3.MediaType;
@@ -33,6 +37,7 @@
3337

3438
import static org.junit.jupiter.api.Assertions.assertEquals;
3539
import static org.junit.jupiter.api.Assertions.assertFalse;
40+
import static org.junit.jupiter.api.Assertions.assertNull;
3641
import static org.junit.jupiter.api.Assertions.assertTrue;
3742
import static org.junit.jupiter.api.Assertions.fail;
3843
import static org.mockito.ArgumentMatchers.any;
@@ -63,14 +68,14 @@ public void testErrorResponse() throws Exception {
6368
mProvider.send(mRequest, Object.class, null);
6469
fail("Expected exception in previous statement");
6570
} catch (final GraphServiceException e) {
66-
assertTrue(e.getMessage().indexOf("truncated") > 0);
71+
assertTrue(e.getMessage().indexOf("truncated") > 0);
6772
assertEquals(expectedMessage, e.getServiceError().message);
6873
}
6974
}
7075

7176
@Test
7277
public void testVerboseErrorResponse() throws Exception {
73-
final GraphErrorCodes expectedErrorCode = GraphErrorCodes.INVALID_REQUEST;
78+
final GraphErrorCodes expectedErrorCode = GraphErrorCodes.INVALID_REQUEST;
7479
final String expectedMessage = "Test error!";
7580
final GraphErrorResponse toSerialize = new GraphErrorResponse();
7681
toSerialize.error = new GraphError();
@@ -97,8 +102,8 @@ public void testVerboseErrorResponse() throws Exception {
97102
mProvider.send(mRequest, Object.class, null);
98103
fail("Expected exception in previous statement");
99104
} catch (final GraphServiceException e) {
100-
assertFalse(e.getMessage().indexOf("truncated") > 0);
101-
assertTrue(e.getMessage().indexOf("The raw request was invalid") < 0);
105+
assertFalse(e.getMessage().indexOf("truncated") > 0);
106+
assertTrue(e.getMessage().indexOf("The raw request was invalid") < 0);
102107
}
103108
}
104109

@@ -139,6 +144,36 @@ public void testStreamToStringReturnsEmpty() {
139144
String convertedData = CoreHttpProvider.streamToString(inputStream);
140145
assertEquals("", convertedData);
141146
}
147+
@Test
148+
public void emptyPostContentTypeIsNotReset() {
149+
final String contentTypeValue = "application/json";
150+
final HeaderOption ctype = new HeaderOption("Content-Type", contentTypeValue);
151+
final ArrayList<Option> options = new ArrayList<>();
152+
options.add(ctype);
153+
final IHttpRequest absRequest = new BaseRequest<String>("https://localhost", mock(IBaseClient.class), options, String.class) {{
154+
this.setHttpMethod(HttpMethod.POST);
155+
}};
156+
final ISerializer serializer = mock(ISerializer.class);
157+
final ILogger logger = mock(ILogger.class);
158+
mProvider = new CoreHttpProvider(serializer,
159+
logger,
160+
new OkHttpClient.Builder().build());
161+
final Request request = mProvider.getHttpRequest(absRequest, String.class, null);
162+
assertEquals(contentTypeValue, request.body().contentType().toString());
163+
}
164+
@Test
165+
public void emptyPostContentTypeIsNotSet() {
166+
final IHttpRequest absRequest = new BaseRequest<String>("https://localhost", mock(IBaseClient.class), Collections.emptyList(), String.class) {{
167+
this.setHttpMethod(HttpMethod.POST);
168+
}};
169+
final ISerializer serializer = mock(ISerializer.class);
170+
final ILogger logger = mock(ILogger.class);
171+
mProvider = new CoreHttpProvider(serializer,
172+
logger,
173+
new OkHttpClient.Builder().build());
174+
final Request request = mProvider.getHttpRequest(absRequest, String.class, null);
175+
assertNull(request.body().contentType());
176+
}
142177

143178

144179
/**
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.microsoft.graph.serializer;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.math.BigDecimal;
6+
import java.util.UUID;
7+
8+
import com.microsoft.graph.logger.DefaultLogger;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
public class EdmNativeTypeSerializerTests {
13+
@Test
14+
public void testBoolean() throws Exception {
15+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
16+
17+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":true}";
18+
final Boolean result = serializer.deserializeObject(source, Boolean.class);
19+
20+
assertEquals(Boolean.valueOf(true), result);
21+
}
22+
@Test
23+
public void testInteger() throws Exception {
24+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
25+
26+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12}";
27+
final Integer result = serializer.deserializeObject(source, Integer.class);
28+
29+
assertEquals(Integer.valueOf(12), result);
30+
}
31+
@Test
32+
public void testString() throws Exception {
33+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
34+
35+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":\"toto\"}";
36+
final String result = serializer.deserializeObject(source, String.class);
37+
38+
assertEquals("toto", result);
39+
}
40+
@Test
41+
public void testFloat() throws Exception {
42+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
43+
44+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12.5}";
45+
final Float result = serializer.deserializeObject(source, Float.class);
46+
47+
assertEquals(Float.valueOf("12.5"), result);
48+
}
49+
@Test
50+
public void testLong() throws Exception {
51+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
52+
53+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12}";
54+
final Long result = serializer.deserializeObject(source, Long.class);
55+
56+
assertEquals(Long.valueOf(12), result);
57+
}
58+
@Test
59+
public void testBigDecimal() throws Exception {
60+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
61+
62+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":12}";
63+
final BigDecimal result = serializer.deserializeObject(source, BigDecimal.class);
64+
65+
assertEquals(BigDecimal.valueOf(12), result);
66+
}
67+
@Test
68+
public void testUUID() throws Exception {
69+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
70+
71+
final String source = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Edm.Null\",\"@odata.null\":\"0E6558C3-9640-4385-860A-2A894AC5C246\"}";
72+
final UUID result = serializer.deserializeObject(source, UUID.class);
73+
74+
assertEquals(UUID.fromString("0E6558C3-9640-4385-860A-2A894AC5C246"), result);
75+
}
76+
}

0 commit comments

Comments
 (0)