package org.archstudio.bna.keys; import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import com.google.common.base.Function; import com.google.common.collect.Maps; @NonNullByDefault abstract class AbstractThingKey<V> implements IThingKey<V> { private static Map<IThingKey<?>, IThingKey<?>> identityMap = Maps.newHashMap(); @SuppressWarnings("unchecked") synchronized protected static <K extends IThingKey<?>> K identity(K key) { IThingKey<?> cached = identityMap.get(key); if (cached == null) { identityMap.put(key, cached = key); } return (K) cached; } private final Object id; private final int idHashCode; private final Function<V, V> cloneFunction; private final boolean nullable; protected AbstractThingKey(Object id, @Nullable Function<V, V> cloneFunction, boolean nullable) { this.id = id; this.idHashCode = this.id.hashCode(); this.cloneFunction = cloneFunction; this.nullable = nullable; } @Override public int hashCode() { return idHashCode; } @SuppressWarnings("rawtypes") @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AbstractThingKey other = (AbstractThingKey) obj; if (id == null) { if (other.id != null) { return false; } } else if (!id.equals(other.id)) { return false; } return true; } @Override public @Nullable V clone(@Nullable V value) { return value == null ? null : cloneFunction != null ? cloneFunction.apply(value) : value; } @Override public boolean isNullable() { return nullable; } @Override public String toString() { return id.toString().replaceAll("[\\[\\]]", ""); } }