kv-4.0.9.src.oracle.kv.avro.GenericAvroBinding Maven / Gradle / Ivy
Show all versions of oracle-nosql-client Show documentation
/*-
*
* This file is part of Oracle NoSQL Database
* Copyright (C) 2011, 2016 Oracle and/or its affiliates. All rights reserved.
*
* If you have received this file as part of Oracle NoSQL Database the
* following applies to the work as a whole:
*
* Oracle NoSQL Database server software is free software: you can
* redistribute it and/or modify it under the terms of the GNU Affero
* General Public License as published by the Free Software Foundation,
* version 3.
*
* Oracle NoSQL Database is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* If you have received this file as part of Oracle NoSQL Database Client or
* distributed separately the following applies:
*
* Oracle NoSQL Database client software is free software: you can
* redistribute it and/or modify it under the terms of the Apache License
* as published by the Apache Software Foundation, version 2.0.
*
* You should have received a copy of the GNU Affero General Public License
* and/or the Apache License in the LICENSE file along with Oracle NoSQL
* Database client or server distribution. If not, see
*
* or
* .
*
* An active Oracle commercial licensing agreement for this product supersedes
* these licenses and in such case the license notices, but not the copyright
* notice, may be removed by you in connection with your distribution that is
* in accordance with the commercial licensing terms.
*
* For more information please contact:
*
* [email protected]
*
*/
package oracle.kv.avro;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericRecord;
import oracle.kv.Value;
/**
* The {@code GenericAvroBinding} interface has the same methods as {@link
* AvroBinding}, but represents values as instances of {@link GenericRecord}.
* A single schema binding is created using {@link
* AvroCatalog#getGenericBinding}, and a multiple schema binding is created
* using {@link AvroCatalog#getGenericMultiBinding}.
*
* The trade-offs in using a {@code GenericAvroBinding}, compared to other
* types of bindings, are:
*
* - The obvious advantage of using a generic binding is that values may be
* treated generically. Also, if schemas are treated dynamically, then the
* set of schemas used in an application need not be fixed at build time.
*
* - Because {@link GenericRecord} is part of the Avro API, it conveniently
* represents all data types defined by Avro. This is in contrast to a
* {@link JsonAvroBinding}.
*
* - {@link GenericRecord} does not provide type safety because field
* values must be cast to the type defined in the schema. It can also be
* error prone, because fields are accessed by string name.
*
* - To support class evolution, with generic bindings (unlike Avro
* specific bindings) the application must supply the Avro {@link Schema}
* objects at runtime. In other words, the application must maintain a set
* of known schemas for use at runtime.
*
*
*
* See {@link AvroCatalog} for general information on Avro bindings and
* schemas. The schemas used in the examples below are described in the {@link
* AvroCatalog} javadoc.
*
* When using a {@code GenericAvroBinding}, a {@link GenericRecord} is used to
* represent values. A {@link GenericRecord} represents an Avro object roughly
* as a map of string field names to field values, as follows:
*
*
* public interface GenericRecord {
* public Schema getSchema();
* public Object get(String key);
* public void put(String key, Object value);
* }
* Note that field values in this API are type Object and must be cast to the
* appropriate type, as defined by the schema. The mapping from Avro schema
* data types to Java data types is described at the bottom of the {@link
* org.apache.avro.generic} package description.
*
* The following code fragment demonstrates writing and reading a value using a
* generic single schema binding.
*
*
* Schema.Parser parser = new Schema.Parser();
* Schema nameSchema = parser.parse(nameSchemaText);
* Schema memberSchema = parser.parse(memberSchemaText);
*
* GenericAvroBinding binding = avroCatalog.getGenericBinding(memberSchema);
*
* // Create object
* GenericRecord name = new GenericData.Record(nameSchema)
* name.put("first", ...);
* name.put("last", ...);
* GenericRecord object = new GenericData.Record(memberSchema)
* object.put("name", name);
* object.put("age", new Integer(...));
*
* // Serialize and store
* Value value = binding.toValue(object);
* kvStore.put(key, value);
*
* // Sometime later, retrieve and deserialize
* ValueVersion vv = kvStore.get(key);
* GenericRecord object = binding.toObject(vv.getValue());
*
* // Use object
* GenericRecord name = (GenericRecord) object.get("name");
* Integer age = (Integer) object.get("age");
* ...
*
* The following code fragment demonstrates reading values with different
* schemas using a generic multiple schema binding.
*
*
* Schema.Parser parser = new Schema.Parser();
* Schema nameSchema = parser.parse(nameSchemaText);
* Schema memberSchema = parser.parse(memberSchemaText);
* Schema anotherSchema = parser.parse(anotherSchemaText);
*
* Map<String, Schema> schemas = new HashMap<String, Schema>()
* schemas.put(memberSchema.getFullName(), memberSchema);
* schemas.put(anotherSchema.getFullName(), anotherSchema);
*
* GenericAvroBinding binding = avroCatalog.getGenericMultiBinding(schemas);
*
* Iterator<KeyValueVersion> iter = kvStore.multiGetIterator(...);
* for (KeyValueVersion kvv : iter) {
* GenericRecord object = binding.toObject(kvv.getValue());
* String schemaName = object.getSchema().getFullName();
* if (schemaName.equals(memberSchema.getFullName())) {
* ...
* } else if (schemaName.equals(anotherSchema.getFullName())) {
* ...
* } else {
* ...
* }
* }
*
* A special use case for a generic multiple schema binding is when the
* application treats values dynamically based on their schema, rather than
* using a fixed set of known schemas. The {@link
* AvroCatalog#getCurrentSchemas} method can be used to obtain a map of the
* most current schemas, which can be passed to {@link
* AvroCatalog#getGenericMultiBinding}.
*
* For example, the following code fragment demonstrates reading values with
* different schemas using a generic multiple schema binding. Note that in a
* long running application, it is possible that a schema may be added and used
* to store a key-value pair, after the binding has been created. The
* application may handle this possibility by catching {@link
* SchemaNotAllowedException}.
*
*
* GenericAvroBinding binding =
* avroCatalog.getGenericMultiBinding(avroCatalog.getCurrentSchemas());
*
* Iterator<KeyValueVersion> iter = kvStore.storeIterator(...);
* while (iter.hasNext()) {
* KeyValueVersion kvv = iter.next();
* GenericRecord object;
* try {
* object = binding.toObject(kvv.getValue());
* } catch (SchemaNotAllowedException e) {
* // In this example, ignore values with a schema that was not
* // known at the time the binding was created.
* continue;
* }
* String schemaName = object.getSchema().getFullName();
* if (schemaName.equals(memberSchema.getFullName())) {
* ...
* } else if (schemaName.equals(anotherSchema.getFullName())) {
* ...
* } else {
* ...
* }
* }
*
* @since 2.0
*
* @deprecated as of 4.0, use the table API instead.
*/
@Deprecated
public interface GenericAvroBinding extends AvroBinding {
/**
* {@inheritDoc}
*
* If necessary, this method automatically performs schema evolution, as
* described in {@link AvroCatalog}. In the context of schema evolution,
* the writer schema is the one associated internally with the {@code
* value} parameter (this association was normally made earlier when the
* value was stored), and the reader schema is the one associated with this
* binding (and was specified when the binding was created).
*
* In other words, this method transforms the serialized data in the {@code
* value} parameter to conform to the schema of the {@link GenericRecord}
* that is returned.
*
* @return the deserialized {@link GenericRecord} instance. The {@link
* GenericRecord#getSchema} method will return the reader schema, which is
* the schema that was specified when this binding was created.
*/
@Override
public GenericRecord toObject(Value value)
throws SchemaNotAllowedException, IllegalArgumentException;
/**
* {@inheritDoc}
*
* In the context of schema evolution, as described in {@link AvroCatalog},
* the returned value is serialized according to the writer schema. The
* writer schema is the one associated with the {@link GenericRecord}
* {@code object} parameter; it is returned by {@link
* GenericRecord#getSchema} and normally specified when creating a {@link
* org.apache.avro.generic.GenericData.Record} object. The writer schema
* must be one of the schemas specified when this binding was created.
*
* In other words, this method returns serialized data that conforms to the
* schema of the given {@link GenericRecord}.
*
* @param object the {@link GenericRecord} instance the user wishes to
* store, or at least serialize.
*/
@Override
public Value toValue(GenericRecord object)
throws SchemaNotAllowedException, UndefinedSchemaException,
IllegalArgumentException;
}