All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.kiota.serialization.JsonParseNode Maven / Gradle / Ivy

There is a newer version: 1.8.0
Show newest version
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);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy