JsonDataBack.java

package space.sunqian.fs.data.json;

import space.sunqian.annotation.Nonnull;
import space.sunqian.annotation.Nullable;
import space.sunqian.fs.Fs;
import space.sunqian.fs.collect.ArrayKit;
import space.sunqian.fs.io.IOKit;
import space.sunqian.fs.io.IORuntimeException;

import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.List;
import java.util.Map;

final class JsonDataBack {

    private interface DefaultData extends JsonData {

        @Override
        default @Nonnull String asString() throws JsonDataException {
            throw new JsonDataException("Current JSON data is not a JSON string.");
        }

        @Override
        default @Nonnull Map<String, Object> asMap() throws JsonDataException {
            throw new JsonDataException("Current JSON data is not a JSON object.");
        }

        @Override
        default @Nonnull List<Object> asList() throws JsonDataException {
            throw new JsonDataException("Current JSON data is not a JSON array.");
        }

        @Override
        default @Nonnull Number asNumber() throws JsonDataException {
            throw new JsonDataException("Current JSON data is not a JSON number.");
        }

        @Override
        default boolean asBoolean() throws JsonDataException {
            throw new JsonDataException("Current JSON data is not a JSON boolean.");
        }

        @Override
        default void writeTo(@Nonnull OutputStream out) throws IORuntimeException {
            writeTo(IOKit.newWriter(out));
        }

        @Override
        default void writeTo(@Nonnull WritableByteChannel channel) throws IORuntimeException {
            writeTo(Channels.newOutputStream(channel));
        }
    }

    abstract static class AbsData implements DefaultData {

        @Override
        public void writeTo(@Nonnull Appendable appender) throws IORuntimeException {
            try {
                doWrite(appender);
            } catch (Exception e) {
                throw new IORuntimeException(e);
            }
        }

        @Override
        public @Nonnull String toString() {
            StringBuilder sb = new StringBuilder();
            writeTo(sb);
            return sb.toString();
        }

        protected abstract void doWrite(@Nonnull Appendable appender) throws Exception;
    }

    enum JsonNull implements DefaultData {
        INST;

        @Override
        public @Nonnull JsonType type() {
            return JsonType.NULL;
        }

        @Override
        public void writeTo(@Nonnull Appendable appender) throws IORuntimeException {
            JsonKit.toJsonString(null, appender);
        }

        @Override
        public @Nonnull String toString() {
            return Fs.NULL_STRING;
        }
    }

    enum JsonBoolean implements DefaultData {
        TRUE(true), FALSE(false);

        private final boolean bool;

        JsonBoolean(boolean bool) {
            this.bool = bool;
        }

        @Override
        public @Nonnull JsonType type() {
            return JsonType.BOOLEAN;
        }

        @Override
        public boolean asBoolean() throws JsonDataException {
            return bool;
        }

        @Override
        public void writeTo(@Nonnull Appendable appender) throws IORuntimeException {
            JsonKit.toJsonString(bool, appender);
        }

        @Override
        public @Nonnull String toString() {
            return Boolean.toString(bool);
        }
    }

    static final class JsonString extends AbsData {

        private final @Nonnull String string;

        JsonString(@Nonnull String string) {
            this.string = string;
        }

        @Override
        public @Nonnull JsonType type() {
            return JsonType.STRING;
        }

        @Override
        public @Nonnull String asString() throws JsonDataException {
            return string;
        }

        @Override
        public void doWrite(@Nonnull Appendable appender) throws Exception {
            appender.append("\"");
            appender.append(string);
            appender.append("\"");
        }
    }

    static final class JsonNumber extends AbsData {

        private final @Nonnull Number number;

        JsonNumber(@Nonnull Number number) {
            this.number = number;
        }

        @Override
        public @Nonnull JsonType type() {
            return JsonType.NUMBER;
        }

        @Override
        public @Nonnull Number asNumber() throws JsonDataException {
            return number;
        }

        @Override
        public void doWrite(@Nonnull Appendable appender) throws Exception {
            appender.append(number.toString());
        }
    }

    static final class JsonObject extends AbsData {

        private final @Nonnull Map<@Nonnull String, @Nullable Object> dataMap;

        JsonObject(@Nonnull Map<@Nonnull String, @Nullable Object> dataMap) {
            this.dataMap = dataMap;
        }

        @Override
        public @Nonnull JsonType type() {
            return JsonType.OBJECT;
        }

        @Override
        public @Nonnull Map<String, Object> asMap() throws JsonDataException {
            return dataMap;
        }

        @Override
        public void doWrite(@Nonnull Appendable appender) {
            JsonKit.toJsonString(dataMap, appender);
        }
    }

    static final class JsonArray extends AbsData {

        private final @Nonnull List<@Nullable Object> dataList;

        JsonArray(@Nonnull List<@Nullable Object> dataList) {
            this.dataList = dataList;
        }

        JsonArray(@Nullable Object @Nonnull [] dataList) {
            this.dataList = ArrayKit.asList(dataList);
        }

        @Override
        public @Nonnull JsonType type() {
            return JsonType.ARRAY;
        }

        @Override
        public @Nonnull List<@Nullable Object> asList() throws JsonDataException {
            return dataList;
        }

        @Override
        public void doWrite(@Nonnull Appendable appender) {
            JsonKit.toJsonString(dataList, appender);
        }
    }

    private JsonDataBack() {
    }
}