org.apache.ignite

## Interface IgniteBinary

All Known Implementing Classes:
  IgniteBinaryImpl, NoOpBinary

    public interface IgniteBinary

Defines binary objects functionality. With binary objects you are able to:

- Seamlessly interoperate between Java, .NET, and C++.
- Make any object binary with zero code change to your existing code.
- Nest binary objects within each other.
- Automatically handle `circular` or `null` references.
- Automatically convert collections and maps between Java, .NET, and C++.
- Optionally avoid deserialization of objects on the server side (objects are stored in `BinaryObject` format).
- Avoid need to have concrete class definitions on the server side.
- Dynamically change structure of the classes without having to restart the cluster.
- Index into binary objects for querying purposes.

# Working With Binaries Directly

Once an object is defined as binary, Ignite will always store it in memory in the binary (i.e. binary) format. User can choose to work either with the binary format or with the deserialized form (assuming that class definitions are present in the classpath).

To work with the binary format directly, user should create a special cache projection using IgniteCache.withKeepBinary() method and then retrieve individual fields as needed:

     IgniteCache<BinaryObject, BinaryObject> prj = cache.withKeepBinary();

     // Convert instance of MyKey to binary format.
     // We could also use BinaryBuilder to create the key in binary format directly.
     BinaryObject key = grid.binary().toBinary(new MyKey());

     BinaryObject val = prj.get(key);

     String field = val.field("myFieldName");

Alternatively, if we have class definitions in the classpath, we may choose to work with deserialized typed objects at all times.

     IgniteCache<MyKey.class, MyValue.class> cache = grid.cache(null);

     MyValue val = cache.get(new MyKey());

     // Normal java getter.
     String fieldVal = val.getMyFieldName();

If we used, for example, one of the automatically handled binary types for a key, like integer, and still wanted to work with binary binary format for values, then we would declare cache projection as follows:

     IgniteCache<Integer.class, BinaryObject> prj = cache.withKeepBinary();

# Automatic Binary Types

Note that only binary classes are converted to `BinaryObject` format. Following classes are never converted (e.g., `toBinary(Object)` method will return original object, and instances of these classes will be stored in cache without changes):

- All primitives (byte, int, ...) and there boxed versions (Byte, Integer, ...)
- Arrays of primitives (byte[], int[], ...)
- `String` and array of `String`s
- `UUID` and array of `UUID`s
- `Date` and array of `Date`s
- `Timestamp` and array of `Timestamp`s
- Enums and array of enums
- Maps, collections and array of objects (but objects inside them will still be converted if they are binary)

# Working With Maps and Collections

All maps and collections in the binary objects are serialized automatically. When working with different platforms, e.g. C++ or .NET, Ignite will automatically pick the most adequate collection or map in either language. For example, `ArrayList` in Java will become `List` in C#, `LinkedList` in Java is `LinkedList` in C#, `HashMap` in Java is `Dictionary` in C#, and `TreeMap` in Java becomes `SortedDictionary` in C#, etc.

# Building Binary Objects

Ignite comes with `BinaryObjectBuilder` which allows to build binary objects dynamically:

     BinaryBuilder builder = Ignition.ignite().binary().builder();

     builder.typeId("MyObject");

     builder.stringField("fieldA", "A");
     build.intField("fieldB", "B");

     BinaryObject binaryObj = builder.build();

For the cases when class definition is present in the class path, it is also possible to populate a standard POJO and then convert it to binary format, like so:

     MyObject obj = new MyObject();

     obj.setFieldA("A");
     obj.setFieldB(123);

     BinaryObject binaryObj = Ignition.ignite().binary().toBinary(obj);

NOTE: you don't need to convert typed objects to binary format before storing them in cache, Ignite will do that automatically.

# Binary Metadata

Even though Ignite binary protocol only works with hash codes for type and field names to achieve better performance, Ignite provides metadata for all binary types which can be queried ar runtime via any of the `type(Class)` methods. Having metadata also allows for proper formatting of `BinaryObject#toString()` method, even when binary objects are kept in binary format only, which may be necessary for audit reasons.

# Dynamic Structure Changes

Since objects are always cached in the binary binary format, server does not need to be aware of the class definitions. Moreover, if class definitions are not present or not used on the server, then clients can continuously change the structure of the binary objects without having to restart the cluster. For example, if one client stores a certain class with fields A and B, and another client stores the same class with fields B and C, then the server-side binary object will have the fields A, B, and C. As the structure of a binary object changes, the new fields become available for SQL queries automatically.

# Configuration

By default all your objects are considered as binary and no specific configuration is needed. The only requirement Ignite imposes is that your object has an empty constructor. Note, that since server side does not have to know the class definition, you only need to list binary objects in configuration on the client side. However, if you list them on the server side as well, then you get the ability to deserialize binary objects into concrete types on the server as well as on the client.

Here is an example of binary configuration (note that star (*) notation is supported):

     ...
     <!-- Explicit binary objects configuration. -->
     <property name="marshaller">
         <bean class="org.apache.ignite.marshaller.binary.BinaryMarshaller">
             <property name="classNames">
                 <list>
                     <value>my.package.for.binary.objects.*</value>
                     <value>org.apache.ignite.examples.client.binary.Employee</value>
                 </list>
             </property>
         </bean>
     </property>
     ...

or from code:

     IgniteConfiguration cfg = new IgniteConfiguration();

     BinaryMarshaller marsh = new BinaryMarshaller();

     marsh.setClassNames(Arrays.asList(
         Employee.class.getName(),
         Address.class.getName())
     );

     cfg.setMarshaller(marsh);

You can also specify class name for a binary object via `BinaryTypeConfiguration`. Do it in case if you need to override other configuration properties on per-type level, like ID-mapper, or serializer.

# Custom Affinity Keys

Often you need to specify an alternate key (not the cache key) for affinity routing whenever storing objects in cache. For example, if you are caching `Employee` object with `Organization`, and want to colocate employees with organization they work for, so you can process them together, you need to specify an alternate affinity key. With binary objects you would have to do it as following:

     <property name="marshaller">
         <bean class="org.gridgain.grid.marshaller.binary.BinaryMarshaller">
             ...
             <property name="typeConfigurations">
                 <list>
                     <bean class="org.apache.ignite.binary.BinaryTypeConfiguration">
                         <property name="className" value="org.apache.ignite.examples.client.binary.EmployeeKey"/>
                         <property name="affinityKeyFieldName" value="organizationId"/>
                     </bean>
                 </list>
             </property>
             ...
         </bean>
     </property>

# Serialization

Serialization and deserialization works out-of-the-box in Ignite. However, you can provide your own custom serialization logic by optionally implementing `Binarylizable` interface, like so:

     public class Address implements BinaryMarshalAware {
         private String street;
         private int zip;

         // Empty constructor required for binary deserialization.
         public Address() {}

         @Override public void writeBinary(BinaryWriter writer) throws BinaryException {
             writer.writeString("street", street);
             writer.writeInt("zip", zip);
         }

         @Override public void readBinary(BinaryReader reader) throws BinaryException {
             street = reader.readString("street");
             zip = reader.readInt("zip");
         }
     }

Alternatively, if you cannot change class definitions, you can provide custom serialization logic in `BinarySerializer` either globally in `BinaryConfiguration` or for a specific type via `BinaryTypeConfiguration` instance.

Similar to java serialization you can use `writeReplace()` and `readResolve()` methods.

- `readResolve` is defined as follows: `ANY-ACCESS-MODIFIER Object readResolve()`. It may be used to replace the de-serialized object by another one of your choice.
- `writeReplace` is defined as follows: `ANY-ACCESS-MODIFIER Object writeReplace()`. This method allows the developer to provide a replacement object that will be serialized instead of the original one.

# Custom ID Mappers

Ignite implementation uses name hash codes to generate IDs for class names or field names internally. However, in cases when you want to provide your own ID mapping schema, you can provide your own `BinaryIdMapper` implementation.

ID-mapper may be provided either globally in `BinaryConfiguration`, or for a specific type via `BinaryTypeConfiguration` instance.

# Query Indexing

Binary objects can be indexed for querying by specifying index fields in `CacheTypeMetadata` inside of specific `CacheConfiguration` instance, like so:

     ...
     <bean class="org.apache.ignite.cache.CacheConfiguration">
         ...
         <property name="typeMetadata">
             <list>
                 <bean class="CacheTypeMetadata">
                     <property name="type" value="Employee"/>

                     <!-- Fields to index in ascending order. -->
                     <property name="ascendingFields">
                         <map>
                         <entry key="name" value="java.lang.String"/>

                             <!-- Nested binary objects can also be indexed. -->
                             <entry key="address.zip" value="java.lang.Integer"/>
                         </map>
                     </property>
                 </bean>
             </list>
         </property>
     </bean>

### Method Summary

Methods
`BinaryObject` `buildEnum(String typeName, int ord)` Create enum object.
`BinaryObjectBuilder` `builder(BinaryObject binaryObj)` Creates binary builder initialized by existing binary object.
`BinaryObjectBuilder` `builder(String typeName)` Creates new binary builder.
`<T> T` `toBinary(Object obj)` Converts provided object to instance of `BinaryObject`.
`BinaryType` `type(Class<?> cls)` Gets metadata for provided class.
`BinaryType` `type(int typeId)` Gets metadata for provided type ID.
`BinaryType` `type(String typeName)` Gets metadata for provided class name.
`int` `typeId(String typeName)` Gets type ID for given type name.
`Collection<BinaryType>` `types()` Gets metadata for all known types.

### Method Detail

#### typeId

    int typeId(String typeName)

Gets type ID for given type name.

Parameters:
  `typeName` - Type name.
Returns:
  Type ID.

#### toBinary

    <T> T toBinary(@Nullable
                 Object obj)
               throws BinaryObjectException

Converts provided object to instance of `BinaryObject`.

Parameters:
  `obj` - Object to convert.
Returns:
  Converted object.
Throws:
  `BinaryObjectException` - In case of error.

#### builder

    BinaryObjectBuilder builder(String typeName)
                                throws BinaryObjectException

Creates new binary builder.

Parameters:
  `typeName` - Type name.
Returns:
  Newly binary builder.
Throws:
  `BinaryObjectException`

#### builder

    BinaryObjectBuilder builder(BinaryObject binaryObj)
                                throws BinaryObjectException

Creates binary builder initialized by existing binary object.

Parameters:
  `binaryObj` - Binary object to initialize builder.
Returns:
  Binary builder.
Throws:
  `BinaryObjectException`

#### type

    BinaryType type(Class<?> cls)
                    throws BinaryObjectException

Gets metadata for provided class.

Parameters:
  `cls` - Class.
Returns:
  Metadata.
Throws:
  `BinaryObjectException` - In case of error.

#### type

    BinaryType type(String typeName)
                    throws BinaryObjectException

Gets metadata for provided class name.

Parameters:
  `typeName` - Type name.
Returns:
  Metadata.
Throws:
  `BinaryObjectException` - In case of error.

#### type

    BinaryType type(int typeId)
                    throws BinaryObjectException

Gets metadata for provided type ID.

Parameters:
  `typeId` - Type ID.
Returns:
  Metadata.
Throws:
  `BinaryObjectException` - In case of error.

#### types

    Collection<BinaryType> types()
                                 throws BinaryObjectException

Gets metadata for all known types.

Returns:
  Metadata.
Throws:
  `BinaryObjectException` - In case of error.

#### buildEnum

    BinaryObject buildEnum(String typeName,
                         int ord)

Create enum object.

Parameters:
  `typeName` - Type name.
  `ord` - Ordinal.
Returns:
  Enum object.

2015 Copyright © Apache Software Foundation

Follow @ApacheIgnite

Ignite Fabric | : ver. 1.8.0
Release Date | : December 5 2016