com.fizzed.crux.util.BindingPropertyMap Maven / Gradle / Ivy
package com.fizzed.crux.util;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class BindingPropertyMap {
public class Property {
private final Class type;
private final BiConsumer setter;
private final Function converter;
public Property(Class type, BiConsumer setter, Function converter) {
this.type = type;
this.setter = setter;
this.converter = converter;
}
public void set(A instance, Object value) {
T target;
if (value == null || type.isInstance(value)) {
target = (T)value;
} else {
String s = Objects.toString(value, null);
try {
target = this.converter.apply(s);
} catch (Throwable t) {
throw new IllegalArgumentException("Unable to convert '" + s + "' to " + this.type.getCanonicalName());
}
}
this.setter.accept(instance, target);
}
}
static public final Function STRING_CONVERTER = (s) -> {
return s;
};
static public final Function BOOLEAN_CONVERTER = (s) -> {
if (s == null) {
return null;
}
if (s.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (s.equalsIgnoreCase("false")) {
return Boolean.FALSE;
} else {
throw new IllegalArgumentException("Invalid boolean (only true or false)");
}
};
static public final Function INTEGER_CONVERTER = (s) -> {
return s != null ? Integer.valueOf(s) : null;
};
static public final Function LONG_CONVERTER = (s) -> {
return s != null ? Long.valueOf(s) : null;
};
static public final Function PATH_CONVERTER = (s) -> {
return s != null ? Paths.get(s) : null;
};
static public final Function FILE_CONVERTER = (s) -> {
return s != null ? new File(s) : null;
};
static public final Function URI_CONVERTER = (s) -> {
return s != null ? URI.create(s) : null;
};
static public final Function URL_CONVERTER = (s) -> {
if (s == null) {
return null;
}
try {
return new URL(s);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
};
private final Map> map;
public BindingPropertyMap() {
this.map = new LinkedHashMap<>(); // insertion order important
}
public BindingPropertyMap bindString(String key, BiConsumer setter) {
this.map.put(key, new Property<>(String.class, setter, STRING_CONVERTER));
return this;
}
public BindingPropertyMap bindBoolean(String key, BiConsumer setter) {
this.map.put(key, new Property<>(Boolean.class, setter, BOOLEAN_CONVERTER));
return this;
}
public BindingPropertyMap bindInteger(String key, BiConsumer setter) {
this.map.put(key, new Property<>(Integer.class, setter, INTEGER_CONVERTER));
return this;
}
public BindingPropertyMap bindLong(String key, BiConsumer setter) {
this.map.put(key, new Property<>(Long.class, setter, LONG_CONVERTER));
return this;
}
public BindingPropertyMap bindPath(String key, BiConsumer setter) {
this.map.put(key, new Property<>(Path.class, setter, PATH_CONVERTER));
return this;
}
public BindingPropertyMap bindFile(String key, BiConsumer setter) {
this.map.put(key, new Property<>(File.class, setter, FILE_CONVERTER));
return this;
}
public BindingPropertyMap bindURI(String key, BiConsumer setter) {
this.map.put(key, new Property<>(URI.class, setter, URI_CONVERTER));
return this;
}
public BindingPropertyMap bindURL(String key, BiConsumer setter) {
this.map.put(key, new Property<>(URL.class, setter, URL_CONVERTER));
return this;
}
public BindingPropertyMap bindType(String key, BiConsumer setter, Class type, Function converter) {
this.map.put(key, new Property<>(type, setter, converter));
return this;
}
public Set getKeys() {
return this.map.keySet();
}
public boolean hasKey(String key) {
return this.map.containsKey(key);
}
public void set(A instance, String key, Object value) {
this.set(instance, key, value, false);
}
public void set(A instance, String key, Object value, boolean skipUnknownKeys) {
Objects.requireNonNull(instance, "instance was null");
Objects.requireNonNull(key, "key was null");
Property property = (Property)this.map.get(key);
if (property == null) {
if (skipUnknownKeys) {
return;
} else {
throw new IllegalArgumentException("Property '" + key + "' is not recognized for "
+ instance.getClass().getCanonicalName()
+ " (available are " + this.map.keySet() + ")");
}
}
try {
property.set(instance, value);
} catch (IllegalArgumentException e) {
// unwrap conversion exception, add message, but also return its cause
throw new IllegalArgumentException("Property '" + key + "' could not be converted. " + e.getMessage(), e.getCause());
}
}
public void setAll(A instance, Properties properties) {
this.setAll(instance, properties, false);
}
public void setAll(A instance, Properties properties, boolean skipUnknownKeys) {
if (properties == null) {
return;
}
// process each property
properties.forEach((key, value) -> this.set(instance, key.toString(), value, skipUnknownKeys));
}
public void setAll(A instance, Map values) {
this.setAll(instance, values, false);
}
public void setAll(A instance, Map values, boolean skipUnknownKeys) {
if (values == null) {
return;
}
values.forEach((key, value) -> this.set(instance, key, value, skipUnknownKeys));
}
}