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

net.hamnaberg.json.codec.DecodeJson Maven / Gradle / Ivy

There is a newer version: 8.0.0
Show newest version
package net.hamnaberg.json.codec;

import net.hamnaberg.json.Json;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public interface DecodeJson {
    DecodeResult fromJson(Json.JValue value);

    default Optional defaultValue() {
        return Optional.empty();
    }

    default A fromJsonUnsafe(Json.JValue value) {
        return fromJson(value).unsafeGet();
    }

    default  DecodeJson map(Function f) {
        return (json) -> this.fromJson(json).map(f);
    }

    default  DecodeJson tryMap(Function> f) {
        return json -> this.fromJson(json).map(f).flatMap(DecodeResult::fromCallable);
    }

    default  DecodeJson flatMap(Function> f) {
        return value -> {
            DecodeResult result = this.fromJson(value);
            return result.flatMap(a -> f.apply(a).fromJson(value));
        };
    }

    default DecodeJson withDefaultValue(A defaultValue) {
        if (this instanceof DecodeJsonWithDefault) {
            return new DecodeJsonWithDefault<>(((DecodeJsonWithDefault)this).delegate, defaultValue);
        }
        return new DecodeJsonWithDefault<>(this, defaultValue);
    }

    default DecodeJson or(DecodeJson orElse) {
        return value -> fromJson(value).fold(aFail -> orElse.fromJson(value).fold(bFail -> DecodeResult.fail(aFail + " " + bFail), DecodeResult::ok), DecodeResult::ok);
    }

    default  DecodeJson> and(DecodeJson next) {
        return value -> {
            DecodeResult aRes = fromJson(value);
            DecodeResult bRes = next.fromJson(value);
            return aRes.flatMap(a -> bRes.map(b -> Map.entry(a, b)));
        };
    }

    default DecodeJson> option() {
        return Decoders.optionalDecoder(this);
    }

    default DecodeJson> list() {
        return Decoders.listDecoder(this);
    }

    default FieldDecoder fieldDecoder(String name) {
        return FieldDecoder.typedFieldOf(name, this);
    }

    default DecodeJson filter(Predicate p) {
        return filter(p, () -> "Filter failed");
    }

    default DecodeJson filter(Predicate p, Supplier errorSupplier) {
        return value -> fromJson(value).filter(p, errorSupplier);
    }

    static  DecodeJson> sequence(List> toSequence) {
        return value -> DecodeResult.sequence(
                toSequence.stream().map(d -> d.fromJson(value)).collect(Collectors.toUnmodifiableList())
        );
    }

    static  DecodeJson sequence(final Iterable> results, final Collector collector) {
        return value ->
                DecodeResult.sequence(
                        () -> StreamSupport.stream(results.spliterator(), false).map(d -> d.fromJson(value)).iterator(),
                        collector
                );
    }

    static  DecodeJson successful(A value) {
        return result(DecodeResult.ok(value));
    }

    static  DecodeJson failure(String message) {
        return result(DecodeResult.fail(message));
    }

    static  DecodeJson result(DecodeResult value) {
        return ignore -> value;
    }

    class DecodeJsonWithDefault implements DecodeJson {
        final DecodeJson delegate;
        private final A defaultValue;

        public DecodeJsonWithDefault(DecodeJson delegate, A defaultValue) {
            this.delegate = delegate;
            this.defaultValue = defaultValue;
        }

        @Override
        public DecodeResult fromJson(Json.JValue value) {
            DecodeResult res = delegate.fromJson(value);
            return res.fold(ignore -> DecodeResult.ok(defaultValue), DecodeResult::ok);
        }

        @Override
        public Optional defaultValue() {
            return Optional.of(defaultValue);
        }

        @Override
        public String toString() {
            return getClass().getSimpleName() + String.format(" {delegate=%s, default=%s}", delegate, defaultValue);
        }
    }
}