001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.hadoop.io; 019 020 import java.io.DataInput; 021 import java.io.DataOutput; 022 import java.io.IOException; 023 import java.util.Collection; 024 import java.util.HashMap; 025 import java.util.Map; 026 import java.util.Set; 027 028 import org.apache.hadoop.classification.InterfaceAudience; 029 import org.apache.hadoop.classification.InterfaceStability; 030 import org.apache.hadoop.util.ReflectionUtils; 031 032 /** 033 * A Writable Map. 034 */ 035 @InterfaceAudience.Public 036 @InterfaceStability.Stable 037 public class MapWritable extends AbstractMapWritable 038 implements Map<Writable, Writable> { 039 040 private Map<Writable, Writable> instance; 041 042 /** Default constructor. */ 043 public MapWritable() { 044 super(); 045 this.instance = new HashMap<Writable, Writable>(); 046 } 047 048 /** 049 * Copy constructor. 050 * 051 * @param other the map to copy from 052 */ 053 public MapWritable(MapWritable other) { 054 this(); 055 copy(other); 056 } 057 058 @Override 059 public void clear() { 060 instance.clear(); 061 } 062 063 @Override 064 public boolean containsKey(Object key) { 065 return instance.containsKey(key); 066 } 067 068 @Override 069 public boolean containsValue(Object value) { 070 return instance.containsValue(value); 071 } 072 073 @Override 074 public Set<Map.Entry<Writable, Writable>> entrySet() { 075 return instance.entrySet(); 076 } 077 078 @Override 079 public boolean equals(Object obj) { 080 if (this == obj) { 081 return true; 082 } 083 084 if (obj instanceof MapWritable) { 085 Map map = (Map) obj; 086 if (size() != map.size()) { 087 return false; 088 } 089 090 return entrySet().equals(map.entrySet()); 091 } 092 093 return false; 094 } 095 096 @Override 097 public Writable get(Object key) { 098 return instance.get(key); 099 } 100 101 @Override 102 public int hashCode() { 103 return 1 + this.instance.hashCode(); 104 } 105 106 @Override 107 public boolean isEmpty() { 108 return instance.isEmpty(); 109 } 110 111 @Override 112 public Set<Writable> keySet() { 113 return instance.keySet(); 114 } 115 116 @Override 117 @SuppressWarnings("unchecked") 118 public Writable put(Writable key, Writable value) { 119 addToMap(key.getClass()); 120 addToMap(value.getClass()); 121 return instance.put(key, value); 122 } 123 124 @Override 125 public void putAll(Map<? extends Writable, ? extends Writable> t) { 126 for (Map.Entry<? extends Writable, ? extends Writable> e: t.entrySet()) { 127 put(e.getKey(), e.getValue()); 128 } 129 } 130 131 @Override 132 public Writable remove(Object key) { 133 return instance.remove(key); 134 } 135 136 @Override 137 public int size() { 138 return instance.size(); 139 } 140 141 @Override 142 public Collection<Writable> values() { 143 return instance.values(); 144 } 145 146 // Writable 147 148 @Override 149 public void write(DataOutput out) throws IOException { 150 super.write(out); 151 152 // Write out the number of entries in the map 153 154 out.writeInt(instance.size()); 155 156 // Then write out each key/value pair 157 158 for (Map.Entry<Writable, Writable> e: instance.entrySet()) { 159 out.writeByte(getId(e.getKey().getClass())); 160 e.getKey().write(out); 161 out.writeByte(getId(e.getValue().getClass())); 162 e.getValue().write(out); 163 } 164 } 165 166 @SuppressWarnings("unchecked") 167 @Override 168 public void readFields(DataInput in) throws IOException { 169 super.readFields(in); 170 171 // First clear the map. Otherwise we will just accumulate 172 // entries every time this method is called. 173 this.instance.clear(); 174 175 // Read the number of entries in the map 176 177 int entries = in.readInt(); 178 179 // Then read each key/value pair 180 181 for (int i = 0; i < entries; i++) { 182 Writable key = (Writable) ReflectionUtils.newInstance(getClass( 183 in.readByte()), getConf()); 184 185 key.readFields(in); 186 187 Writable value = (Writable) ReflectionUtils.newInstance(getClass( 188 in.readByte()), getConf()); 189 190 value.readFields(in); 191 instance.put(key, value); 192 } 193 } 194 }