/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.flink.types; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.flink.annotation.Public; import org.apache.flink.core.memory.DataInputView; import org.apache.flink.core.memory.DataOutputView; import org.apache.flink.util.ReflectionUtil; /** * Generic map base type for PACT programs that implements the Value and Map interfaces. * The {@link MapValue} encapsulates a Java {@link HashMap} object. * * @see org.apache.flink.types.Value * @see java.util.Map * @see java.util.HashMap * * @param <K> Type of the map's key element. * @param <V> Type of the map's value element. * * */ @Public public abstract class MapValue<K extends Value, V extends Value> implements Value, Map<K, V> { private static final long serialVersionUID = 1L; // type of the map's key private final Class<K> keyClass; // type of the map's value private final Class<V> valueClass; // encapsulated map private final Map<K, V> map; /** * Initializes the encapsulated map with an empty HashMap. */ public MapValue() { this.keyClass = ReflectionUtil.getTemplateType1(this.getClass()); this.valueClass = ReflectionUtil.getTemplateType2(this.getClass()); this.map = new HashMap<>(); } /** * Initializes the encapsulated map with a HashMap filled with all entries of the provided map. * * @param map Map holding all entries with which the new encapsulated map is filled. */ public MapValue(Map<K, V> map) { this.keyClass = ReflectionUtil.getTemplateType1(this.getClass()); this.valueClass = ReflectionUtil.getTemplateType2(this.getClass()); this.map = new HashMap<>(map); } @Override public void read(final DataInputView in) throws IOException { int size = in.readInt(); this.map.clear(); try { for (; size > 0; size--) { final K key = this.keyClass.newInstance(); final V val = this.valueClass.newInstance(); key.read(in); val.read(in); this.map.put(key, val); } } catch (final InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } @Override public void write(final DataOutputView out) throws IOException { out.writeInt(this.map.size()); for (final Entry<K, V> entry : this.map.entrySet()) { entry.getKey().write(out); entry.getValue().write(out); } } /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return this.map.toString(); } /* * (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 47; int result = 1; result = prime * result + this.map.hashCode(); return result; } /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final MapValue<?, ?> other = (MapValue<?, ?>) obj; if (this.map == null) { if (other.map != null) { return false; } } else if (!this.map.equals(other.map)) { return false; } return true; } /* * (non-Javadoc) * @see java.util.Map#clear() */ @Override public void clear() { this.map.clear(); } /* * (non-Javadoc) * @see java.util.Map#containsKey(java.lang.Object) */ @Override public boolean containsKey(final Object key) { return this.map.containsKey(key); } /* * (non-Javadoc) * @see java.util.Map#containsValue(java.lang.Object) */ @Override public boolean containsValue(final Object value) { return this.map.containsValue(value); } /* * (non-Javadoc) * @see java.util.Map#entrySet() */ @Override public Set<Entry<K, V>> entrySet() { return this.map.entrySet(); } /* * (non-Javadoc) * @see java.util.Map#get(java.lang.Object) */ @Override public V get(final Object key) { return this.map.get(key); } /* * (non-Javadoc) * @see java.util.Map#isEmpty() */ @Override public boolean isEmpty() { return this.map.isEmpty(); } /* * (non-Javadoc) * @see java.util.Map#keySet() */ @Override public Set<K> keySet() { return this.map.keySet(); } /* * (non-Javadoc) * @see java.util.Map#put(java.lang.Object, java.lang.Object) */ @Override public V put(final K key, final V value) { return this.map.put(key, value); } /* * (non-Javadoc) * @see java.util.Map#putAll(java.util.Map) */ @Override public void putAll(final Map<? extends K, ? extends V> m) { this.map.putAll(m); } /* * (non-Javadoc) * @see java.util.Map#remove(java.lang.Object) */ @Override public V remove(final Object key) { return this.map.remove(key); } /* * (non-Javadoc) * @see java.util.Map#size() */ @Override public int size() { return this.map.size(); } /* * (non-Javadoc) * @see java.util.Map#values() */ @Override public Collection<V> values() { return this.map.values(); } }