Package org.apache.ignite

## Interface IgniteBinary

-     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 `QueryEntity` inside of specific `CacheConfiguration` instance, like so:

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

                       <!-- Fields available from query. -->
                       <property name="fields">
                           <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>

                       <!-- Aliases for full property name in dot notation. -->
                       <property name="fields">
                           <map>
                           <entry key="address.zip" value="zip" />
                           </map>
                       </property>

                       <!-- Indexes configuration. -->
                       <property name="indexes">
                       <list>
                       <bean class="org.apache.ignite.cache.QueryIndex">
                           <property name="fields">
                                <map>
                                <!-- The boolean value is the acceding flag. -->
                                <entry key="name" value="true"/>
                                </map>
                           </property>
                       </bean>
                       </list>
                       </property>
                   </bean>
               </list>
           </property>
       </bean>

- - ### Method Summary

    All Methods Instance Methods Abstract Methods
    Modifier and Type | Method | Description
    --- | --- | ---
    `BinaryObject` | `buildEnum​(String typeName, int ord)` | Create enum object using value.
    `BinaryObject` | `buildEnum​(String typeName, String name)` | Create enum object using name.
    `BinaryObjectBuilder` | `builder​(String typeName)` | Creates new binary builder.
    `BinaryObjectBuilder` | `builder​(BinaryObject binaryObj)` | Creates binary builder initialized by existing binary object.
    `BinaryType` | `registerClass​(Class<?> cls)` | Register binary type for specified class.
    `BinaryType` | `registerEnum​(String typeName, Map<String,​Integer> vals)` | Register enum type.
    `<T> T` | `toBinary​(@Nullable Object obj)` | Converts provided object to instance of `BinaryObject`.
    `BinaryType` | `type​(int typeId)` | Gets metadata for provided type ID.
    `BinaryType` | `type​(Class<?> cls)` | Gets metadata for provided class.
    `BinaryType` | `type​(String typeName)` | Gets metadata for provided class name.
    `int` | `typeId​(@NotNull String typeName)` | Gets type ID for given type name.
    `Collection<BinaryType>` | `types()` | Gets metadata for all known types.

- - ### Method Detail

    - #### typeId

          int typeId​(@NotNull
                     @NotNull String typeName)

      Gets type ID for given type name. If no user defined `BinaryIdMapper` is configured via `BinaryConfiguration`, then system mapper will be used.
      Parameters:
        `typeName` - Type name.
      Returns:
        Type ID which a type would have had if it has been registered in Ignite.

    - #### toBinary

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

      Converts provided object to instance of `BinaryObject`.
      Type Parameters:
        `T` - Type of the binary object.
      Parameters:
        `obj` - Object to convert.
      Returns:
        Converted object or `null` if obj is null.
      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` - In case of error.

    - #### 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)
                          throws BinaryObjectException

      Create enum object using value.
      Parameters:
        `typeName` - Type name.
        `ord` - Ordinal.
      Returns:
        Enum object.
      Throws:
        `BinaryObjectException` - In case of error.

    - #### buildEnum

          BinaryObject buildEnum​(String typeName,
                                 String name)
                          throws BinaryObjectException

      Create enum object using name.
      Parameters:
        `typeName` - Type name.
        `name` - Name.
      Returns:
        Enum object.
      Throws:
        `BinaryObjectException` - In case of error.

    - #### registerEnum

          BinaryType registerEnum​(String typeName,
                                  Map<String,​Integer> vals)
                           throws BinaryObjectException

      Register enum type.
      Parameters:
        `typeName` - Type name.
        `vals` - Mapping of enum constant names to ordinals.
      Returns:
        Binary type for registered enum.
      Throws:
        `BinaryObjectException` - In case of error.

    - #### registerClass

          BinaryType registerClass​(Class<?> cls)
                            throws BinaryObjectException

      Register binary type for specified class.
      Parameters:
        `cls` - Class.
      Returns:
        Metadata.
      Throws:
        `BinaryObjectException` - In case of error.