/* * Copyright (c) 2014 Oculus Info Inc. * http://www.oculusinfo.com/ * * Released under the MIT License. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.oculusinfo.binning.io.serialization.impl; import org.apache.avro.Schema; import org.apache.avro.file.CodecFactory; import org.apache.avro.generic.GenericRecord; import com.oculusinfo.binning.io.serialization.GenericAvroArraySerializer; import com.oculusinfo.factory.util.Pair; import com.oculusinfo.binning.util.TypeDescriptor; /** * A serializer to serialize tiles whose bin values are lists of pairs of some * primitive types, using Avro. * * See {@link com.oculusinfo.binning.io.serialization.impl.PrimitiveAvroSerializer} * for information about what primitives are supported, and how. */ public class PairArrayAvroSerializer<S, T> extends GenericAvroArraySerializer<Pair<S, T>> { private static final long serialVersionUID = 1777339648086558933L; private static PatternedSchemaStore __schemaStore = new PatternedSchemaStore( "{\n" + " \"name\":\"entryType\",\n" + " \"namespace\":\"ar.avro\",\n" + " \"type\":\"record\",\n" + " \"fields\":[\n" + " {\"name\":\"key\", \"type\":\"%s\"},\n" + " {\"name\":\"value\", \"type\":\"%s\"}\n" + " ]\n" + "}"); private Class<? extends S> _keyType; private Class<? extends T> _valueType; private transient Schema _schema = null; // A bit of a hack to handle string tiles as strings rather than Utf8s private boolean _keyToString; private boolean _valueToString; public PairArrayAvroSerializer (Class<? extends S> keyType, Class<? extends T> valueType, CodecFactory compressionCodec) { super(compressionCodec, new TypeDescriptor(Pair.class, PrimitiveAvroSerializer.getPrimitiveTypeDescriptor(keyType), PrimitiveAvroSerializer.getPrimitiveTypeDescriptor(valueType))); _keyType = keyType; _valueType = valueType; _keyToString = (String.class.equals(keyType)); _valueToString = (String.class.equals(valueType)); } @Override protected String getEntrySchemaFile() { throw new UnsupportedOperationException("Primitive types have standard schema; schema files should not be required."); } @Override protected Schema createEntrySchema () { if (null == _schema) { String keyTypeName = PrimitiveAvroSerializer.getAvroType(_keyType); String valueTypeName = PrimitiveAvroSerializer.getAvroType(_valueType); _schema = __schemaStore.getSchema(new Pair<>(_keyType, _valueType), keyTypeName, valueTypeName); } return _schema; } // This doesn't need to be checked because // (a) One can't create a serializer for which it theoreticallly won't work. // (b) It is possible to use the wrong serializer for a given tile, in which // case it will fail - but it should fail in that case. @SuppressWarnings("unchecked") @Override protected Pair<S, T> getEntryValue(GenericRecord entry) { S key; if (_keyToString) key = (S) entry.get("key").toString(); else key = (S) entry.get("key"); T value; if (_valueToString) value = (T) entry.get("value").toString(); else value = (T) entry.get("value"); return new Pair<S, T>(key, value); } @Override protected void setEntryValue(GenericRecord avroEntry, Pair<S, T> rawEntry) { avroEntry.put("key", rawEntry.getFirst()); avroEntry.put("value", rawEntry.getSecond()); } }