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

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

package com.microsoft.kiota.serialization;

import com.microsoft.kiota.PeriodAndDuration;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
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.Arrays;
import java.util.Base64;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;

/** ParseNode implementation for URI form encoded payloads */
public class FormParseNode implements ParseNode {
    private final String rawStringValue;
    private final String encoding = StandardCharsets.UTF_8.name();
    private final HashMap fields = new HashMap<>();

    /**
     * Initializes a new instance of the {@link FormParseNode} class.
     * @param rawString the raw string value to parse.
     */
    public FormParseNode(@Nonnull final String rawString) {
        Objects.requireNonNull(rawString, "parameter node cannot be null");
        rawStringValue = rawString;
        for (final String kv : rawString.split("&")) {
            final String[] split = kv.split("=");
            final String key = sanitizeKey(split[0]);
            if (split.length == 2) {
                if (fields.containsKey(key))
                    fields.put(key, fields.get(key).concat("," + split[1].trim()));
                else fields.put(key, split[1].trim());
            }
        }
    }

    @SuppressWarnings("removal")
    protected final void finalize() throws Throwable {
        // this is to prevent finalizer attacks, remove when java 9 is the minimum supported version
    }

    private String sanitizeKey(@Nonnull final String key) {
        Objects.requireNonNull(key);
        try {
            return URLDecoder.decode(key, encoding).trim();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Unsupported encoding", e);
        }
    }

    @Nullable public ParseNode getChildNode(@Nonnull final String identifier) {
        Objects.requireNonNull(identifier, "identifier parameter is required");
        final String key = sanitizeKey(identifier);
        if (fields.containsKey(key)) {
            final Consumer onBefore = this.onBeforeAssignFieldValues;
            final Consumer onAfter = this.onAfterAssignFieldValues;
            final FormParseNode result = new FormParseNode(fields.get(key));
            result.setOnBeforeAssignFieldValues(onBefore);
            result.setOnAfterAssignFieldValues(onAfter);
            return result;
        } else return null;
    }

    @Nullable public String getStringValue() {
        try {
            final String decoded = URLDecoder.decode(rawStringValue, encoding);
            if (decoded.equalsIgnoreCase("null")) return null;
            return decoded;
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    @Nullable public Boolean getBooleanValue() {
        switch (getStringValue()
                .toLowerCase(
                        Locale.ROOT)) { // boolean parse returns false for any value that is not
                // true
            case "true":
            case "1":
                return true;
            case "false":
            case "0":
                return false;
            default:
                return null;
        }
    }

    @Nullable public Byte getByteValue() {
        try {
            return Byte.parseByte(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public Short getShortValue() {
        try {
            return Short.parseShort(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public BigDecimal getBigDecimalValue() {
        try {
            return new BigDecimal(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public Integer getIntegerValue() {
        try {
            return Integer.parseInt(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public Float getFloatValue() {
        try {
            return Float.parseFloat(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public Double getDoubleValue() {
        try {
            return Double.parseDouble(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public Long getLongValue() {
        try {
            return Long.parseLong(getStringValue());
        } catch (final NumberFormatException ex) {
            return null;
        }
    }

    @Nullable public UUID getUUIDValue() {
        final String stringValue = getStringValue();
        if (stringValue == null) return null;
        return UUID.fromString(stringValue);
    }

    @Nullable public OffsetDateTime getOffsetDateTimeValue() {
        final String stringValue = getStringValue();
        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 = getStringValue();
        if (stringValue == null) return null;
        return LocalDate.parse(stringValue);
    }

    @Nullable public LocalTime getLocalTimeValue() {
        final String stringValue = getStringValue();
        if (stringValue == null) return null;
        return LocalTime.parse(stringValue);
    }

    @Nullable public PeriodAndDuration getPeriodAndDurationValue() {
        final String stringValue = getStringValue();
        if (stringValue == null) return null;
        return PeriodAndDuration.parse(stringValue);
    }

    @Nullable public  List getCollectionOfPrimitiveValues(@Nonnull final Class targetClass) {
        final List primitiveStringCollection = Arrays.asList(getStringValue().split(","));
        final Iterator sourceIterator = primitiveStringCollection.iterator();
        final FormParseNode _this = this;
        final List result = new ArrayList<>();
        final Iterable iterable =
                new Iterable() {
                    @Override
                    public Iterator iterator() {
                        return new Iterator() {
                            @Override
                            public boolean hasNext() {
                                return sourceIterator.hasNext();
                            }

                            @Override
                            @SuppressWarnings("unchecked")
                            public T next() {
                                final String item = sourceIterator.next();
                                final Consumer onBefore =
                                        _this.getOnBeforeAssignFieldValues();
                                final Consumer onAfter =
                                        _this.getOnAfterAssignFieldValues();
                                final FormParseNode itemNode =
                                        new FormParseNode(item) {
                                            {
                                                this.setOnBeforeAssignFieldValues(onBefore);
                                                this.setOnAfterAssignFieldValues(onAfter);
                                            }
                                        };
                                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());
                                }
                            }
                        };
                    }
                };

        for (T elem : iterable) {
            result.add(elem);
        }
        return result;
    }

    @Nullable public  List getCollectionOfObjectValues(
            @Nonnull final ParsableFactory factory) {
        throw new RuntimeException(
                "deserialization of collections of is not supported with form encoding");
    }

    @Nullable public > List getCollectionOfEnumValues(
            @Nonnull final ValuedEnumParser enumParser) {
        Objects.requireNonNull(enumParser, "parameter enumParser cannot be null");
        final String stringValue = getStringValue();
        if (stringValue == null || stringValue.isEmpty()) {
            return null;
        } else {
            final String[] array = stringValue.split(",");
            final ArrayList result = new ArrayList<>();
            for (final String item : array) {
                result.add(enumParser.forValue(item));
            }
            return result;
        }
    }

    @Nonnull public  T getObjectValue(@Nonnull final ParsableFactory factory) {
        Objects.requireNonNull(factory, "parameter factory cannot be null");
        final T item = factory.create(this);
        assignFieldValues(item, item.getFieldDeserializers());
        return item;
    }

    @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 (!fields.isEmpty()) {
            if (this.onBeforeAssignFieldValues != null) {
                this.onBeforeAssignFieldValues.accept(item);
            }
            Map itemAdditionalData = null;
            if (item instanceof AdditionalDataHolder) {
                itemAdditionalData = ((AdditionalDataHolder) item).getAdditionalData();
            }
            for (final Map.Entry fieldEntry : fields.entrySet()) {
                final String fieldKey = fieldEntry.getKey();
                final Consumer fieldDeserializer = fieldDeserializers.get(fieldKey);
                final String fieldValue = fieldEntry.getValue();
                if (fieldValue == null) continue;
                if (fieldDeserializer != null) {
                    final Consumer onBefore = this.onBeforeAssignFieldValues;
                    final Consumer onAfter = this.onAfterAssignFieldValues;
                    fieldDeserializer.accept(
                            new FormParseNode(fieldValue) {
                                {
                                    this.setOnBeforeAssignFieldValues(onBefore);
                                    this.setOnAfterAssignFieldValues(onAfter);
                                }
                            });
                } else if (itemAdditionalData != null) itemAdditionalData.put(fieldKey, fieldValue);
            }
            if (this.onAfterAssignFieldValues != null) {
                this.onAfterAssignFieldValues.accept(item);
            }
        }
    }

    @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