Skip to content

Instantly share code, notes, and snippets.

@agentgt
Last active February 12, 2023 15:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agentgt/78bd22d473d52d6e0c4ff9c45d5cd7d0 to your computer and use it in GitHub Desktop.
Save agentgt/78bd22d473d52d6e0c4ff9c45d5cd7d0 to your computer and use it in GitHub Desktop.
Config.java
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