/*
* Copyright 2013 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.errorprone.refaster;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
/**
* A type-safe map from objects of type {@code Bindings.Key<V>}, which consist of a {@code String}
* key and a {@code Bindings.Key} subclass, to values of type {@code V}.
*
* @author Louis Wasserman
*/
public class Bindings extends ForwardingMap<Bindings.Key<?>, Object> {
/**
* A key type for a {@code Binding}. Users must subclass {@code Key} with a specific literal
* {@code V} type.
*/
public abstract static class Key<V> {
private final String identifier;
protected Key(String identifier) {
this.identifier = checkNotNull(identifier);
}
public String getIdentifier() {
return identifier;
}
TypeToken<V> getValueType() {
return new TypeToken<V>(getClass()) {};
}
@Override
public int hashCode() {
return Objects.hashCode(getClass(), identifier);
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj != null && this.getClass() == obj.getClass()) {
Key<?> key = (Key<?>) obj;
return identifier.equals(key.identifier);
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("identifier", identifier).toString();
}
}
private final Map<Key<?>, Object> contents;
public static Bindings create() {
return new Bindings();
}
public static <V> Bindings create(Key<V> key, V value) {
Bindings result = create();
result.putBinding(key, value);
return result;
}
public static <V1, V2> Bindings create(Key<V1> key1, V1 value1, Key<V2> key2, V2 value2) {
Bindings result = create();
result.putBinding(key1, value1);
result.putBinding(key2, value2);
return result;
}
public static Bindings create(Bindings bindings) {
return new Bindings(bindings);
}
private Bindings() {
this(new HashMap<Key<?>, Object>());
}
Bindings(Bindings bindings) {
this(Maps.newHashMap(bindings.contents));
}
private Bindings(Map<Key<?>, Object> contents) {
this.contents = contents;
}
@Override
protected Map<Key<?>, Object> delegate() {
return contents;
}
@SuppressWarnings("unchecked")
public <V> V getBinding(Key<V> key) {
checkNotNull(key);
return (V) super.get(key);
}
@SuppressWarnings("unchecked")
public <V> V putBinding(Key<V> key, V value) {
checkNotNull(value);
return (V) super.put(key, value);
}
@Override
public Object put(Key<?> key, Object value) {
checkNotNull(key, "key");
checkNotNull(value, "value");
return super.put(key, key.getValueType().getRawType().cast(value));
}
@Override
public void putAll(Map<? extends Key<?>, ? extends Object> map) {
standardPutAll(map);
}
public Bindings unmodifiable() {
return new Bindings(Collections.unmodifiableMap(contents));
}
}