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

com.fizzed.crux.util.BindingPropertyMap Maven / Gradle / Ivy

There is a newer version: 1.0.46
Show newest version
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));
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy