com.microsoft.kiota.serialization.JsonParseNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of microsoft-kiota-serialization-json Show documentation
Show all versions of microsoft-kiota-serialization-json Show documentation
Microsoft Kiota-Serialization for Json
package com.microsoft.kiota.serialization;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.microsoft.kiota.PeriodAndDuration;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
/** ParseNode implementation for JSON */
public class JsonParseNode implements ParseNode {
private final JsonElement currentNode;
/**
* Creates a new instance of the JsonParseNode class.
* @param node the node to wrap.
*/
public JsonParseNode(@Nonnull final JsonElement node) {
currentNode = Objects.requireNonNull(node, "parameter node cannot be null");
}
/** {@inheritDoc} */
@Nullable public ParseNode getChildNode(@Nonnull final String identifier) {
Objects.requireNonNull(identifier, "identifier parameter is required");
if (currentNode.isJsonObject()) {
final JsonObject object = currentNode.getAsJsonObject();
final JsonElement childNodeElement = object.get(identifier);
if (childNodeElement == null) return null;
final JsonParseNode result = new JsonParseNode(childNodeElement);
result.setOnBeforeAssignFieldValues(this.onBeforeAssignFieldValues);
result.setOnAfterAssignFieldValues(this.onAfterAssignFieldValues);
return result;
} else return null;
}
@Nullable public String getStringValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsString() : null;
}
@Nullable public Boolean getBooleanValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsBoolean() : null;
}
@Nullable public Byte getByteValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsByte() : null;
}
@Nullable public Short getShortValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsShort() : null;
}
@Nullable public BigDecimal getBigDecimalValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsBigDecimal() : null;
}
@Nullable public Integer getIntegerValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsInt() : null;
}
@Nullable public Float getFloatValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsFloat() : null;
}
@Nullable public Double getDoubleValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsDouble() : null;
}
@Nullable public Long getLongValue() {
return currentNode.isJsonPrimitive() ? currentNode.getAsLong() : null;
}
@Nullable public UUID getUUIDValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return UUID.fromString(stringValue);
}
@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;
}
}
}
@Nullable public LocalDate getLocalDateValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return LocalDate.parse(stringValue);
}
@Nullable public LocalTime getLocalTimeValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return LocalTime.parse(stringValue);
}
@Nullable public PeriodAndDuration getPeriodAndDurationValue() {
final String stringValue = currentNode.getAsString();
if (stringValue == null) return null;
return PeriodAndDuration.parse(stringValue);
}
@Nullable private T getPrimitiveValue(
@Nonnull final Class targetClass, @Nonnull final JsonParseNode itemNode) {
if (targetClass == Boolean.class) {
return (T) itemNode.getBooleanValue();
} else if (targetClass == Short.class) {
return (T) itemNode.getShortValue();
} else if (targetClass == Byte.class) {
return (T) itemNode.getByteValue();
} else if (targetClass == BigDecimal.class) {
return (T) itemNode.getBigDecimalValue();
} else if (targetClass == String.class) {
return (T) itemNode.getStringValue();
} else if (targetClass == Integer.class) {
return (T) itemNode.getIntegerValue();
} else if (targetClass == Float.class) {
return (T) itemNode.getFloatValue();
} else if (targetClass == Long.class) {
return (T) itemNode.getLongValue();
} else if (targetClass == UUID.class) {
return (T) itemNode.getUUIDValue();
} else if (targetClass == OffsetDateTime.class) {
return (T) itemNode.getOffsetDateTimeValue();
} else if (targetClass == LocalDate.class) {
return (T) itemNode.getLocalDateValue();
} else if (targetClass == LocalTime.class) {
return (T) itemNode.getLocalTimeValue();
} else if (targetClass == PeriodAndDuration.class) {
return (T) itemNode.getPeriodAndDurationValue();
} else {
throw new RuntimeException("unknown type to deserialize " + targetClass.getName());
}
}
private List iterateOnArray(JsonElement jsonElement, Function fn) {
JsonArray array = jsonElement.getAsJsonArray();
final Iterator sourceIterator = array.iterator();
final List result = new ArrayList<>();
while (sourceIterator.hasNext()) {
final JsonElement item = sourceIterator.next();
final JsonParseNode itemNode = new JsonParseNode(item);
itemNode.setOnBeforeAssignFieldValues(this.getOnBeforeAssignFieldValues());
itemNode.setOnAfterAssignFieldValues(this.getOnAfterAssignFieldValues());
result.add(fn.apply(itemNode));
}
return result;
}
@Nullable public List getCollectionOfPrimitiveValues(@Nonnull final Class targetClass) {
Objects.requireNonNull(targetClass, "parameter targetClass cannot be null");
if (currentNode.isJsonNull()) {
return null;
} else if (currentNode.isJsonArray()) {
return iterateOnArray(
currentNode, itemNode -> getPrimitiveValue(targetClass, itemNode));
} else throw new RuntimeException("invalid state expected to have an array node");
}
@Nullable public List getCollectionOfObjectValues(
@Nonnull final ParsableFactory factory) {
Objects.requireNonNull(factory, "parameter factory cannot be null");
if (currentNode.isJsonNull()) {
return null;
} else if (currentNode.isJsonArray()) {
return iterateOnArray(currentNode, itemNode -> itemNode.getObjectValue(factory));
} else return null;
}
@Nullable public > List getCollectionOfEnumValues(
@Nonnull final ValuedEnumParser enumParser) {
Objects.requireNonNull(enumParser, "parameter enumParser cannot be null");
if (currentNode.isJsonNull()) {
return null;
} else if (currentNode.isJsonArray()) {
return iterateOnArray(currentNode, itemNode -> itemNode.getEnumValue(enumParser));
} else throw new RuntimeException("invalid state expected to have an array node");
}
@Nonnull public T getObjectValue(@Nonnull final ParsableFactory factory) {
Objects.requireNonNull(factory, "parameter factory cannot be null");
final T item = factory.create(this);
if (item.getClass() == UntypedNode.class) return (T) getUntypedValue();
assignFieldValues(item, item.getFieldDeserializers());
return item;
}
@Nonnull private UntypedNode getUntypedValue() {
return getUntypedValue(currentNode);
}
@Nonnull private UntypedNode getUntypedValue(JsonElement element) {
if (element.isJsonNull()) return new UntypedNull();
else if (element.isJsonPrimitive()) {
final JsonPrimitive primitive = element.getAsJsonPrimitive();
if (primitive.isBoolean()) return new UntypedBoolean(primitive.getAsBoolean());
else if (primitive.isString()) return new UntypedString(primitive.getAsString());
else if (primitive.isNumber()) return new UntypedDouble(primitive.getAsDouble());
else
throw new RuntimeException(
"Could not get the value during deserialization, unknown primitive type");
} else if (element.isJsonObject()) {
HashMap propertiesMap = new HashMap<>();
for (final Map.Entry fieldEntry :
element.getAsJsonObject().entrySet()) {
final String fieldKey = fieldEntry.getKey();
final JsonElement fieldValue = fieldEntry.getValue();
final JsonParseNode childNode = new JsonParseNode(fieldValue);
childNode.setOnBeforeAssignFieldValues(this.getOnBeforeAssignFieldValues());
childNode.setOnAfterAssignFieldValues(this.getOnAfterAssignFieldValues());
propertiesMap.put(fieldKey, childNode.getUntypedValue());
}
return new UntypedObject(propertiesMap);
} else if (element.isJsonArray()) {
return new UntypedArray(iterateOnArray(element, JsonParseNode::getUntypedValue));
}
throw new RuntimeException(
"Could not get the value during deserialization, unknown json value type");
}
@Nullable public > T getEnumValue(@Nonnull final ValuedEnumParser enumParser) {
final String rawValue = this.getStringValue();
if (rawValue == null || rawValue.isEmpty()) {
return null;
}
return enumParser.forValue(rawValue);
}
@Nullable public > EnumSet getEnumSetValue(
@Nonnull final ValuedEnumParser enumParser) {
final String rawValue = this.getStringValue();
if (rawValue == null || rawValue.isEmpty()) {
return null;
}
final List result = new ArrayList<>();
final String[] rawValues = rawValue.split(",");
for (final String rawValueItem : rawValues) {
final T value = enumParser.forValue(rawValueItem);
if (value != null) {
result.add(value);
}
}
return EnumSet.copyOf(result);
}
private void assignFieldValues(
final T item, final Map> fieldDeserializers) {
if (currentNode.isJsonObject()) {
if (this.onBeforeAssignFieldValues != null) {
this.onBeforeAssignFieldValues.accept(item);
}
Map itemAdditionalData = null;
if (item instanceof AdditionalDataHolder) {
itemAdditionalData = ((AdditionalDataHolder) item).getAdditionalData();
}
for (final Map.Entry fieldEntry :
currentNode.getAsJsonObject().entrySet()) {
final String fieldKey = fieldEntry.getKey();
final Consumer fieldDeserializer = fieldDeserializers.get(fieldKey);
final JsonElement fieldValue = fieldEntry.getValue();
if (fieldValue.isJsonNull()) continue;
if (fieldDeserializer != null) {
final JsonParseNode itemNode = new JsonParseNode(fieldValue);
itemNode.setOnBeforeAssignFieldValues(this.onBeforeAssignFieldValues);
itemNode.setOnAfterAssignFieldValues(this.onAfterAssignFieldValues);
fieldDeserializer.accept(itemNode);
} else if (itemAdditionalData != null)
itemAdditionalData.put(fieldKey, this.tryGetAnything(fieldValue));
}
if (this.onAfterAssignFieldValues != null) {
this.onAfterAssignFieldValues.accept(item);
}
}
}
private Object tryGetAnything(final JsonElement element) {
if (element.isJsonNull()) return null;
else if (element.isJsonPrimitive()) {
final JsonPrimitive primitive = element.getAsJsonPrimitive();
if (primitive.isBoolean()) return primitive.getAsBoolean();
else if (primitive.isString()) return primitive.getAsString();
else if (primitive.isNumber()) return primitive.getAsDouble();
else
throw new RuntimeException(
"Could not get the value during deserialization, unknown primitive type");
} else if (element.isJsonObject() || element.isJsonArray()) return getUntypedValue(element);
else
throw new RuntimeException(
"Could not get the value during deserialization, unknown primitive type");
}
@Nullable public Consumer getOnBeforeAssignFieldValues() {
return this.onBeforeAssignFieldValues;
}
@Nullable public Consumer getOnAfterAssignFieldValues() {
return this.onAfterAssignFieldValues;
}
private Consumer onBeforeAssignFieldValues;
public void setOnBeforeAssignFieldValues(@Nullable final Consumer value) {
this.onBeforeAssignFieldValues = value;
}
private Consumer onAfterAssignFieldValues;
public void setOnAfterAssignFieldValues(@Nullable final Consumer value) {
this.onAfterAssignFieldValues = value;
}
@Nullable public byte[] getByteArrayValue() {
final String base64 = this.getStringValue();
if (base64 == null || base64.isEmpty()) {
return null;
}
return Base64.getDecoder().decode(base64);
}
}