From 7c2c1e614a1de491473877aba06cd6d81b7b2530 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 13 Sep 2016 21:47:03 +0300 Subject: Utility functions for helping to use elemental.json with Java 8 Change-Id: I7c3cf7be95eaf451be806cb75b7b2a34fc534deb --- .../main/java/com/vaadin/data/util/JsonUtil.java | 247 +++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 server/src/main/java/com/vaadin/data/util/JsonUtil.java (limited to 'server/src/main') diff --git a/server/src/main/java/com/vaadin/data/util/JsonUtil.java b/server/src/main/java/com/vaadin/data/util/JsonUtil.java new file mode 100644 index 0000000000..93f9782ac6 --- /dev/null +++ b/server/src/main/java/com/vaadin/data/util/JsonUtil.java @@ -0,0 +1,247 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.data.util; + +import java.util.AbstractList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.DoubleStream; +import java.util.stream.Stream; + +import elemental.json.Json; +import elemental.json.JsonArray; +import elemental.json.JsonNumber; +import elemental.json.JsonObject; +import elemental.json.JsonType; +import elemental.json.JsonValue; + +/** + * Helpers for using elemental.json. + * + * @author Vaadin Ltd + */ +public class JsonUtil { + + /** + * Collects a stream of JSON values to a JSON array. + */ + private static final class JsonArrayCollector + implements Collector { + @Override + public Supplier supplier() { + return Json::createArray; + } + + @Override + public BiConsumer accumulator() { + return (array, value) -> array.set(array.length(), value); + } + + @Override + public BinaryOperator combiner() { + return (left, right) -> { + for (int i = 0; i < right.length(); i++) { + left.set(left.length(), right. get(i)); + } + return left; + }; + } + + @Override + public Function finisher() { + return Function.identity(); + } + + @Override + public Set characteristics() { + return ARRAY_COLLECTOR_CHARACTERISTICS; + } + } + + private static final Set ARRAY_COLLECTOR_CHARACTERISTICS = Collections + .unmodifiableSet( + EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); + + private JsonUtil() { + // Static-only class + } + + /** + * Compares two JSON values for deep equality. + *

+ * This is a helper for overcoming the fact that {@link JsonValue} doesn't + * override {@link Object#equals(Object)} and + * {@link JsonValue#jsEquals(JsonValue)} is defined to use JavaScript + * semantics where arrays and objects are equals only based on identity. + * + * @param a + * the first JSON value to check, may not be null + * @param b + * the second JSON value to check, may not be null + * @return true if both JSON values are the same; + * false otherwise + */ + public static boolean jsonEquals(JsonValue a, JsonValue b) { + assert a != null; + assert b != null; + + if (a == b) { + return true; + } + + JsonType type = a.getType(); + if (type != b.getType()) { + return false; + } + + switch (type) { + case NULL: + return true; + case BOOLEAN: + return a.asBoolean() == b.asBoolean(); + case NUMBER: + return Double.doubleToRawLongBits(a.asNumber()) == Double + .doubleToRawLongBits(b.asNumber()); + case STRING: + return a.asString().equals(b.asString()); + case OBJECT: + return jsonObjectEquals((JsonObject) a, (JsonObject) b); + case ARRAY: + return jsonArrayEquals((JsonArray) a, (JsonArray) b); + default: + throw new IllegalArgumentException("Unsupported JsonType: " + type); + } + } + + private static boolean jsonObjectEquals(JsonObject a, JsonObject b) { + assert a != null; + assert b != null; + + if (a == b) { + return true; + } + + String[] keys = a.keys(); + + if (keys.length != b.keys().length) { + return false; + } + + for (String key : keys) { + JsonValue value = b.get(key); + if (value == null || !jsonEquals(a.get(key), value)) { + return false; + } + } + + return true; + } + + private static boolean jsonArrayEquals(JsonArray a, JsonArray b) { + assert a != null; + assert b != null; + + if (a == b) { + return true; + } + + if (a.length() != b.length()) { + return false; + } + for (int i = 0; i < a.length(); i++) { + if (!jsonEquals(a.get(i), b.get(i))) { + return false; + } + } + return true; + } + + /** + * Creates a stream from a JSON array. + * + * @param array + * the JSON array to create a stream from + * @return a stream of JSON values + */ + public static Stream stream(JsonArray array) { + assert array != null; + return new AbstractList() { + @Override + public T get(int index) { + return array.get(index); + } + + @Override + public int size() { + return array.length(); + } + }.stream(); + } + + /** + * Creates a stream from a JSON array of objects. This method does not + * verify that all items in the array are actually JSON objects instead of + * some other JSON type. + * + * @param array + * the JSON array to create a stream from + * @return a stream of JSON objects + */ + public static Stream objectStream(JsonArray array) { + return stream(array); + } + + /** + * Creates a double stream from a JSON array of numbers. This method does + * not verify that all items in the array are actually JSON numbers instead + * of some other JSON type. + * + * @param array + * the JSON array to create a stream from + * @return a double stream of the values in the array + */ + public static DoubleStream numberStream(JsonArray array) { + return JsonUtil. stream(array) + .mapToDouble(JsonNumber::getNumber); + } + + /** + * Creates a collector that collects values into a JSON array. + * + * @return the collector + */ + public static Collector asArray() { + return new JsonArrayCollector(); + } + + /** + * Creates a new JSON array with the given values. + * + * @param values + * the values that should be in the created array + * @return the created array + */ + public static JsonArray createArray(JsonValue... values) { + return Stream.of(values).collect(asArray()); + } +} -- cgit v1.2.3