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

com.flipkart.hbaseobjectmapper.codec.BestSuitCodec Maven / Gradle / Ivy

package com.flipkart.hbaseobjectmapper.codec;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flipkart.hbaseobjectmapper.Flag;
import com.flipkart.hbaseobjectmapper.codec.exceptions.DeserializationException;
import com.flipkart.hbaseobjectmapper.codec.exceptions.SerializationException;
import com.flipkart.hbaseobjectmapper.exceptions.BadHBaseLibStateException;
import com.google.common.collect.ImmutableMap;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * This is an implementation of {@link Codec} that:
 * 
    *
  1. uses HBase's native methods to serialize objects of data types {@link Boolean}, {@link Short}, {@link Integer}, {@link Long}, {@link Float}, {@link Double}, {@link String} and {@link BigDecimal}
  2. *
  3. uses Jackson's JSON serializer for all other data types
  4. *
  5. serializes null as null
  6. *
*

* This codec takes the following {@link Flag Flag}s: *

    *
  • {@link #SERIALIZE_AS_STRING}: When this flag is "true", this codec stores field/rowkey values in it's string representation (e.g. 560034 is serialized into a byte[] that represents the string "560034"). This flag applies only to fields or rowkeys of data types in point 1 above.
  • *
*

* This is the default codec for {@link com.flipkart.hbaseobjectmapper.HBObjectMapper HBObjectMapper}. */ public class BestSuitCodec implements Codec { public static final String SERIALIZE_AS_STRING = "serializeAsString"; private static final Map fromBytesMethodNames = ImmutableMap.builder() .put(Boolean.class, "toBoolean") .put(Short.class, "toShort") .put(Integer.class, "toInt") .put(Long.class, "toLong") .put(Float.class, "toFloat") .put(Double.class, "toDouble") .put(String.class, "toString") .put(BigDecimal.class, "toBigDecimal") .build(); private static final Map nativeCounterParts = ImmutableMap.builder() .put(Boolean.class, boolean.class) .put(Short.class, short.class) .put(Long.class, long.class) .put(Integer.class, int.class) .put(Float.class, float.class) .put(Double.class, double.class) .build(); private static final Map fromBytesMethods, toBytesMethods; private static final Map constructors; static { try { fromBytesMethods = new HashMap<>(fromBytesMethodNames.size()); toBytesMethods = new HashMap<>(fromBytesMethodNames.size()); constructors = new HashMap<>(fromBytesMethodNames.size()); for (Map.Entry e : fromBytesMethodNames.entrySet()) { Class clazz = e.getKey(); String toDataTypeMethodName = e.getValue(); Method fromBytesMethod = Bytes.class.getDeclaredMethod(toDataTypeMethodName, byte[].class); Method toBytesMethod = Bytes.class.getDeclaredMethod("toBytes", nativeCounterParts.containsKey(clazz) ? nativeCounterParts.get(clazz) : clazz); Constructor constructor = clazz.getConstructor(String.class); fromBytesMethods.put(clazz, fromBytesMethod); toBytesMethods.put(clazz, toBytesMethod); constructors.put(clazz, constructor); } } catch (Exception ex) { throw new BadHBaseLibStateException(ex); } } private final ObjectMapper objectMapper; /** * Construct an object of class {@link BestSuitCodec} with custom instance of Jackson's Object Mapper * * @param objectMapper Instance of Jackson's Object Mapper */ @SuppressWarnings("WeakerAccess") public BestSuitCodec(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } /** * Construct an object of class {@link BestSuitCodec} */ public BestSuitCodec() { this(getObjectMapper()); } private static ObjectMapper getObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return objectMapper; } /* * @inherit */ @Override public byte[] serialize(Serializable object, Map flags) throws SerializationException { if (object == null) return null; Class clazz = object.getClass(); if (toBytesMethods.containsKey(clazz)) { boolean serializeAsString = isSerializeAsStringTrue(flags); try { Method toBytesMethod = toBytesMethods.get(clazz); return serializeAsString ? Bytes.toBytes(String.valueOf(object)) : (byte[]) toBytesMethod.invoke(null, object); } catch (Exception e) { throw new SerializationException(String.format("Could not serialize value of type %s using HBase's native methods", clazz.getName()), e); } } else { try { return objectMapper.writeValueAsBytes(object); } catch (Exception e) { throw new SerializationException("Could not serialize object to JSON using Jackson", e); } } } /* * @inherit */ @Override public Serializable deserialize(byte[] bytes, Type type, Map flags) throws DeserializationException { if (bytes == null) return null; if (type instanceof Class && fromBytesMethods.containsKey(type)) { boolean serializeAsString = isSerializeAsStringTrue(flags); try { Serializable value; if (serializeAsString) { Constructor constructor = constructors.get(type); value = (Serializable) constructor.newInstance(Bytes.toString(bytes)); } else { Method method = fromBytesMethods.get(type); value = (Serializable) method.invoke(null, new Object[]{bytes}); } return value; } catch (Exception e) { throw new DeserializationException("Could not deserialize byte array into an object using HBase's native methods", e); } } else { JavaType javaType = null; try { javaType = objectMapper.constructType(type); return objectMapper.readValue(bytes, javaType); } catch (Exception e) { throw new DeserializationException(String.format("Could not deserialize JSON into an object of type %s using Jackson%n(Jackson resolved type = %s)", type, javaType), e); } } } /* * @inherit */ @Override public boolean canDeserialize(Type type) { JavaType javaType = objectMapper.constructType(type); return objectMapper.canDeserialize(javaType); } private static boolean isSerializeAsStringTrue(Map flags) { return flags != null && flags.get(SERIALIZE_AS_STRING) != null && flags.get(SERIALIZE_AS_STRING).equalsIgnoreCase("true"); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy