Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.microsoft.kiota.serialization;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.microsoft.kiota.PeriodAndDuration;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeParseException;

public class DefaultGsonBuilder {

private static final TypeAdapter<OffsetDateTime> OFFSET_DATE_TIME =
new TypeAdapter<>() {
@Override
public OffsetDateTime read(JsonReader in) throws IOException {
String stringValue = in.nextString();
try {
return OffsetDateTime.parse(stringValue);
} catch (DateTimeParseException ex) {
// Append UTC offset if it's missing
try {
LocalDateTime localDateTime = LocalDateTime.parse(stringValue);
return localDateTime.atOffset(ZoneOffset.UTC);
} catch (DateTimeParseException ex2) {
throw new JsonSyntaxException(
"Failed parsing '"
+ stringValue
+ "' as OffsetDateTime; at path "
+ in.getPreviousPath(),
ex2);
}
}
}

@Override
public void write(JsonWriter out, OffsetDateTime value) throws IOException {
out.value(value.toString());
}
};

private static final TypeAdapter<LocalDate> LOCAL_DATE =
new TypeAdapter<>() {
@Override
public LocalDate read(JsonReader in) throws IOException {
String stringValue = in.nextString();
try {
return LocalDate.parse(stringValue);
} catch (DateTimeParseException ex) {
throw new JsonSyntaxException(
"Failed parsing '"
+ stringValue
+ "' as LocalDate; at path "
+ in.getPreviousPath(),
ex);
}
}

@Override
public void write(JsonWriter out, LocalDate value) throws IOException {
out.value(value.toString());
}
};

private static final TypeAdapter<LocalTime> LOCAL_TIME =
new TypeAdapter<>() {
@Override
public LocalTime read(JsonReader in) throws IOException {
String stringValue = in.nextString();
try {
return LocalTime.parse(stringValue);
} catch (DateTimeParseException ex) {
throw new JsonSyntaxException(
"Failed parsing '"
+ stringValue
+ "' as LocalTime; at path "
+ in.getPreviousPath(),
ex);
}
}

@Override
public void write(JsonWriter out, LocalTime value) throws IOException {
out.value(value.toString());
}
};

private static final TypeAdapter<PeriodAndDuration> PERIOD_AND_DURATION =
new TypeAdapter<>() {
@Override
public PeriodAndDuration read(JsonReader in) throws IOException {
String stringValue = in.nextString();
try {
return PeriodAndDuration.parse(stringValue);
} catch (DateTimeParseException ex) {
throw new JsonSyntaxException(
"Failed parsing '"
+ stringValue
+ "' as PeriodAndDuration; at path "
+ in.getPreviousPath(),
ex);
}
}

@Override
public void write(JsonWriter out, PeriodAndDuration value) throws IOException {
out.value(value.toString());
}
};

private static final Gson defaultInstance = getDefaultBuilder().create();

public static Gson getDefaultInstance() {
return defaultInstance;
}

public static GsonBuilder getDefaultBuilder() {
return new GsonBuilder()
.registerTypeAdapter(OffsetDateTime.class, OFFSET_DATE_TIME.nullSafe())
.registerTypeAdapter(LocalDate.class, LOCAL_DATE.nullSafe())
.registerTypeAdapter(LocalTime.class, LOCAL_TIME.nullSafe())
.registerTypeAdapter(PeriodAndDuration.class, PERIOD_AND_DURATION.nullSafe());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.microsoft.kiota.serialization;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
Expand All @@ -11,11 +12,8 @@

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.EnumSet;
Expand All @@ -31,13 +29,36 @@
/** ParseNode implementation for JSON */
public class JsonParseNode implements ParseNode {
private final JsonElement currentNode;
protected final Gson gson;

/**
* Creates a new instance of the JsonParseNode class.
* @param node the node to wrap.
* @deprecated use {@link #JsonParseNode(JsonElement, Gson)} instead.
*/
@Deprecated
public JsonParseNode(@Nonnull final JsonElement node) {
currentNode = Objects.requireNonNull(node, "parameter node cannot be null");
this.gson = DefaultGsonBuilder.getDefaultInstance();
}

/**
* Creates a new instance of the JsonParseNode class.
* @param node the node to wrap.
* @param node the node to wrap.
*/
public JsonParseNode(@Nonnull final JsonElement node, @Nonnull final Gson gson) {
currentNode = Objects.requireNonNull(node, "parameter node cannot be null");
this.gson = Objects.requireNonNull(gson, "parameter gson cannot be null");
}

/**
* Creates a new {@link JsonParseNode} for the given {@link JsonElement}.
* @param node the node to wrap.
* @return the newly created {@link JsonParseNode}.
*/
@Nonnull protected JsonParseNode createNewNode(@Nonnull JsonElement node) {
return new JsonParseNode(node, gson);
}

/** {@inheritDoc} */
Expand All @@ -47,7 +68,7 @@ public JsonParseNode(@Nonnull final JsonElement node) {
final JsonObject object = currentNode.getAsJsonObject();
final JsonElement childNodeElement = object.get(identifier);
if (childNodeElement == null) return null;
final JsonParseNode result = new JsonParseNode(childNodeElement);
final JsonParseNode result = createNewNode(childNodeElement);
result.setOnBeforeAssignFieldValues(this.onBeforeAssignFieldValues);
result.setOnAfterAssignFieldValues(this.onAfterAssignFieldValues);
return result;
Expand Down Expand Up @@ -91,43 +112,23 @@ public JsonParseNode(@Nonnull final JsonElement node) {
}

@Nullable public UUID getUUIDValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return UUID.fromString(stringValue);
return gson.fromJson(currentNode, UUID.class);
}

@Nullable public OffsetDateTime getOffsetDateTimeValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
try {
return OffsetDateTime.parse(stringValue);
} catch (DateTimeParseException ex) {
// Append UTC offset if it's missing
try {
LocalDateTime localDateTime = LocalDateTime.parse(stringValue);
return localDateTime.atOffset(ZoneOffset.UTC);
} catch (DateTimeParseException ex2) {
throw ex;
}
}
return gson.fromJson(currentNode, OffsetDateTime.class);
}

@Nullable public LocalDate getLocalDateValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return LocalDate.parse(stringValue);
return gson.fromJson(currentNode, LocalDate.class);
}

@Nullable public LocalTime getLocalTimeValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return LocalTime.parse(stringValue);
return gson.fromJson(currentNode, LocalTime.class);
}

@Nullable public PeriodAndDuration getPeriodAndDurationValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return PeriodAndDuration.parse(stringValue);
return gson.fromJson(currentNode, PeriodAndDuration.class);
}

@Nullable private <T> T getPrimitiveValue(
Expand Down Expand Up @@ -171,7 +172,7 @@ private <T> List<T> iterateOnArray(JsonElement jsonElement, Function<JsonParseNo
final List<T> result = new ArrayList<>();
while (sourceIterator.hasNext()) {
final JsonElement item = sourceIterator.next();
final JsonParseNode itemNode = new JsonParseNode(item);
final JsonParseNode itemNode = createNewNode(item);
itemNode.setOnBeforeAssignFieldValues(this.getOnBeforeAssignFieldValues());
itemNode.setOnAfterAssignFieldValues(this.getOnAfterAssignFieldValues());
result.add(fn.apply(itemNode));
Expand Down Expand Up @@ -237,7 +238,7 @@ else if (element.isJsonPrimitive()) {
element.getAsJsonObject().entrySet()) {
final String fieldKey = fieldEntry.getKey();
final JsonElement fieldValue = fieldEntry.getValue();
final JsonParseNode childNode = new JsonParseNode(fieldValue);
final JsonParseNode childNode = createNewNode(fieldValue);
childNode.setOnBeforeAssignFieldValues(this.getOnBeforeAssignFieldValues());
childNode.setOnAfterAssignFieldValues(this.getOnAfterAssignFieldValues());
propertiesMap.put(fieldKey, childNode.getUntypedValue());
Expand Down Expand Up @@ -294,7 +295,7 @@ private <T extends Parsable> void assignFieldValues(
final JsonElement fieldValue = fieldEntry.getValue();
if (fieldValue.isJsonNull()) continue;
if (fieldDeserializer != null) {
final JsonParseNode itemNode = new JsonParseNode(fieldValue);
final JsonParseNode itemNode = createNewNode(fieldValue);
itemNode.setOnBeforeAssignFieldValues(this.onBeforeAssignFieldValues);
itemNode.setOnAfterAssignFieldValues(this.onAfterAssignFieldValues);
fieldDeserializer.accept(itemNode);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.microsoft.kiota.serialization;

import com.google.gson.Gson;
import com.google.gson.JsonParser;

import jakarta.annotation.Nonnull;
Expand All @@ -22,6 +23,23 @@ public JsonParseNodeFactory() {}

private static final String validContentType = "application/json";

private Gson gson = DefaultGsonBuilder.getDefaultInstance();

/**
* @return the {@link Gson} instance to use for parsing value types.
*/
@Nonnull public Gson getGson() {
return gson;
}

/**
* Specify a custom {@link Gson} instance for parsing value types.
* @param gson the {@link Gson} instance to use.
*/
public void setGson(@Nonnull Gson gson) {
this.gson = gson;
}

/** {@inheritDoc} */
@Override
@Nonnull public ParseNode getParseNode(
Expand All @@ -35,7 +53,7 @@ public JsonParseNodeFactory() {}
}
try (final InputStreamReader reader =
new InputStreamReader(rawResponse, StandardCharsets.UTF_8)) {
return new JsonParseNode(JsonParser.parseReader(reader));
return new JsonParseNode(JsonParser.parseReader(reader), gson);
} catch (IOException ex) {
throw new RuntimeException("could not close the reader", ex);
}
Expand Down
Loading