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

net.algart.json.Jsons Maven / Gradle / Ivy

Go to download

Open-source libraries, providing the base core functionality for SciChains product.

There is a newer version: 4.4.7
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017-2024 Daniel Alievsky, AlgART Laboratory (http://algart.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.algart.json;

import jakarta.json.*;
import jakarta.json.spi.JsonProvider;
import jakarta.json.stream.JsonGenerator;

import java.awt.*;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;

public class Jsons {

    private static final JsonProvider JSON_PROVIDER = JsonProvider.provider();

    private Jsons() {
    }

    public static JsonObject newEmptyJson() {
        return Json.createObjectBuilder().build();
    }

    public static JsonObject readJson(Path path) throws IOException {
        Objects.requireNonNull(path, "Null path");
        try {
            try (final JsonReader reader = Json.createReader(Files.newBufferedReader(path, StandardCharsets.UTF_8))) {
                return reader.readObject();
            }
        } catch (JsonException e) {
            throw new JsonException("Invalid JSON in the file " + path, e);
        }
    }

    public static JsonObject toJson(String jsonString) {
        Objects.requireNonNull(jsonString, "Null jsonString");
        try (final JsonReader reader = Json.createReader(new StringReader(jsonString))) {
            return reader.readObject();
        }
    }

    public static JsonObject toJson(String jsonString, boolean allowNullOrEmptyString) {
        if (allowNullOrEmptyString && jsonString == null || (jsonString = jsonString.trim()).isEmpty()) {
            return newEmptyJson();
        } else {
            return toJson(jsonString);
        }
    }

    public static JsonArray toJsonArray(String jsonString) {
        Objects.requireNonNull(jsonString, "Null jsonString");
        try (final JsonReader reader = Json.createReader(new StringReader(jsonString))) {
            return reader.readArray();
        }
    }

    public static JsonArray toJsonArray(Collection strings) {
        Objects.requireNonNull(strings, "Null strings");
        final JsonArrayBuilder builder = Json.createArrayBuilder();
        for (String s : strings) {
            builder.add(s);
        }
        return builder.build();
    }

    public static JsonString toJsonStringValue(String value) {
        Objects.requireNonNull(value, "Null value");
        return JSON_PROVIDER.createObjectBuilder().add("x", value).build().getJsonString("x");
        // Unfortunately standard JsonStringImpl constructor is never called outside
        // JsonObjectBuilder and JsonArrayBuilder
    }

    public static JsonNumber toJsonIntValue(int value) {
        return JSON_PROVIDER.createObjectBuilder().add("x", value).build().getJsonNumber("x");
        // See toJsonValue(String)
    }

    public static JsonNumber toJsonLongValue(long value) {
        return JSON_PROVIDER.createObjectBuilder().add("x", value).build().getJsonNumber("x");
        // See toJsonValue(String)
    }

    public static JsonNumber toJsonDoubleValue(double value) {
        return JSON_PROVIDER.createObjectBuilder().add("x", value).build().getJsonNumber("x");
        // See toJsonValue(String)
    }

    public static JsonValue toJsonBooleanValue(boolean value) {
        return value ? JsonValue.TRUE : JsonValue.FALSE;
    }

    public static void addAllJson(JsonObjectBuilder builder, JsonObject existingJson) {
        Objects.requireNonNull(builder, "Null builder");
        Objects.requireNonNull(existingJson, "Null existingJson");
        for (Map.Entry entry : existingJson.entrySet()) {
            builder.add(entry.getKey(), entry.getValue());
        }
    }

    public static JsonObjectBuilder createObjectBuilder(JsonObject existingJson) {
        Objects.requireNonNull(existingJson, "Null existingJson");
        final JsonObjectBuilder builder = Json.createObjectBuilder();
        addAllJson(builder, existingJson);
        return builder;
    }

    public static JsonObject filterJson(JsonObject sourceJson, Set keysToPreserve) {
        Objects.requireNonNull(sourceJson, "Null sourceJson");
        Objects.requireNonNull(keysToPreserve, "Null keysToPreserve");
        final JsonObjectBuilder builder = Json.createObjectBuilder();
        for (Map.Entry entry : sourceJson.entrySet()) {
            final String key = entry.getKey();
            if (keysToPreserve.contains(key)) {
                builder.add(key, entry.getValue());
            }
        }
        return builder.build();
    }

    public static JsonObject overrideEntries(JsonObject sourceJson, JsonObject overridingJson) {
        Objects.requireNonNull(sourceJson, "Null sourceJson");
        Objects.requireNonNull(overridingJson, "Null overridingJson");
        final JsonObjectBuilder builder = createObjectBuilder(sourceJson);
        addAllJson(builder, overridingJson);
        return builder.build();
    }

    public static JsonObject addNonExistingEntries(JsonObject sourceJson, JsonObject overridingJson) {
        Objects.requireNonNull(sourceJson, "Null sourceJson");
        Objects.requireNonNull(overridingJson, "Null overridingJson");
        final JsonObjectBuilder builder = createObjectBuilder(sourceJson);
        for (Map.Entry entry : overridingJson.entrySet()) {
            final String key = entry.getKey();
            if (!sourceJson.containsKey(key)) {
                builder.add(key, entry.getValue());
            }
        }
        return builder.build();
    }

    public static JsonObject overrideOnlyExistingInBoth(JsonObject sourceJson, JsonObject overridingJson) {
        Objects.requireNonNull(sourceJson, "Null sourceJson");
        Objects.requireNonNull(overridingJson, "Null overridingJson");
        final JsonObjectBuilder builder = createObjectBuilder(sourceJson);
        for (Map.Entry entry : overridingJson.entrySet()) {
            final String key = entry.getKey();
            if (sourceJson.containsKey(key)) {
                builder.add(key, entry.getValue());
            }
        }
        return builder.build();
    }

    public static String toPrettyString(JsonValue jsonValue) {
        Objects.requireNonNull(jsonValue, "Null jsonValue");
        switch (jsonValue.getValueType()) {
            case STRING:
                return ((JsonString) jsonValue).getString();
            case OBJECT:
                return toPrettyString((JsonObject) jsonValue);
            case ARRAY:
                return toPrettyString((JsonArray) jsonValue);
            default:
                return jsonValue.toString();
        }
    }

    public static String toPrettyString(JsonObject json) {
        Objects.requireNonNull(json, "Null json");
        JsonWriterFactory jsonWriterFactory = Json.createWriterFactory(
                Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true));
        StringWriter stringWriter = new StringWriter();
        try (JsonWriter jsonWriter = jsonWriterFactory.createWriter(stringWriter)) {
            jsonWriter.writeObject(json);
            return stringWriter.toString().trim();
            // - trim() removes extra starting empty line
        }
    }

    public static String toPrettyString(JsonArray json) {
        Objects.requireNonNull(json, "Null json");
        JsonWriterFactory jsonWriterFactory = Json.createWriterFactory(
                Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true));
        StringWriter stringWriter = new StringWriter();
        try (JsonWriter jsonWriter = jsonWriterFactory.createWriter(stringWriter)) {
            jsonWriter.writeArray(json);
            return stringWriter.toString().trim();
            // - trim() removes extra starting empty line
        }
    }

    public static List toJsonObjects(JsonArray jsonArray) {
        return toJsonObjects(jsonArray, null);
    }

    public static List toJsonObjects(JsonArray jsonArray, String nameForException) {
        return toJsonObjects(jsonArray, nameForException, null);
    }

    public static List toJsonObjects(JsonArray jsonArray, String nameForException, Path file) {
        Objects.requireNonNull(jsonArray, "Null jsonArray");
        final List result = new ArrayList<>();
        for (JsonValue jsonValue : jsonArray) {
            if (!(jsonValue instanceof JsonObject)) {
                throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file) + ": "
                        + (nameForException == null ? "an" : "\"" + nameForException + "\"")
                        + " array contains non-object element " + jsonValue);
            }
            result.add((JsonObject) jsonValue);
        }
        return result;
    }

    public static List toStrings(JsonArray jsonArray) {
        return toStrings(jsonArray, null);
    }

    public static List toStrings(JsonArray jsonArray, String nameForException) {
        return toStrings(jsonArray, nameForException, null);
    }

    public static List toStrings(JsonArray jsonArray, String nameForException, Path file) {
        Objects.requireNonNull(jsonArray, "Null jsonArray");
        final List result = new ArrayList<>();
        for (JsonValue jsonValue : jsonArray) {
            if (!(jsonValue instanceof JsonString)) {
                throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file) + ": "
                        + (nameForException == null ? "an" : "\"" + nameForException + "\"")
                        + " array contains non-string element " + jsonValue);
            }
            result.add(((JsonString) jsonValue).getString());
        }
        return result;
    }

    public static int reqInt(JsonObject json, String name) {
        return reqInt(json, name, null);
    }

    public static int reqInt(JsonObject json, String name, Path file) {
        return reqIntWithAlias(json, name, null, file);
    }

    public static int reqIntWithAlias(JsonObject json, String name, String aliasName, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        JsonNumber result;
        String usedName = name;
        try {
            result = json.getJsonNumber(name);
            if (result == null && aliasName != null) {
                usedName = aliasName;
                result = json.getJsonNumber(aliasName);
            }
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + usedName + "\" value is not a number"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        if (result == null) {
            throw new JsonException("Invalid JSON " + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" numeric value required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result.intValueExact();
    }

    public static void addDouble(JsonObjectBuilder builder, String name, double value) {
        if (value == Double.NEGATIVE_INFINITY) {
            builder.add(name, "\u2212\u221E");
        } else if (value == Double.POSITIVE_INFINITY) {
            builder.add(name, "+\u221E");
        } else if (Double.isNaN(value)) {
            builder.add(name, "NaN");
        } else {
            builder.add(name, value);
        }
    }

    public static double getDouble(JsonObject json, String name, double defaultValue) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        final JsonValue jsonValue = json.get(name);
        if (jsonValue == null) {
            return defaultValue;
        }
        final Double special = specialDoubleValue(jsonValue);
        if (special != null) {
            return special;
        }
        try {
            return ((JsonNumber) jsonValue).doubleValue();
        } catch (Exception e) {
            return defaultValue;
        }
    }

    public static double reqDouble(JsonObject json, String name) {
        return reqDouble(json, name, null);
    }

    public static double reqDouble(JsonObject json, String name, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        final JsonValue jsonValue = json.get(name);
        if (jsonValue == null) {
            throw new JsonException("Invalid JSON " + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" double value required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        final Double special = specialDoubleValue(jsonValue);
        if (special != null) {
            return special;
        }
        JsonNumber result;
        try {
            result = (JsonNumber) jsonValue;
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value is not a number"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result.doubleValue();
    }

    public static long getLong(JsonObject json, String name, long defaultValue) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        try {
            return json.getJsonNumber(name).longValueExact();
        } catch (Exception e) {
            return defaultValue;
        }
    }

    public static long reqLong(JsonObject json, String name) {
        return reqLong(json, name, null);
    }

    public static long reqLong(JsonObject json, String name, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        JsonNumber result;
        try {
            result = json.getJsonNumber(name);
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value is not a number"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        if (result == null) {
            throw new JsonException("Invalid JSON " + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" long value required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result.longValueExact();
    }

    public static String reqString(JsonObject json, String name) {
        return reqString(json, name, null);
    }

    public static String reqString(JsonObject json, String name, Path file) {
        return reqStringWithAlias(json, name, null, file);
    }

    public static String reqStringWithAlias(JsonObject json, String name, String aliasName, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        JsonString result;
        String usedName = name;
        try {
            result = json.getJsonString(name);
            if (result == null && aliasName != null) {
                usedName = aliasName;
                result = json.getJsonString(aliasName);
            }
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + usedName + "\" value is not a string"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        if (result == null) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result.getString();
    }

    public static JsonValue reqJsonValue(JsonObject json, String name) {
        return reqJsonValue(json, name, null);
    }

    public static JsonValue reqJsonValue(JsonObject json, String name, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        final JsonValue result = json.get(name);
        if (result == null) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result;
    }

    public static List getJsonObjectsOrEmptyList(JsonObject json, String name) {
        return getJsonObjectsOrEmptyList(json, name, null);
    }

    public static List getJsonObjectsOrEmptyList(JsonObject json, String name, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        final JsonArray jsonArray = json.getJsonArray(name);
        if (jsonArray == null) {
            return Collections.emptyList();
        }
        return toJsonObjects(jsonArray, name, file);
    }

    public static JsonObject reqJsonObject(JsonObject json, String name) {
        return reqJsonObject(json, name, null);
    }

    public static JsonObject reqJsonObject(JsonObject json, String name, Path file) {
        Objects.requireNonNull(json, "Null json");
        JsonObject result = getJsonObject(json, name, file);
        if (result == null) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" JSON object required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result;
    }

    /**
     * Analog of json.getJsonObject(name) with two differences:
     * 1) if json==null, it returns null;
     * 2) if json contains value with a given name, but it is not an object,
     * it throws detailed {@link JsonException} (instead of ClassCastException).
     *
     * @param json JSON object to by analysed
     * @param name the name whose associated value is to be returned
     * @return the object value to which the specified name is mapped,
     * or null if there is no necessary mapping
     * @throws JsonException if the value to which the specified name is mapped is not assignable to JsonObject type
     */
    public static JsonObject getJsonObject(JsonObject json, String name) {
        return getJsonObject(json, name, null);
    }

    public static JsonObject getJsonObject(JsonObject json, String name, Path file) {
        Objects.requireNonNull(name, "Null name");
        if (json == null) {
            return null;
        }
        try {
            return json.getJsonObject(name);
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value is not a JSON object"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
    }

    public static JsonArray reqJsonArray(JsonObject json, String name, Path file) {
        return reqJsonArray(json, name, file, false);
    }

    public static JsonArray reqJsonArray(JsonObject json, String name, Path file, boolean mustContainOnlyObjects) {
        JsonArray result = getJsonArray(json, name, file, mustContainOnlyObjects);
        if (result == null) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" JSON array required"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return result;
    }

    public static JsonArray getJsonArray(JsonObject json, String name, Path file) {
        return getJsonArray(json, name, file, false);
    }

    public static JsonArray getJsonArray(JsonObject json, String name, Path file, boolean mustContainOnlyObjects) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        final JsonArray result;
        try {
            result = json.getJsonArray(name);
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value is not a JSON array"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        if (mustContainOnlyObjects && result != null) {
            for (JsonValue jsonValue : result) {
                if (!(jsonValue instanceof JsonObject)) {
                    throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file) + ": \"" + name
                            + "\" array contains non-object element " + jsonValue);
                }
            }
        }
        return result;
    }

    public static List reqJsonObjects(JsonObject json, String name) {
        return reqJsonObjects(json, name, null);
    }

    public static List reqJsonObjects(JsonObject json, String name, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        JsonArray jsonArray;
        try {
            jsonArray = json.getJsonArray(name);
        } catch (ClassCastException e) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value is not a JSON array"
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        if (jsonArray == null) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" array required");
        }
        return toJsonObjects(jsonArray, name, file);
    }

    public static String toString(Color color) {
        Objects.requireNonNull(color, "Null color");
        final int rgb = color.getRGB() & 0xFFFFFF;
        return String.format("#%06X", rgb);
    }

    public static Color toColor(String s) {
        Objects.requireNonNull(s, "Null string");
        return Color.decode(s);
    }

    public static  T requireNonNull(T value, JsonObject json, String name) {
        return requireNonNull(value, json, name, null);
    }

    public static  T requireNonNull(T value, JsonObject json, String name, Path file) {
        return requireNonNull(value, json, name, "required", file);
    }

    public static  T requireNonNull(T value, JsonObject json, String name, String message, Path file) {
        Objects.requireNonNull(json, "Null json");
        Objects.requireNonNull(name, "Null name");
        if (value == null) {
            throw new JsonException("Invalid JSON" + (file == null ? "" : " " + file)
                    + ": \"" + name + "\" value is " + message
                    + (file == null ? " <<<" + json + ">>>" : ""));
        }
        return value;
    }


    private static Double specialDoubleValue(JsonValue jsonValue) {
        if (jsonValue.getValueType() == JsonValue.ValueType.STRING) {
            final String s = ((JsonString) jsonValue).getString();
            if ("\u2212\u221E".equals(s)) {
                return Double.NEGATIVE_INFINITY;
            } else if ("+\u221E".equals(s)) {
                return Double.POSITIVE_INFINITY;
            } else if ("NaN".equals(s)) {
                return Double.NaN;
            }
        }
        return null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy