All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.oss.driver.api.core.type.codec.TypeCodec Maven / Gradle / Ivy

The newest version!
/*
 * Copyright DataStax, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.oss.driver.api.core.type.codec;

import com.datastax.oss.driver.api.core.ProtocolVersion;
import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.data.TupleValue;
import com.datastax.oss.driver.api.core.data.UdtValue;
import com.datastax.oss.driver.api.core.metadata.schema.AggregateMetadata;
import com.datastax.oss.driver.api.core.type.DataType;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
import com.datastax.oss.driver.shaded.guava.common.base.Preconditions;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.nio.ByteBuffer;

/**
 * Manages the two-way conversion between a CQL type and a Java type.
 *
 * 

Type codec implementations: * *

    *
  1. must be thread-safe. *
  2. must perform fast and never block. *
  3. must support all native protocol versions; it is not possible to use different * codecs for the same types but under different protocol versions. *
  4. must comply with the native protocol specifications; failing to do so will result * in unexpected results and could cause the driver to crash. *
  5. should be stateless and immutable. *
  6. should interpret {@code null} values and empty byte buffers (i.e. * {@link ByteBuffer#remaining()} == 0) in a reasonable way; usually, {@code * NULL} CQL values should map to {@code null} references, but exceptions exist; e.g. for * varchar types, a {@code NULL} CQL value maps to a {@code null} reference, whereas an empty * buffer maps to an empty String. For collection types, it is also admitted that {@code NULL} * CQL values map to empty Java collections instead of {@code null} references. In any case, * the codec's behavior with respect to {@code null} values and empty ByteBuffers should be * clearly documented. *
  7. for Java types that have a primitive equivalent, should implement the appropriate * "primitive" codec interface, e.g. {@link PrimitiveBooleanCodec} for {@code boolean}. This * allows the driver to avoid the overhead of boxing when using primitive accessors such as * {@link Row#getBoolean(int)}. *
  8. when decoding, must not consume {@link ByteBuffer} instances by performing * relative read operations that modify their current position; codecs should instead prefer * absolute read methods or, if necessary, {@link ByteBuffer#duplicate() duplicate} their byte * buffers prior to reading them. *
*/ public interface TypeCodec { @NonNull GenericType getJavaType(); @NonNull DataType getCqlType(); /** * Whether this codec is capable of processing the given Java type. * *

The default implementation is invariant with respect to the passed argument * (through the usage of {@link GenericType#equals(Object)}) and it's strongly recommended not * to modify this behavior. This means that a codec will only ever accept the exact * Java type that it has been created for. * *

If the argument represents a Java primitive type, its wrapper type is considered instead. */ default boolean accepts(@NonNull GenericType javaType) { Preconditions.checkNotNull(javaType); return getJavaType().equals(javaType.wrap()); } /** * Whether this codec is capable of processing the given Java class. * *

This implementation simply compares the given class (or its wrapper type if it is a * primitive type) against this codec's runtime (raw) class; it is invariant with respect * to the passed argument (through the usage of {@link Class#equals(Object)} and it's strongly * recommended not to modify this behavior. This means that a codec will only ever return * {@code true} for the exact runtime (raw) Java class that it has been created for. * *

Implementors are encouraged to override this method if there is a more efficient way. In * particular, if the codec targets a final class, the check can be done with a simple {@code ==}. */ default boolean accepts(@NonNull Class javaClass) { Preconditions.checkNotNull(javaClass); if (javaClass.isPrimitive()) { if (javaClass == Boolean.TYPE) { javaClass = Boolean.class; } else if (javaClass == Character.TYPE) { javaClass = Character.class; } else if (javaClass == Byte.TYPE) { javaClass = Byte.class; } else if (javaClass == Short.TYPE) { javaClass = Short.class; } else if (javaClass == Integer.TYPE) { javaClass = Integer.class; } else if (javaClass == Long.TYPE) { javaClass = Long.class; } else if (javaClass == Float.TYPE) { javaClass = Float.class; } else if (javaClass == Double.TYPE) { javaClass = Double.class; } } return getJavaType().getRawType().equals(javaClass); } /** * Whether this codec is capable of encoding the given Java object. * *

The object's Java type is inferred from its runtime (raw) type, contrary to {@link * #accepts(GenericType)} which is capable of handling generic types. * *

Contrary to other {@code accept} methods, this method's default implementation is * covariant with respect to the passed argument (through the usage of {@link * Class#isAssignableFrom(Class)}) and it's strongly recommended not to modify this * behavior. This means that, by default, a codec will accept any subtype of the * Java type that it has been created for. This is so because codec lookups by arbitrary Java * objects only make sense when attempting to encode, never when attempting to decode, and indeed * the {@linkplain #encode(Object, ProtocolVersion) encode} method is covariant with {@code * JavaTypeT}. * *

It can only handle non-parameterized types; codecs handling parameterized types, such as * collection types, must override this method and perform some sort of "manual" inspection of the * actual type parameters. * *

Similarly, codecs that only accept a partial subset of all possible values must override * this method and manually inspect the object to check if it complies or not with the codec's * limitations. * *

Finally, if the codec targets a non-generic Java class, it might be possible to implement * this method with a simple {@code instanceof} check. */ default boolean accepts(@NonNull Object value) { Preconditions.checkNotNull(value); return getJavaType().getRawType().isAssignableFrom(value.getClass()); } /** Whether this codec is capable of processing the given CQL type. */ default boolean accepts(@NonNull DataType cqlType) { Preconditions.checkNotNull(cqlType); return this.getCqlType().equals(cqlType); } /** * Encodes the given value in the binary format of the CQL type handled by this codec. * *

    *
  • Null values should be gracefully handled and no exception should be raised; they should * be considered as the equivalent of a NULL CQL value; *
  • Codecs for CQL collection types should not permit null elements; *
  • Codecs for CQL collection types should treat a {@code null} input as the equivalent of an * empty collection. *
*/ @Nullable ByteBuffer encode(@Nullable JavaTypeT value, @NonNull ProtocolVersion protocolVersion); /** * Decodes a value from the binary format of the CQL type handled by this codec. * *
    *
  • Null or empty buffers should be gracefully handled and no exception should be raised; * they should be considered as the equivalent of a NULL CQL value and, in most cases, * should map to {@code null} or a default value for the corresponding Java type, if * applicable; *
  • Codecs for CQL collection types should clearly document whether they return immutable * collections or not (note that the driver's default collection codecs return * mutable collections); *
  • Codecs for CQL collection types should avoid returning {@code null}; they should return * empty collections instead (the driver's default collection codecs all comply with this * rule); *
  • The provided {@link ByteBuffer} should never be consumed by read operations that modify * its current position; if necessary, {@link ByteBuffer#duplicate()} duplicate} it before * consuming. *
*/ @Nullable JavaTypeT decode(@Nullable ByteBuffer bytes, @NonNull ProtocolVersion protocolVersion); /** * Formats the given value as a valid CQL literal according to the CQL type handled by this codec. * *

Implementors should take care of quoting and escaping the resulting CQL literal where * applicable. Null values should be accepted; in most cases, implementations should return the * CQL keyword {@code "NULL"} for {@code null} inputs. * *

Implementing this method is not strictly mandatory. It is used: * *

    *
  1. by the request logger, if parameter logging is enabled; *
  2. to format the INITCOND in {@link AggregateMetadata#describe(boolean)}; *
  3. in the {@code toString()} representation of some driver objects (such as {@link UdtValue} * and {@link TupleValue}), which is only used in driver logs; *
  4. for literal values in the query builder (see {@code QueryBuilder#literal(Object, * CodecRegistry)} and {@code QueryBuilder#literal(Object, TypeCodec)}). *
* * If you choose not to implement this method, don't throw an exception but instead return a * constant string (for example "XxxCodec.format not implemented"). */ @NonNull String format(@Nullable JavaTypeT value); /** * Parse the given CQL literal into an instance of the Java type handled by this codec. * *

Implementors should take care of unquoting and unescaping the given CQL string where * applicable. Null values and empty strings should be accepted, as well as the string {@code * "NULL"}; in most cases, implementations should interpret these inputs has equivalent to a * {@code null} reference. * *

Implementing this method is not strictly mandatory: internally, the driver only uses it to * parse the INITCOND when building the {@link AggregateMetadata metadata of an aggregate * function} (and in most cases it will use a built-in codec, unless the INITCOND has a custom * type). * *

If you choose not to implement this method, don't throw an exception but instead return * {@code null}. */ @Nullable JavaTypeT parse(@Nullable String value); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy