
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