oracle.kv.avro

## Interface SpecificAvroBinding<T extends SpecificRecord>

- Type Parameters:
    `T` - is the `SpecificRecord` type of the deserialized object that is passed to `toValue` and returned by `toObject`. When using a single schema binding, `T` is the generated Avro specific class, which implements `SpecificRecord`. When using a multiple schema binding, `T` is the `SpecificRecord` interface itself.
  All Superinterfaces:
    AvroBinding<T>, ValueBinding<T>

      public interface SpecificAvroBinding<T extends SpecificRecord>
      extends AvroBinding<T>

  The `SpecificAvroBinding` interface has the same methods as `AvroBinding`, but represents values as instances of a generated Avro specific class which implements `SpecificRecord`. A single schema binding is created using `AvroCatalog.getSpecificBinding(java.lang.Class<T>)`, and a multiple schema binding is created using `AvroCatalog.getSpecificMultiBinding()`.

  The trade-offs in using a `SpecificAvroBinding`, compared to other types of bindings, are:

  - Avro specific classes provide type safety and ease of use. Properties are accessed through getter/setter methods with parameters and return values of the correct type, as defined in the schema.

  - When using Avro specific classes, the client application does not need to be aware of the Avro schema at runtime. The generated class has an internal reference to its associated schema, and this schema is used by the binding, so the application does not need to explicitly supply a schema. Schemas are supplied at build time, when the source code for the specific class is generated.

  - A potential disadvantage to using Avro specific classes is that the set of specific classes used in the application is fixed at build time. Applications that wish to treat values generically, or dynamically based on the schema, should use a generic or JSON binding instead.

  See `AvroCatalog` for general information on Avro bindings and schemas. The schemas used in the examples below are described in the `AvroCatalog` javadoc.

  When using a `SpecificAvroBinding`, an Avro specific Java class, which implements the Avro `SpecificRecord` interface, is used to represent values. An Avro specific class is a POJO (Plain Old Java Object) having properties (getter and setter methods) for each field in its associated Avro schema. The source code for an Avro specific class is generated from an Avro schema using the Avro compiler tools; see the Avro example in `KVHOME/examples/avro` for details.

  For example, the generated Avro specific classes for the example schemas are:

        package com.example;

        import org.apache.avro.Schema;
        import org.apache.avro.specific.SpecificRecord;

        public class FullName implements SpecificRecord {
          public FullName() {}
          public Schema getSchema() { ... }
          public String getFirst() { ... }
          public void setFirst(String value) { ... }
          public String getLast() { ... }
          public void setLast(String value) { ... }
        }

        public class MemberInfo implements SpecificRecord {
          public MemberInfo() {}
          public Schema getSchema() { ... }
          public FullName getName() { ... }
          public void setName(FullName value) { ... }
          public Integer getAge() { ... }
          public void setAge(Integer value) { ... }
        }

  In addition to the methods shown, useful `Object.toString()`, `Object.equals(java.lang.Object)` and `Object.hashCode()` methods are generated. Avro also generates internal methods for performing serialization and deserialization, and an internal static field that holds the schema used to compile the class. Note that the full Avro schema name and full Java class name are always equal.

  The following code fragment demonstrates writing and reading a value using a specific single schema binding. Note that no casting is needed when a single schema binding is used.

       AvroBinding<MemberInfo> binding =
           avroCatalog.getSpecificBinding(MemberInfo.class);

       // Create object
       FullName name = new FullName();
       name.setFirst(...);
       name.setLast(...);
       MemberInfo object = new MemberInfo();
       object.setName(name);
       object.setAge(...);

       // Serialize and store
       Value value = binding.toValue(object);
       kvStore.put(key, value);

       // Sometime later, retrieve and deserialize
       ValueVersion vv = kvStore.get(key);
       MemberInfo object = binding.toObject(vv.getValue());

       // Use object
       FullName name = object.getName();
       int age = object.getAge();
       ...

  The following code fragment demonstrates reading values with different schemas (different specific classes) using a multiple schema binding. Note that schema name could also be used to distinguish between classes, instead of using `instanceof`.

       SpecificAvroBinding<SpecificRecord> binding =
           avroCatalog.getSpecificMultiBinding();

       Iterator<KeyValueVersion> iter = kvStore.multiGetIterator(...);
       for (KeyValueVersion kvv : iter) {
           SpecificRecord object = binding.toObject(kvv.getValue());
           if (object instanceof MemberInfo) {
               MemberInfo member = (MemberInfo) object;
               ...
           } else if (object instanceof OtherSpecificClass) {
               ...
           } else {
               ...
           }
       }

  Since:
    2.0

- - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `T` | `toObject(Value value)` After doing a read operation using a `KVStore` method, the user calls `toObject` with the `Value` obtained from the read operation.
    `Value` | `toValue(T object)` Before doing a write operation, the user calls `toValue` passing an object she wishes to store.

- - ### Method Detail

    - #### toObject

          T toObject(Value value)
                                            throws SchemaNotAllowedException,
                                                   IllegalArgumentException

      After doing a read operation using a `KVStore` method, the user calls `toObject` with the `Value` obtained from the read operation.

      If necessary, this method automatically performs schema evolution, as described in `AvroCatalog`. In the context of schema evolution, the writer schema is the one associated internally with the `value` parameter (this association was normally made earlier when the value was stored), and the reader schema is the one associated with the Avro specific class of the caller. The schema of an Avro specific class is the one from which the class was generated using the Avro compiler tools.

      In other words, this method transforms the serialized data in the `value` parameter to conform to the schema of the Avro specific class that is returned.

      Specified by:
        `toObject` in interface `AvroBinding<T extends SpecificRecord>`
      Specified by:
        `toObject` in interface `ValueBinding<T extends SpecificRecord>`
      Parameters:
        `value` - the `Value` obtained from a `KVStore` read operation method.. The byte array of the `Value` is serialized Avro data, packaged in an internal format that includes a reference to the Avro schema
      Returns:
        the deserialized `SpecificRecord` instance.
      Throws:
        `SchemaNotAllowedException` - if the schema associated with the `value` parameter is not allowed with this binding.
        `IllegalArgumentException` - if the value format is not `Value.Format.AVRO`, the schema identifier embedded in the `value` parameter is invalid, or the serialized data cannot be parsed.

    - #### toValue

          Value toValue(T object)
                        throws SchemaNotAllowedException,
                               UndefinedSchemaException,
                               IllegalArgumentException

      Before doing a write operation, the user calls `toValue` passing an object she wishes to store. The resulting `Value` is then passed to the write operation method in `KVStore`.

      In the context of schema evolution, as described in `AvroCatalog`, the returned value is serialized according to the writer schema. The writer schema is the one associated with the Avro specific class of the `object` parameter. The schema of an Avro specific class is the one from which the class was generated using the Avro compiler tools.

      In other words, this method returns serialized data that conforms to the schema of the Avro specific class.

      Specified by:
        `toValue` in interface `AvroBinding<T extends SpecificRecord>`
      Specified by:
        `toValue` in interface `ValueBinding<T extends SpecificRecord>`
      Parameters:
        `object` - the `SpecificRecord` instance the user wishes to store, or at least serialize.
      Returns:
        the serialized object.. The byte array of the `Value` is serialized Avro data, packaged in an internal format that includes a reference to the Avro schema
      Throws:
        `SchemaNotAllowedException` - if the `object` parameter's class is not the class passed to `AvroCatalog.getSpecificBinding(java.lang.Class<T>)`; this can only happen if generic type warnings are ignored or suppressed. This exception is never thrown by a `specific multi-binding`.
        `UndefinedSchemaException` - if the schema associated with the `object` parameter has not been defined using the NoSQL Database administration interface. Note that when the allowed schemas for a binding are specified (and validate) at the time the binding is created, this exception is extremely unlikely and is only possible if a schema is mistakenly disabled after the binding is created.
        `IllegalArgumentException` - if the `object` parameter is invalid according to its schema, and cannot be serialized.

Copyright (c) 2011, 2014 Oracle and/or its affiliates. All rights reserved.