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

io.datakernel.http.decoder.DecodeErrors Maven / Gradle / Ivy

package io.datakernel.http.decoder;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.function.BiFunction;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toList;

/**
 * A tree of https errors. It structure matches the structure of the decoder is was received from
 */
public final class DecodeErrors {
	private static final String DEFAULT_SEPARATOR = ".";

	@Nullable
	private List errors;
	@Nullable
	private Map children;

	private DecodeErrors() {}

	public static DecodeErrors create() {
		return new DecodeErrors();
	}

	public static DecodeErrors of(String message, Object... args) {
		return create().with(DecodeError.of(message, args));
	}

	public static DecodeErrors of(@NotNull DecodeError error) {
		return create().with(error);
	}

	public static DecodeErrors of(@NotNull List errors) {
		return create().with(errors);
	}

	public DecodeErrors with(@NotNull DecodeError error) {
		if (this.errors == null) this.errors = new ArrayList<>();
		this.errors.add(error);
		return this;
	}

	public DecodeErrors with(@NotNull List errors) {
		if (this.errors == null) this.errors = new ArrayList<>();
		this.errors.addAll(errors);
		return this;
	}

	public DecodeErrors with(@NotNull String id, @NotNull DecodeErrors nestedError) {
		if (children == null) children = new HashMap<>();
		children.merge(id, nestedError, DecodeErrors::merge);
		return this;
	}

	public DecodeErrors merge(DecodeErrors another) {
		if (another.errors != null) {
			if (this.errors == null) {
				this.errors = new ArrayList<>(another.errors);
			} else {
				this.errors.addAll(another.errors);
			}
		}
		if (another.children != null) {
			if (this.children == null) {
				this.children = new HashMap<>(another.children);
			} else {
				for (String key : another.children.keySet()) {
					this.children.merge(key, another.children.get(key), DecodeErrors::merge);
				}
			}
		}
		return this;
	}

	public DecodeErrors with(@NotNull String id, @NotNull DecodeError nestedError) {
		if (children == null) children = new HashMap<>();
		children.computeIfAbsent(id, $ -> new DecodeErrors()).with(nestedError);
		return this;
	}

	public boolean hasErrors() {
		return errors != null || children != null;
	}

	@NotNull
	public List getErrors() {
		return errors != null ? errors : emptyList();
	}

	@NotNull
	public Set getChildren() {
		return children != null ? children.keySet() : emptySet();
	}

	public DecodeErrors getChild(String id) {
		return children != null ? children.get(id) : null;
	}

	public Map toMap() {
		return toMap(String::format);
	}

	public Map toMap(String separator) {
		return toMap(String::format, separator);
	}

	public Map> toMultimap() {
		return toMultimap(String::format);
	}

	public Map> toMultimap(String separator) {
		return toMultimap(String::format, separator);
	}

	public Map toMap(BiFunction formatter) {
		return toMap(formatter, DEFAULT_SEPARATOR);
	}

	public Map toMap(BiFunction formatter, String separator) {
		Map map = new HashMap<>();
		toMapImpl(this, map, "", formatter, separator);
		return map;
	}

	public Map> toMultimap(BiFunction formatter, String separator) {
		Map> multimap = new HashMap<>();
		toMultimapImpl(this, multimap, "", formatter, separator);
		return multimap;
	}

	public Map> toMultimap(BiFunction formatter) {
		return toMultimap(formatter, DEFAULT_SEPARATOR);
	}

	private static void toMultimapImpl(DecodeErrors errors,
			Map> multimap, String prefix,
			BiFunction formatter,
			String separator) {
		if (errors.errors != null) {
			multimap.put(prefix, errors.errors.stream().map(error -> formatter.apply(error.message, error.getArgs())).collect(toList()));
		}
		if (errors.children != null) {
			errors.children.forEach((id, child) -> toMultimapImpl(child, multimap, (prefix.isEmpty() ? "" : prefix + separator) + id, formatter, separator));
		}
	}

	private static void toMapImpl(DecodeErrors errors,
			Map map, String prefix,
			BiFunction formatter,
			String separator) {
		if (errors.errors != null) {
			DecodeError error = errors.errors.get(0);
			map.put(prefix, formatter.apply(error.message, error.getArgs()));
		}
		if (errors.children != null) {
			errors.children.forEach((id, child) -> toMapImpl(child, map, (prefix.isEmpty() ? "" : prefix + separator) + id, formatter, separator));
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy