Last active
February 12, 2023 15:18
-
-
Save agentgt/78bd22d473d52d6e0c4ff9c45d5cd7d0 to your computer and use it in GitHub Desktop.
Config.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface Config extends Iterable<PropertyString> { | |
/* | |
* Required methods to implement | |
*/ | |
public Config withPrefix(String prefix); | |
public Stream<PropertyString> stream(); | |
public PropertyString property(String name); | |
default Function<String, String> asFunction() { | |
PropertyFunction<String, String> pf = this::property; | |
return pf; | |
} | |
@Override | |
default Iterator<PropertyString> iterator() { | |
return stream().iterator(); | |
} | |
public interface Key { | |
String name(); | |
default String description() { | |
return "\"" + name() + "\""; | |
} | |
} | |
public interface Property<T> extends Key { | |
default <R> R to(Function<? super T, ? extends R> f) { | |
try { | |
return f.apply(get()); | |
} | |
catch (IllegalArgumentException e) { | |
throw new PropertyConvertException(this, e); | |
} | |
} | |
default int toInt(ToIntFunction<T> f) { | |
try { | |
return f.applyAsInt(get()); | |
} | |
catch (IllegalArgumentException e) { | |
throw new PropertyConvertException(this, e); | |
} | |
} | |
default long toLong(ToLongFunction<T> f) { | |
try { | |
return f.applyAsLong(get()); | |
} | |
catch (IllegalArgumentException e) { | |
throw new PropertyConvertException(this, e); | |
} | |
} | |
default boolean toBoolean(Predicate<T> f) { | |
try { | |
return f.test(get()); | |
} | |
catch (IllegalArgumentException e) { | |
throw new PropertyConvertException(this, e); | |
} | |
} | |
default PropertyString toProperty(Function<? super T, String> f) { | |
return new SupplierStringProperty(this, () -> to(f)); | |
} | |
default <R> Property<R> map(Function<? super T, ? extends R> f) { | |
return new SupplierProperty<>(this, () -> to(f)); | |
} | |
/* | |
* TODO flatMap... not sure how to combine | |
*/ | |
default <R> Property<R> flatMap(Function<? super T, ? extends Property<? extends R>> f) { | |
throw new UnsupportedOperationException(); | |
} | |
default Optional<T> toOptional() { | |
return Optional.ofNullable(orNull()); | |
} | |
default T orElse(T fallback) { | |
var e = orNull(); | |
if (e == null) { | |
return fallback; | |
} | |
return e; | |
} | |
default boolean isMissing() { | |
return orNull() == null; | |
} | |
default T get() { | |
T v = orNull(); | |
if (v == null) { | |
throw new PropertyMissingException(this); | |
} | |
return v; | |
} | |
public @Nullable T orNull(); | |
default void set(BiConsumer<String, T> consumer) { | |
consumer.accept(name(), get()); | |
} | |
default void set(Consumer<T> consumer) { | |
consumer.accept(get()); | |
} | |
} | |
interface PropertyFunction<T, R> extends Function<T, R> { | |
@Override | |
default R apply(T t) { | |
return property(t).get(); | |
} | |
public Property<? extends R> property(T t); | |
@Override | |
default <V> PropertyFunction<T, V> andThen(Function<? super R, ? extends V> after) { | |
return t -> property(t).map(after); | |
} | |
@Override | |
default <V> PropertyFunction<V, R> compose(Function<? super V, ? extends T> before) { | |
return t -> property(before.apply(t)); | |
} | |
} | |
public interface PropertyString extends Property<String> { | |
default int toInt() { | |
return toInt(Integer::parseInt); | |
} | |
default long toLong() { | |
return toLong(Long::parseLong); | |
} | |
default boolean toBoolean() { | |
return toBoolean(Boolean::parseBoolean); | |
} | |
} | |
public record KeyValue(String name, // | |
String value, // | |
String rawValue, // | |
String sourceName, // | |
int sourceOrdinal) implements PropertyString { | |
public static KeyValue of(Entry<String, String> e, String sourceName, int index) { | |
return new KeyValue(e.getKey(), e.getValue(), e.getValue(), sourceName, index); | |
} | |
public static List<KeyValue> of(Iterator<? extends Entry<String, String>> entries, String sourceName) { | |
List<KeyValue> kvs = new ArrayList<>(); | |
int i = 0; | |
while (entries.hasNext()) { | |
kvs.add(of(entries.next(), sourceName, i++)); | |
} | |
return kvs; | |
} | |
@Override | |
public @Nullable String orNull() { | |
return value; | |
} | |
@Override | |
public String name() { | |
return name; | |
} | |
public String toString() { | |
StringBuilder sb = new StringBuilder(); | |
sb.append(this.getClass().getSimpleName()).append("(").append(description()).append(")"); | |
return sb.toString(); | |
} | |
public StringBuilder description(StringBuilder sb) { | |
sb.append(name()); | |
if (!sourceName.isBlank()) { | |
sb.append(" <-- [").append(sourceName).append(":").append(sourceOrdinal).append("]"); | |
} | |
return sb; | |
} | |
@Override | |
public String description() { | |
return description(new StringBuilder()).toString(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment