001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import com.google.common.annotations.GwtIncompatible; 020import com.google.common.collect.MapConstraints.ConstrainedMap; 021import com.google.common.primitives.Primitives; 022import com.google.errorprone.annotations.CanIgnoreReturnValue; 023import java.io.Serializable; 024import java.util.HashMap; 025import java.util.Map; 026 027/** 028 * A mutable class-to-instance map backed by an arbitrary user-provided map. 029 * See also {@link ImmutableClassToInstanceMap}. 030 * 031 * <p>See the Guava User Guide article on <a href= 032 * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#classtoinstancemap"> 033 * {@code ClassToInstanceMap}</a>. 034 * 035 * @author Kevin Bourrillion 036 * @since 2.0 037 */ 038@GwtIncompatible 039@SuppressWarnings("serial") // using writeReplace instead of standard serialization 040public final class MutableClassToInstanceMap<B> extends ConstrainedMap<Class<? extends B>, B> 041 implements ClassToInstanceMap<B>, Serializable { 042 043 /** 044 * Returns a new {@code MutableClassToInstanceMap} instance backed by a {@link 045 * HashMap} using the default initial capacity and load factor. 046 */ 047 public static <B> MutableClassToInstanceMap<B> create() { 048 return new MutableClassToInstanceMap<B>(new HashMap<Class<? extends B>, B>()); 049 } 050 051 /** 052 * Returns a new {@code MutableClassToInstanceMap} instance backed by a given 053 * empty {@code backingMap}. The caller surrenders control of the backing map, 054 * and thus should not allow any direct references to it to remain accessible. 055 */ 056 public static <B> MutableClassToInstanceMap<B> create(Map<Class<? extends B>, B> backingMap) { 057 return new MutableClassToInstanceMap<B>(backingMap); 058 } 059 060 private MutableClassToInstanceMap(Map<Class<? extends B>, B> delegate) { 061 super(delegate, VALUE_CAN_BE_CAST_TO_KEY); 062 } 063 064 private static final MapConstraint<Class<?>, Object> VALUE_CAN_BE_CAST_TO_KEY = 065 new MapConstraint<Class<?>, Object>() { 066 @Override 067 public void checkKeyValue(Class<?> key, Object value) { 068 cast(key, value); 069 } 070 }; 071 072 @CanIgnoreReturnValue 073 @Override 074 public <T extends B> T putInstance(Class<T> type, T value) { 075 return cast(type, put(type, value)); 076 } 077 078 @Override 079 public <T extends B> T getInstance(Class<T> type) { 080 return cast(type, get(type)); 081 } 082 083 @CanIgnoreReturnValue 084 private static <B, T extends B> T cast(Class<T> type, B value) { 085 return Primitives.wrap(type).cast(value); 086 } 087 088 private Object writeReplace() { 089 return new SerializedForm(delegate()); 090 } 091 092 /** 093 * Serialized form of the map, to avoid serializing the constraint. 094 */ 095 private static final class SerializedForm<B> implements Serializable { 096 private final Map<Class<? extends B>, B> backingMap; 097 098 SerializedForm(Map<Class<? extends B>, B> backingMap) { 099 this.backingMap = backingMap; 100 } 101 102 Object readResolve() { 103 return create(backingMap); 104 } 105 106 private static final long serialVersionUID = 0; 107 } 108}