jarrodhroberson
9/28/2015 - 10:15 PM

MapBackedJavaBeanProxy.java

package com.vertigrated.rtti;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.reflect.AbstractInvocationHandler;
import com.google.common.reflect.Reflection;

import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.util.Map;

public class MapBackedJavaBeanProxy extends AbstractInvocationHandler
{
    public static <T> Builder<T> as(@Nonnull final Class<T> cls)
    {
        return new Builder<T>()
        {
            @Override public T from(@Nonnull final Map<String, Object> map)
            {
                return Reflection.newProxy(cls, new MapBackedJavaBeanProxy(map));
            }
        };
    }

    private final Map<String, Object> values;

    private MapBackedJavaBeanProxy(@Nonnull final Map<String, Object> values)
    {
        if (values instanceof ImmutableSortedMap) { this.values = values; }
        else { this.values = ImmutableSortedMap.copyOf(values); }
    }

    @Override
    protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable
    {
        final String methodName = method.getName();
        if (this.values.containsKey(methodName)) { return this.values.get(methodName); }
        else { throw new IllegalArgumentException(methodName + " does not exist in " + Joiner.on(',').join(values.keySet())); }
    }

    @Override
    public boolean equals(Object obj) { return super.equals(obj); }

    @Override
    public String toString() { return Joiner.on(',').withKeyValueSeparator(":").join(this.values); }

    interface Builder<T>
    {
        public T from(@Nonnull final Map<String, Object> map);
    }
}