Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.datatorrent.lib.appdata.gpo; import java.io.Serializable; import java.lang.reflect.Array; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.apache.commons.lang3.mutable.MutableInt; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.datatorrent.lib.appdata.schemas.Fields; import com.datatorrent.lib.appdata.schemas.FieldsDescriptor; import com.datatorrent.lib.appdata.schemas.ResultFormatter; import com.datatorrent.lib.appdata.schemas.Type; import com.datatorrent.lib.util.PojoUtils; import com.datatorrent.lib.util.PojoUtils.Getter; import com.datatorrent.lib.util.PojoUtils.GetterBoolean; import com.datatorrent.lib.util.PojoUtils.GetterByte; import com.datatorrent.lib.util.PojoUtils.GetterChar; import com.datatorrent.lib.util.PojoUtils.GetterDouble; import com.datatorrent.lib.util.PojoUtils.GetterFloat; import com.datatorrent.lib.util.PojoUtils.GetterInt; import com.datatorrent.lib.util.PojoUtils.GetterLong; import com.datatorrent.lib.util.PojoUtils.GetterShort; /** * This class holds utility methods for serializing and deserializing {@link GPOMutable} objects to/from bytes and JSON. * There are also utility methods for converting POJOs into GPOMutable objects. * @since 3.0.0 */ public class GPOUtils { /** * This class should not be instantiated */ private GPOUtils() { //Do nothing } /** * This utility method converts a field to type map specified in JSON into * a java map from field to type. An example of a JSON field to type map * is the following: * <br/> * <br/> * <pre> * {@code * { * "fieldName1":"integer", * "fieldName2":"string", * "fieldName3":"byte", * ... * } * } * </pre> * @param jo The {@link JSONObject} containing the JSON to convert. * @return A java Map from field name to the corresponding field type. * @throws JSONException */ @SuppressWarnings("unchecked") public static Map<String, Type> buildTypeMap(JSONObject jo) throws JSONException { Map<String, Type> fieldToType = Maps.newHashMap(); for (Iterator<String> keys = (Iterator<String>) jo.keys(); keys.hasNext();) { String key = keys.next(); String val = jo.getString(key); Type type = Type.getTypeEx(val); fieldToType.put(key, type); } return fieldToType; } /** * Converts the provided JSON into a GPOMutable object with the provided {@link FieldsDescriptor} * @param fieldsDescriptor The {@link FieldsDescriptor} to initialize the {@link GPOMutable} object with. * @param dpou The JSONObject to deserialize from. * @return The deserialized GPOMutable object. */ public static GPOMutable deserialize(FieldsDescriptor fieldsDescriptor, JSONObject dpou) { GPOMutable gpo = new GPOMutable(fieldsDescriptor); @SuppressWarnings("unchecked") Iterator<String> itr = (Iterator<String>) dpou.keys(); while (itr.hasNext()) { String field = itr.next(); setFieldFromJSON(gpo, field, dpou); } return gpo; } /** * This method deserializes the fields in the given {@link FieldsDescriptor} into a map. * @param fieldsDescriptor The {@link FieldsDescriptor} to fetch fields from. * @param dpou The {@link JSONObject} which contains the fields whose values need to be fetched. * @return A {@link Map} whose keys are field names, and whose values are possible values for those fields. */ public static Map<String, Set<Object>> deserializeToMap(FieldsDescriptor fieldsDescriptor, JSONObject dpou) { Map<String, Set<Object>> keyToValues = Maps.newHashMap(); for (String key : fieldsDescriptor.getFields().getFields()) { if (!dpou.has(key)) { throw new IllegalArgumentException("The given key " + key + " is not contained in the given JSON"); } Set<Object> keyValues; Object keyValue; try { keyValue = dpou.get(key); } catch (JSONException ex) { throw new IllegalStateException("This should never happen", ex); } if (keyValue instanceof JSONArray) { JSONArray ja = (JSONArray) keyValue; keyValues = Sets.newHashSetWithExpectedSize(ja.length()); Type type = fieldsDescriptor.getType(key); for (int index = 0; index < ja.length(); index++) { keyValues.add(getFieldFromJSON(type, ja, index)); } } else if (keyValue instanceof JSONObject) { throw new UnsupportedOperationException("Cannot extract objects from JSONObjects"); } else { keyValues = Sets.newHashSetWithExpectedSize(1); keyValues.add(getFieldFromJSON(fieldsDescriptor, key, dpou)); } keyToValues.put(key, keyValues); } return keyToValues; } /** * This is a helper method for deserialization of a GPOMutable from JSON. It allows you to select a field from * a JSONObject in a json array and set it on the provided GPOMutable object. The format of the JSONArray should * be the following: * <br/> * <br/> * <pre> * {@code * [ * { * "fieldName1":"val1", * "fieldName2":"val2", * ... * }, * { * "fieldName1":"valx", * ... * } * ... * ] * } * </pre> * <br/> * <br/> * @param gpo The {@link GPOMutable} to set fields on. * @param type The type of the field that will be set. * @param field The name of the field that will be set. * The name of the field must be the same in both the {@link GPOMutable}'s {@link FieldsDescriptor} object and in the JSONObject. * @param jo The JSONOArray holding JSONObjects to deserialize from. * @param index The index of the JSONArray */ public static void setFieldFromJSON(GPOMutable gpo, Type type, String field, JSONArray jo, int index) { GPOType gpoType = GPOType.GPO_TYPE_ARRAY[type.ordinal()]; gpoType.setFieldFromJSON(gpo, field, jo, index); } /** * This is a utility method to deserialize data from the given JSONObject into a {@link GPOMutable} object. * The format of the JSON to deserialize from should look like this. * <pre> * {@code * { * "fieldName1":"val1", * "fieldName2":"val2", * ... * } * } * </pre> * @param gpo The {@link GPOMutable} object to deserialize into. * @param field The name of the field to take from the JSON and place into the {@link GPOMutable} object. * The name of the field must be the same in the {@link FieldsDescriptor} and the {@link GPOMutable} object. * @param jo The JSONObject to deserialize from. */ public static void setFieldFromJSON(GPOMutable gpo, String field, JSONObject jo) { Object val = getFieldFromJSON(gpo.getFieldDescriptor(), field, jo); gpo.setFieldGeneric(field, val); } /** * This method gets the given field from the given {@link JSONObject} and converts the field to an object * of the type specified in the given {@link FieldsDescriptor}. * @param fd The {@link FieldsDescriptor} describing the type of each field. * @param field The field to retrieve from the given {@link JSONObject}. * @param jo The {@link JSONObject} to retrieve a field from. * @return The value of the given field converted to an object of the correct type. */ public static Object getFieldFromJSON(FieldsDescriptor fd, String field, JSONObject jo) { Type type = fd.getType(field); int intVal = 0; if (numericTypeIntOrSmaller(type)) { try { intVal = jo.getInt(field); } catch (JSONException ex) { throw new IllegalArgumentException( "The key " + field + " does not have a valid " + type + " value.", ex); } if (type != Type.INTEGER && !insideRange(type, intVal)) { throw new IllegalArgumentException("The key " + field + " has a value " + intVal + " which is out of range for a " + type + "."); } } if (type == Type.BOOLEAN) { try { return jo.getBoolean(field); } catch (JSONException ex) { throw new IllegalArgumentException("The key " + field + " does not have a valid bool value.", ex); } } else if (type == Type.BYTE) { return ((byte) intVal); } else if (type == Type.SHORT) { return ((short) intVal); } else if (type == Type.INTEGER) { return intVal; } else if (type == Type.LONG) { try { return jo.getLong(field); } catch (JSONException ex) { throw new IllegalArgumentException("The key " + field + " does not have a valid long value.", ex); } } else if (type == Type.CHAR) { String val; try { val = jo.getString(field); } catch (JSONException ex) { throw new IllegalArgumentException("The key " + field + " does not have a valid character value.", ex); } if (val.length() != 1) { throw new IllegalArgumentException( "The key " + field + " has a value " + val + " that is not one character long."); } return val.charAt(0); } else if (type == Type.STRING) { try { return jo.getString(field); } catch (JSONException ex) { throw new IllegalArgumentException("The key " + field + " does not have a valid string value.", ex); } } else if (type == Type.DOUBLE) { try { return jo.getDouble(field); } catch (JSONException ex) { throw new IllegalArgumentException("The key " + field + " does not have a valid double value.", ex); } } else if (type == Type.FLOAT) { try { return (float) jo.getDouble(field); } catch (JSONException ex) { throw new IllegalArgumentException("The key " + field + " does not have a valid double value.", ex); } } else { throw new UnsupportedOperationException("The type " + type + " is not supported."); } } /** * This method gets an object of the given {@link Type} from the given {@link JSONArray} at the * given index. * @param type The {@link Type} of the object to retrieve from the {@link JSONArray}. * @param ja The {@link JSONArray} to retrieve objects from. * @param index The index of the object in the {@link JSONArray} to retrieve. * @return The object retrieved from the {@link JSONArray}. */ public static Object getFieldFromJSON(Type type, JSONArray ja, int index) { int intVal = 0; if (numericTypeIntOrSmaller(type)) { try { intVal = ja.getInt(index); } catch (JSONException ex) { throw new IllegalArgumentException( "The index " + index + " does not have a valid " + type + " value.", ex); } if (type != Type.INTEGER && !insideRange(type, intVal)) { throw new IllegalArgumentException("The index " + index + " has a value " + intVal + " which is out of range for a " + type + "."); } } if (type == Type.BOOLEAN) { try { return ja.getBoolean(index); } catch (JSONException ex) { throw new IllegalArgumentException("The index " + index + " does not have a valid bool value.", ex); } } else if (type == Type.BYTE) { return ((byte) intVal); } else if (type == Type.SHORT) { return ((short) intVal); } else if (type == Type.INTEGER) { return intVal; } else if (type == Type.LONG) { try { return ja.getLong(index); } catch (JSONException ex) { throw new IllegalArgumentException("The index " + index + " does not have a valid long value.", ex); } } else if (type == Type.CHAR) { String val; try { val = ja.getString(index); } catch (JSONException ex) { throw new IllegalArgumentException("The index " + index + " does not have a valid character value.", ex); } if (val.length() != 1) { throw new IllegalArgumentException( "The index " + index + " has a value " + val + " that is not one character long."); } return val.charAt(0); } else if (type == Type.STRING) { try { return ja.getString(index); } catch (JSONException ex) { throw new IllegalArgumentException("The index " + index + " does not have a valid string value.", ex); } } else if (type == Type.DOUBLE) { try { return ja.getDouble(index); } catch (JSONException ex) { throw new IllegalArgumentException("The index " + index + " does not have a valid double value.", ex); } } else if (type == Type.FLOAT) { try { return (float) ja.getDouble(index); } catch (JSONException ex) { throw new IllegalArgumentException("The index " + index + " does not have a valid double value.", ex); } } else { throw new UnsupportedOperationException("The type " + type + " is not supported."); } } /** * This utility method serializes the given fields from the given {@link GPOMutable} object into JSON using the * given resultFormatter. * @param gpo The {@link GPOMutable} to serialize. * @param fields The fields from the given {@link GPOMutable} object to serialize. * @param resultFormatter The result formatter to use when formatting the output data during serialization. * @return The serialized {@link GPOMutable} object. * @throws JSONException */ public static JSONObject serializeJSONObject(GPOMutable gpo, Fields fields, ResultFormatter resultFormatter) throws JSONException { JSONObject jo = new JSONObject(); FieldsDescriptor fd = gpo.getFieldDescriptor(); for (String field : fields.getFields()) { Type fieldType = fd.getType(field); GPOType gpoType = GPOType.GPO_TYPE_ARRAY[fieldType.ordinal()]; gpoType.serializeJSONObject(jo, gpo, field, resultFormatter); } return jo; } /** * Serializes the given {@link GPOMutable} object with the given resultFormatter. * @param gpo The {@link GPOMutable} to serialize. * @param resultFormatter The result formatter to use when serializing data. * @return The serialized {@link GPOMutable} object. * @throws JSONException */ public static JSONObject serializeJSONObject(GPOMutable gpo, ResultFormatter resultFormatter) throws JSONException { return serializeJSONObject(gpo, gpo.getFieldDescriptor().getFields(), resultFormatter); } /** * Computes the number of bytes required to serialize the given {@link GPOMutable} object. Excluding the * object fields in the {@link GPOMutable}. * @param gpo The {@link GPOMutable} object to compute a serialized size for. * @return The serialized size for the given {@link GPOMutable} object. */ public static int serializedLength(GPOMutable gpo) { int arrayLength = 0; FieldsDescriptor fd = gpo.getFieldDescriptor(); List<Type> types = fd.getTypesList(); for (int typeIndex = 0; typeIndex < types.size(); typeIndex++) { Type type = types.get(typeIndex); switch (type) { case STRING: { for (String val : gpo.getFieldsString()) { arrayLength += Type.INTEGER.getByteSize(); arrayLength += val.getBytes().length; } break; } case OBJECT: { //Don't include objects. break; } default: { arrayLength += fd.getTypeToFields().get(type).size() * type.getByteSize(); } } } return arrayLength; } /** * Serializes the given {@link GPOMutable} object to an array of bytes. * @param gpo The {@link GPOMutable} object to serialize. * @param byteArrayList A byte array list to pack serialized data into. Note that * it is assumed that the byteArrayList is empty when passed to this method. * @return The serialized {@link GPOMutable} object. */ public static byte[] serialize(GPOMutable gpo, GPOByteArrayList byteArrayList) { int slength = serializedLength(gpo); byte[] sbytes = new byte[slength]; MutableInt offset = new MutableInt(0); boolean[] fieldsBoolean = gpo.getFieldsBoolean(); if (fieldsBoolean != null) { for (int index = 0; index < fieldsBoolean.length; index++) { serializeBoolean(fieldsBoolean[index], sbytes, offset); } } char[] fieldsCharacter = gpo.getFieldsCharacter(); if (fieldsCharacter != null) { for (int index = 0; index < fieldsCharacter.length; index++) { serializeChar(fieldsCharacter[index], sbytes, offset); } } byte[] fieldsByte = gpo.getFieldsByte(); if (fieldsByte != null) { for (int index = 0; index < fieldsByte.length; index++) { serializeByte(fieldsByte[index], sbytes, offset); } } short[] fieldsShort = gpo.getFieldsShort(); if (fieldsShort != null) { for (int index = 0; index < fieldsShort.length; index++) { serializeShort(fieldsShort[index], sbytes, offset); } } int[] fieldsInteger = gpo.getFieldsInteger(); if (fieldsInteger != null) { for (int index = 0; index < fieldsInteger.length; index++) { serializeInt(fieldsInteger[index], sbytes, offset); } } long[] fieldsLong = gpo.getFieldsLong(); if (fieldsLong != null) { for (int index = 0; index < fieldsLong.length; index++) { serializeLong(fieldsLong[index], sbytes, offset); } } float[] fieldsFloat = gpo.getFieldsFloat(); if (fieldsFloat != null) { for (int index = 0; index < fieldsFloat.length; index++) { serializeFloat(fieldsFloat[index], sbytes, offset); } } double[] fieldsDouble = gpo.getFieldsDouble(); if (fieldsDouble != null) { for (int index = 0; index < fieldsDouble.length; index++) { serializeDouble(fieldsDouble[index], sbytes, offset); } } String[] fieldsString = gpo.getFieldsString(); if (fieldsString != null) { for (int index = 0; index < fieldsString.length; index++) { serializeString(fieldsString[index], sbytes, offset); } } if (sbytes.length > 0) { byteArrayList.add(sbytes); } Object[] fieldsObject = gpo.getFieldsObject(); Serde[] serdes = gpo.getFieldDescriptor().getSerdes(); if (fieldsObject != null) { for (int index = 0; index < fieldsObject.length; index++) { byteArrayList.add(serdes[index].serializeObject(fieldsObject[index])); } } byte[] bytes = byteArrayList.toByteArray(); byteArrayList.clear(); return bytes; } /** * Serializes the given {@link GPOMutable} object while excluding the provided fields from the serialization. * @param gpo The {@link GPOMutable} to serialize. * @param excludedFields The fields from the {@link GPOMutable} object to exclude. * @return A byte array containing the serialized {@link GPOMutable}. */ public static byte[] serialize(GPOMutable gpo, Fields excludedFields) { int slength = serializedLength(gpo); byte[] sbytes = new byte[slength]; MutableInt offset = new MutableInt(0); Set<String> fields = gpo.getFieldDescriptor().getFields().getFields(); Set<String> exFieldsSet = excludedFields.getFields(); for (String field : fields) { if (exFieldsSet.contains(field)) { continue; } Type type = gpo.getFieldDescriptor().getType(field); GPOType gpoType = GPOType.GPO_TYPE_ARRAY[type.ordinal()]; gpoType.serialize(gpo, field, sbytes, offset); } return sbytes; } /** * Deserializes a {@link GPOMutable} object from the given byte array at the given offset with the given * {@link FieldsDescriptor} object. * @param fd The {@link FieldsDescriptor} object which describes the schema of the {@link GPOMutable} object * to deserialize. * @param serializedGPO A byte array containing the serialized {@link GPOMutable} object. * @param offset An offset in the byte array to start deserializing from. * @return The deserialized GPOMutable. */ public static GPOMutable deserialize(FieldsDescriptor fd, byte[] serializedGPO, MutableInt offset) { GPOMutable gpo = new GPOMutable(fd); boolean[] fieldsBoolean = gpo.getFieldsBoolean(); if (fieldsBoolean != null) { for (int index = 0; index < fieldsBoolean.length; index++) { fieldsBoolean[index] = deserializeBoolean(serializedGPO, offset); } } char[] fieldsCharacter = gpo.getFieldsCharacter(); if (fieldsCharacter != null) { for (int index = 0; index < fieldsCharacter.length; index++) { fieldsCharacter[index] = deserializeChar(serializedGPO, offset); } } byte[] fieldsByte = gpo.getFieldsByte(); if (fieldsByte != null) { for (int index = 0; index < fieldsByte.length; index++) { fieldsByte[index] = deserializeByte(serializedGPO, offset); } } short[] fieldsShort = gpo.getFieldsShort(); if (fieldsShort != null) { for (int index = 0; index < fieldsShort.length; index++) { fieldsShort[index] = deserializeShort(serializedGPO, offset); } } int[] fieldsInteger = gpo.getFieldsInteger(); if (fieldsInteger != null) { for (int index = 0; index < fieldsInteger.length; index++) { fieldsInteger[index] = deserializeInt(serializedGPO, offset); } } long[] fieldsLong = gpo.getFieldsLong(); if (fieldsLong != null) { for (int index = 0; index < fieldsLong.length; index++) { fieldsLong[index] = deserializeLong(serializedGPO, offset); } } float[] fieldsFloat = gpo.getFieldsFloat(); if (fieldsFloat != null) { for (int index = 0; index < fieldsFloat.length; index++) { fieldsFloat[index] = deserializeFloat(serializedGPO, offset); } } double[] fieldsDouble = gpo.getFieldsDouble(); if (fieldsDouble != null) { for (int index = 0; index < fieldsDouble.length; index++) { fieldsDouble[index] = deserializeDouble(serializedGPO, offset); } } String[] fieldsString = gpo.getFieldsString(); if (fieldsString != null) { for (int index = 0; index < fieldsString.length; index++) { fieldsString[index] = deserializeString(serializedGPO, offset); } } Object[] fieldsObject = gpo.getFieldsObject(); Serde[] serdes = fd.getSerdes(); if (fieldsObject != null) { for (int index = 0; index < fieldsObject.length; index++) { fieldsObject[index] = serdes[index].deserializeObject(serializedGPO, offset); } } return gpo; } /** * Deserializes a {@link GPOMutable} object from the given byte array at the given offset, which was * serialized with the given {@link FieldsDescriptor} with the given fields excluded. * @param fieldsDescriptor The {@link FieldsDescriptor} object corresponding to the {@link GPOMutable}. * @param excludedFields The fields to exclude from serializing the {@link GPOMutable}. * @param serializedGPO The array containing the serialized {@link GPOMutable}. * @param offset The offset in the provided array to start deserializing from. * @return The deserialized {@link GPOMutable}. */ public static GPOMutable deserialize(FieldsDescriptor fieldsDescriptor, Fields excludedFields, byte[] serializedGPO, int offset) { GPOMutable gpo = new GPOMutable(fieldsDescriptor); MutableInt offsetM = new MutableInt(offset); Set<String> exFieldsSet = excludedFields.getFields(); for (String field : fieldsDescriptor.getFields().getFields()) { if (exFieldsSet.contains(field)) { continue; } Type type = fieldsDescriptor.getType(field); GPOType gpoType = GPOType.GPO_TYPE_ARRAY[type.ordinal()]; gpoType.deserialize(gpo, field, serializedGPO, offsetM); } return gpo; } /** * This method deserializes a string from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized string. */ public static String deserializeString(byte[] buffer, MutableInt offset) { int length = deserializeInt(buffer, offset); String val = new String(buffer, offset.intValue(), length); offset.add(length); return val; } /** * This method serializes the given string to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeString(String val, byte[] buffer, MutableInt offset) { byte[] stringBytes = val.getBytes(); int length = stringBytes.length; serializeInt(length, buffer, offset); for (int index = 0; index < length; index++) { buffer[offset.intValue() + index] = stringBytes[index]; } offset.add(length); } public static byte[] serializeString(String val) { byte[] stringBytes = val.getBytes(); byte[] length = GPOUtils.serializeInt(stringBytes.length); byte[] serialized = new byte[stringBytes.length + length.length]; System.arraycopy(length, 0, serialized, 0, length.length); System.arraycopy(stringBytes, 0, serialized, length.length, stringBytes.length); return serialized; } /** * This method deserializes a long from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized long. */ public static long deserializeLong(byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); long val = ((((long) buffer[0 + offsetInt]) & 0xFFL) << 56) | ((((long) buffer[1 + offsetInt]) & 0xFFL) << 48) | ((((long) buffer[2 + offsetInt]) & 0xFFL) << 40) | ((((long) buffer[3 + offsetInt]) & 0xFFL) << 32) | ((((long) buffer[4 + offsetInt]) & 0xFFL) << 24) | ((((long) buffer[5 + offsetInt]) & 0xFFL) << 16) | ((((long) buffer[6 + offsetInt]) & 0xFFL) << 8) | (((long) buffer[7 + offsetInt]) & 0xFFL); offset.add(Type.LONG.getByteSize()); return val; } /** * This method serializes the given long to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeLong(long val, byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); buffer[0 + offsetInt] = (byte) ((val >> 56) & 0xFFL); buffer[1 + offsetInt] = (byte) ((val >> 48) & 0xFFL); buffer[2 + offsetInt] = (byte) ((val >> 40) & 0xFFL); buffer[3 + offsetInt] = (byte) ((val >> 32) & 0xFFL); buffer[4 + offsetInt] = (byte) ((val >> 24) & 0xFFL); buffer[5 + offsetInt] = (byte) ((val >> 16) & 0xFFL); buffer[6 + offsetInt] = (byte) ((val >> 8) & 0xFFL); buffer[7 + offsetInt] = (byte) (val & 0xFFL); offset.add(Type.LONG.getByteSize()); } /** * Serializes the given long value to an array of bytes. * @param val The long value to serialize. * @return The serialized long value. */ public static byte[] serializeLong(long val) { byte[] buffer = new byte[Type.LONG.getByteSize()]; buffer[0] = (byte) ((val >> 56) & 0xFFL); buffer[1] = (byte) ((val >> 48) & 0xFFL); buffer[2] = (byte) ((val >> 40) & 0xFFL); buffer[3] = (byte) ((val >> 32) & 0xFFL); buffer[4] = (byte) ((val >> 24) & 0xFFL); buffer[5] = (byte) ((val >> 16) & 0xFFL); buffer[6] = (byte) ((val >> 8) & 0xFFL); buffer[7] = (byte) (val & 0xFFL); return buffer; } /** * Deserializes the given long value. * @param buffer A serialized long value. * @return The deserialized long value. */ public static long deserializeLong(byte[] buffer) { Preconditions.checkArgument(buffer.length == Type.LONG.getByteSize()); return deserializeLong(buffer, new MutableInt(0)); } /** * This method deserializes a double from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized double. */ public static double deserializeDouble(byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); long val = (((long) buffer[0 + offsetInt]) & 0xFFL) << 56 | ((((long) buffer[1 + offsetInt]) & 0xFFL) << 48) | ((((long) buffer[2 + offsetInt]) & 0xFFL) << 40) | ((((long) buffer[3 + offsetInt]) & 0xFFL) << 32) | ((((long) buffer[4 + offsetInt]) & 0xFFL) << 24) | ((((long) buffer[5 + offsetInt]) & 0xFFL) << 16) | ((((long) buffer[6 + offsetInt]) & 0xFFL) << 8) | (((long) buffer[7 + offsetInt]) & 0xFFL); offset.add(Type.DOUBLE.getByteSize()); return Double.longBitsToDouble(val); } /** * This method serializes the given double to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param valD The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeDouble(double valD, byte[] buffer, MutableInt offset) { long val = Double.doubleToLongBits(valD); int offsetInt = offset.intValue(); buffer[0 + offsetInt] = (byte) ((val >> 56) & 0xFFL); buffer[1 + offsetInt] = (byte) ((val >> 48) & 0xFFL); buffer[2 + offsetInt] = (byte) ((val >> 40) & 0xFFL); buffer[3 + offsetInt] = (byte) ((val >> 32) & 0xFFL); buffer[4 + offsetInt] = (byte) ((val >> 24) & 0xFFL); buffer[5 + offsetInt] = (byte) ((val >> 16) & 0xFFL); buffer[6 + offsetInt] = (byte) ((val >> 8) & 0xFFL); buffer[7 + offsetInt] = (byte) (val & 0xFFL); offset.add(Type.DOUBLE.getByteSize()); } public static byte[] serializeDouble(double valD) { byte[] buffer = new byte[Type.DOUBLE.getByteSize()]; long val = Double.doubleToLongBits(valD); buffer[0] = (byte) ((val >> 56) & 0xFFL); buffer[1] = (byte) ((val >> 48) & 0xFFL); buffer[2] = (byte) ((val >> 40) & 0xFFL); buffer[3] = (byte) ((val >> 32) & 0xFFL); buffer[4] = (byte) ((val >> 24) & 0xFFL); buffer[5] = (byte) ((val >> 16) & 0xFFL); buffer[6] = (byte) ((val >> 8) & 0xFFL); buffer[7] = (byte) (val & 0xFFL); return buffer; } /** * This method deserializes an integer from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized integer. */ public static int deserializeInt(byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); int val = ((((int) buffer[0 + offsetInt]) & 0xFF) << 24) | ((((int) buffer[1 + offsetInt]) & 0xFF) << 16) | ((((int) buffer[2 + offsetInt]) & 0xFF) << 8) | (((int) buffer[3 + offsetInt]) & 0xFF); offset.add(Type.INTEGER.getByteSize()); return val; } /** * Deserializes the given serialized integer. * @param buffer The integer value to deserialized. * @return The deserialized integer value. */ public static int deserializeInt(byte[] buffer) { Preconditions.checkArgument(buffer.length == Type.INTEGER.getByteSize()); return deserializeInt(buffer, new MutableInt(0)); } /** * This method serializes the given integer to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeInt(int val, byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); buffer[0 + offsetInt] = (byte) ((val >> 24) & 0xFF); buffer[1 + offsetInt] = (byte) ((val >> 16) & 0xFF); buffer[2 + offsetInt] = (byte) ((val >> 8) & 0xFF); buffer[3 + offsetInt] = (byte) (val & 0xFF); offset.add(Type.INTEGER.getByteSize()); } /** * Serializes the given integer value. * @param val The value to serialize. * @return The serialized integer value. */ public static byte[] serializeInt(int val) { byte[] buffer = new byte[Type.INTEGER.getByteSize()]; buffer[0] = (byte) ((val >> 24) & 0xFF); buffer[1] = (byte) ((val >> 16) & 0xFF); buffer[2] = (byte) ((val >> 8) & 0xFF); buffer[3] = (byte) (val & 0xFF); return buffer; } /** * This method deserializes a float from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized float. */ public static float deserializeFloat(byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); int val = ((((int) buffer[0 + offsetInt]) & 0xFF) << 24) | ((((int) buffer[1 + offsetInt]) & 0xFF) << 16) | ((((int) buffer[2 + offsetInt]) & 0xFF) << 8) | (((int) buffer[3 + offsetInt]) & 0xFF); offset.add(Type.FLOAT.getByteSize()); return Float.intBitsToFloat(val); } /** * This method serializes the given float to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param valf The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeFloat(float valf, byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); int val = Float.floatToIntBits(valf); buffer[0 + offsetInt] = (byte) ((val >> 24) & 0xFF); buffer[1 + offsetInt] = (byte) ((val >> 16) & 0xFF); buffer[2 + offsetInt] = (byte) ((val >> 8) & 0xFF); buffer[3 + offsetInt] = (byte) (val & 0xFF); offset.add(Type.FLOAT.getByteSize()); } public static byte[] serializeFloat(float valf) { byte[] buffer = new byte[Type.FLOAT.getByteSize()]; int val = Float.floatToIntBits(valf); buffer[0] = (byte) ((val >> 24) & 0xFF); buffer[1] = (byte) ((val >> 16) & 0xFF); buffer[2] = (byte) ((val >> 8) & 0xFF); buffer[3] = (byte) (val & 0xFF); return buffer; } /** * This method deserializes a short from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized short. */ public static short deserializeShort(byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); short val = (short) (((((int) buffer[0 + offsetInt]) & 0xFF) << 8) | (((int) buffer[1 + offsetInt]) & 0xFF)); offset.add(Type.SHORT.getByteSize()); return val; } /** * This method serializes the given short to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeShort(short val, byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); buffer[0 + offsetInt] = (byte) ((val >> 8) & 0xFF); buffer[1 + offsetInt] = (byte) (val & 0xFF); offset.add(Type.SHORT.getByteSize()); } public static byte[] serializeShort(short val) { byte[] buffer = new byte[Type.SHORT.getByteSize()]; buffer[0] = (byte) ((val >> 8) & 0xFF); buffer[1] = (byte) (val & 0xFF); return buffer; } /** * This method deserializes a byte from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized byte. */ public static byte deserializeByte(byte[] buffer, MutableInt offset) { byte val = buffer[offset.intValue()]; offset.add(Type.BYTE.getByteSize()); return val; } /** * This method serializes the given byte to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeByte(byte val, byte[] buffer, MutableInt offset) { buffer[offset.intValue()] = val; offset.add(Type.BYTE.getByteSize()); } public static byte[] serializeByte(byte val) { return new byte[] { val }; } /** * This method deserializes a boolean from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized boolean. */ public static boolean deserializeBoolean(byte[] buffer, MutableInt offset) { boolean val = buffer[offset.intValue()] != 0; offset.add(Type.BOOLEAN.getByteSize()); return val; } /** * This method serializes the given boolean to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeBoolean(boolean val, byte[] buffer, MutableInt offset) { buffer[offset.intValue()] = (byte) (val ? 1 : 0); offset.add(Type.BOOLEAN.getByteSize()); } public static byte[] serializeBoolean(boolean val) { return new byte[] { (byte) (val ? 1 : 0) }; } /** * This method deserializes a character from the given byte array from the given offset, * and increments the offset appropriately. * @param buffer The byte buffer to deserialize from. * @param offset The offset to deserialize from. * @return The deserialized character. */ public static char deserializeChar(byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); char val = (char) (((((int) buffer[0 + offsetInt]) & 0xFF) << 8) | (((int) buffer[1 + offsetInt]) & 0xFF)); offset.add(Type.CHAR.getByteSize()); return val; } /** * This method serializes the given character to the given byte buffer to the given offset, * the method also increments the offset appropriately. * @param val The value to serialize. * @param buffer The byte buffer to serialize to. * @param offset The offset in the buffer to serialize to and also to increment appropriately. */ public static void serializeChar(char val, byte[] buffer, MutableInt offset) { int offsetInt = offset.intValue(); buffer[0 + offsetInt] = (byte) ((val >> 8) & 0xFF); buffer[1 + offsetInt] = (byte) (val & 0xFF); offset.add(Type.CHAR.getByteSize()); } public static byte[] serializeChar(char val) { byte[] buffer = new byte[Type.CHAR.getByteSize()]; buffer[0] = (byte) ((val >> 8) & 0xFF); buffer[1] = (byte) (val & 0xFF); return buffer; } /** * Utility method for creating getters. This method is useful for creating a {@link GPOGetters} object * which can be used to copy POJOs into GPOMutable objects. * @param fields The fields to create getters for. The order of the fields in this list will be the same order * that the getters will be returned in. * @param valueToExpression A map from field names to the corresponding java expression to be used for getting * the fields. * @param clazz The Class of the POJO to extract values from. * @param getterClazz The class of the getter object to create. * @param getterMethodClazz The class of the getter method. * @return An array of boolean getters for given fields. */ @SuppressWarnings("unchecked") public static <T> T[] createGetters(List<String> fields, Map<String, String> valueToExpression, Class<?> clazz, Class<?> getterClazz, Class<?> getterMethodClazz) { @SuppressWarnings("unchecked") T[] getters = (T[]) Array.newInstance(getterMethodClazz, fields.size()); for (int getterIndex = 0; getterIndex < fields.size(); getterIndex++) { String field = fields.get(getterIndex); getters[getterIndex] = (T) PojoUtils.constructGetter(clazz, valueToExpression.get(field), getterClazz); } return getters; } /** * Utility method for creating getters. This method is useful for creating a {@link GPOGetters} object * which can be used to copy POJOs into GPOMutable objects. * @param fields The fields to create getters for. The order of the fields in this list will be the same order * that the getters will be returned in. * @param valueToExpression A map from field names to the corresponding java expression to be used for getting * the fields. * @param clazz The Class of the POJO to extract values from. * @return An array of boolean getters for given fields. */ public static Getter<Object, String>[] createGettersString(List<String> fields, Map<String, String> valueToExpression, Class<?> clazz) { @SuppressWarnings({ "unchecked", "rawtypes" }) Getter<Object, String>[] getters = new Getter[fields.size()]; for (int getterIndex = 0; getterIndex < fields.size(); getterIndex++) { String field = fields.get(getterIndex); getters[getterIndex] = PojoUtils.createGetter(clazz, valueToExpression.get(field), String.class); } return getters; } /** * Utility method for creating getters. This method is useful for creating a {@link GPOGetters} object * which can be used to copy POJOs into GPOMutable objects. * @param fields The fields to create getters for. The order of the fields in this list will be the same order * that the getters will be returned in. * @param valueToExpression A map from field names to the corresponding java expression to be used for getting * the fields. * @param clazz The Class of the POJO to extract values from. * @return An array of boolean getters for given fields. */ public static Getter<Object, Object>[] createGettersObject(List<String> fields, Map<String, String> valueToExpression, Class<?> clazz) { @SuppressWarnings({ "unchecked", "rawtypes" }) Getter<Object, Object>[] getters = new Getter[fields.size()]; for (int getterIndex = 0; getterIndex < fields.size(); getterIndex++) { String field = fields.get(getterIndex); getters[getterIndex] = PojoUtils.createGetter(clazz, valueToExpression.get(field), Object.class); } return getters; } /** * This is a utility method which builds a {@link GPOGetters} object corresponding to the given {@link FieldsDescriptor}. * This utility method is helpful for converting POJOs into GPOMutable objects. * @param fieldToGetter A map whose keys are field names and whose values correspond to java getter expressions. Field names * in this map should be the same as field names in the provided {@link FieldsDescriptor} object. * @param fieldsDescriptor A {@link FieldsDescriptor} object which describes the type name and order of fields. * @param clazz The Class of the POJO that the getters will be applied to. * @return The {@link GPOGetters} object which can be used to convert POJOs into {@link GPOMutable} objects initialized * with the same {@link FieldsDescriptor} object. */ public static GPOGetters buildGPOGetters(Map<String, String> fieldToGetter, FieldsDescriptor fieldsDescriptor, Class<?> clazz) { GPOGetters gpoGetters = new GPOGetters(); Map<Type, List<String>> typeToFields = fieldsDescriptor.getTypeToFields(); for (Map.Entry<Type, List<String>> entry : typeToFields.entrySet()) { Type inputType = entry.getKey(); GPOType gpoType = GPOType.GPO_TYPE_ARRAY[inputType.ordinal()]; List<String> fields = entry.getValue(); gpoType.buildGPOGetters(gpoGetters, fields, fieldToGetter, clazz); } return gpoGetters; } /** * This is a utility method for converting a POJO to a {@link GPOMutable} object. This method assumes that the provided * GPOMutable is initialized with the correct {@link FieldsDescriptor}, and that the given {@link GPOGetters} object has getters * specified in the same order as fields in the {@link GPOMutable} object. * @param mutable The {@link GPOMutable} object to copy POJO values into. It is assumed this object is initialized with * the correct {@link FieldsDescriptor}. * @param getters The getters to use when retrieving values from the provided POJO. It is assumed that the getters are * specified in the same order as their corresponding fields in the {@link GPOMutable} object. * @param object The POJO to extract values from. */ public static void copyPOJOToGPO(GPOMutable mutable, GPOGetters getters, Object object) { { boolean[] tempBools = mutable.getFieldsBoolean(); GetterBoolean<Object>[] tempGetterBools = getters.gettersBoolean; if (tempBools != null) { for (int index = 0; index < tempBools.length; index++) { tempBools[index] = tempGetterBools[index].get(object); } } } { byte[] tempBytes = mutable.getFieldsByte(); GetterByte<Object>[] tempGetterByte = getters.gettersByte; if (tempBytes != null) { for (int index = 0; index < tempBytes.length; index++) { tempBytes[index] = tempGetterByte[index].get(object); } } } { char[] tempChar = mutable.getFieldsCharacter(); GetterChar<Object>[] tempGetterChar = getters.gettersChar; if (tempChar != null) { for (int index = 0; index < tempChar.length; index++) { tempChar[index] = tempGetterChar[index].get(object); } } } { double[] tempDouble = mutable.getFieldsDouble(); GetterDouble<Object>[] tempGetterDouble = getters.gettersDouble; if (tempDouble != null) { for (int index = 0; index < tempDouble.length; index++) { tempDouble[index] = tempGetterDouble[index].get(object); } } } { float[] tempFloat = mutable.getFieldsFloat(); GetterFloat<Object>[] tempGetterFloat = getters.gettersFloat; if (tempFloat != null) { for (int index = 0; index < tempFloat.length; index++) { tempFloat[index] = tempGetterFloat[index].get(object); } } } { int[] tempInt = mutable.getFieldsInteger(); GetterInt<Object>[] tempGetterInt = getters.gettersInteger; if (tempInt != null) { for (int index = 0; index < tempInt.length; index++) { tempInt[index] = tempGetterInt[index].get(object); } } } { long[] tempLong = mutable.getFieldsLong(); GetterLong<Object>[] tempGetterLong = getters.gettersLong; if (tempLong != null) { for (int index = 0; index < tempLong.length; index++) { tempLong[index] = tempGetterLong[index].get(object); } } } { short[] tempShort = mutable.getFieldsShort(); GetterShort<Object>[] tempGetterShort = getters.gettersShort; if (tempShort != null) { for (int index = 0; index < tempShort.length; index++) { tempShort[index] = tempGetterShort[index].get(object); } } } { String[] tempString = mutable.getFieldsString(); Getter<Object, String>[] tempGetterString = getters.gettersString; if (tempString != null) { for (int index = 0; index < tempString.length; index++) { tempString[index] = tempGetterString[index].get(object); } } } } public static void indirectCopy(GPOMutable dest, GPOMutable src, IndexSubset indexSubset) { { String[] destString = dest.getFieldsString(); String[] srcString = src.getFieldsString(); int[] srcIndex = indexSubset.fieldsStringIndexSubset; if (destString != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destString[index] = srcString[srcIndex[index]]; } } } { boolean[] destBoolean = dest.getFieldsBoolean(); boolean[] srcBoolean = src.getFieldsBoolean(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (destBoolean != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destBoolean[index] = srcBoolean[srcIndex[index]]; } } } { char[] destChar = dest.getFieldsCharacter(); char[] srcChar = src.getFieldsCharacter(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (destChar != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destChar[index] = srcChar[srcIndex[index]]; } } } { byte[] destByte = dest.getFieldsByte(); byte[] srcByte = src.getFieldsByte(); int[] srcIndex = indexSubset.fieldsByteIndexSubset; if (destByte != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destByte[index] = srcByte[srcIndex[index]]; } } } { short[] destShort = dest.getFieldsShort(); short[] srcShort = src.getFieldsShort(); int[] srcIndex = indexSubset.fieldsShortIndexSubset; if (destShort != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destShort[index] = srcShort[srcIndex[index]]; } } } { int[] destInteger = dest.getFieldsInteger(); int[] srcInteger = src.getFieldsInteger(); int[] srcIndex = indexSubset.fieldsIntegerIndexSubset; if (destInteger != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destInteger[index] = srcInteger[srcIndex[index]]; } } } { long[] destLong = dest.getFieldsLong(); long[] srcLong = src.getFieldsLong(); int[] srcIndex = indexSubset.fieldsLongIndexSubset; if (destLong != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destLong[index] = srcLong[srcIndex[index]]; } } } { float[] destFloat = dest.getFieldsFloat(); float[] srcFloat = src.getFieldsFloat(); int[] srcIndex = indexSubset.fieldsFloatIndexSubset; if (destFloat != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destFloat[index] = srcFloat[srcIndex[index]]; } } } { double[] destDouble = dest.getFieldsDouble(); double[] srcDouble = src.getFieldsDouble(); int[] srcIndex = indexSubset.fieldsDoubleIndexSubset; if (destDouble != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destDouble[index] = srcDouble[srcIndex[index]]; } } } { Object[] destObject = dest.getFieldsObject(); Object[] srcObject = src.getFieldsObject(); int[] srcIndex = indexSubset.fieldsObjectIndexSubset; if (destObject != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } destObject[index] = srcObject[srcIndex[index]]; } } } } public static int hashcode(GPOMutable gpo) { int hashCode = 0; { String[] stringArray = gpo.getFieldsString(); if (stringArray != null) { for (int index = 0; index < stringArray.length; index++) { hashCode ^= stringArray[index].hashCode(); } } } { boolean[] booleanArray = gpo.getFieldsBoolean(); if (booleanArray != null) { for (int index = 0; index < booleanArray.length; index++) { hashCode ^= booleanArray[index] ? 1 : 0; } } } { char[] charArray = gpo.getFieldsCharacter(); if (charArray != null) { for (int index = 0; index < charArray.length; index++) { hashCode ^= Character.getNumericValue(charArray[index]); } } } { byte[] byteArray = gpo.getFieldsByte(); if (byteArray != null) { for (int index = 0; index < byteArray.length; index++) { hashCode ^= byteArray[index]; } } } { short[] shortArray = gpo.getFieldsShort(); if (shortArray != null) { for (int index = 0; index < shortArray.length; index++) { hashCode ^= shortArray[index]; } } } { int[] integerArray = gpo.getFieldsInteger(); if (integerArray != null) { for (int index = 0; index < integerArray.length; index++) { hashCode ^= integerArray[index]; } } } { long[] longArray = gpo.getFieldsLong(); if (longArray != null) { for (int index = 0; index < longArray.length; index++) { hashCode ^= longArray[index]; } } } { float[] floatArray = gpo.getFieldsFloat(); if (floatArray != null) { for (int index = 0; index < floatArray.length; index++) { hashCode ^= Float.floatToIntBits(floatArray[index]); } } } { double[] doubleArray = gpo.getFieldsDouble(); if (doubleArray != null) { for (int index = 0; index < doubleArray.length; index++) { hashCode ^= Double.doubleToLongBits(doubleArray[index]); } } } { Object[] objectArray = gpo.getFieldsObject(); if (objectArray != null) { for (int index = 0; index < objectArray.length; index++) { hashCode ^= objectArray[index].hashCode(); } } } return hashCode; } /** * This function computes the hashcode of a {@link GPOMutable} based on a specified subset of its data. * <br/> * <br/> * <b>Note:</b> In some cases a {@link GPOMutable} object contains a field which is bucketed. In the case of * bucketed fields, you may want to preserve the original value of the field, but only use the bucketed value * of the field for computing a hashcode. In order to do this you can store the original value of {@link GPOMutable}'s * field before calling this function, and replace it with the bucketed value. Then after the hashcode is computed, the * original value of the field can be restored. * * @param gpo The {@link GPOMutable} to compute a hashcode for. * @param indexSubset The subset of the {@link GPOMutable} used to compute the hashcode. * @return The hashcode for the given {@link GPOMutable} computed from the specified subset of its data. */ public static int indirectHashcode(GPOMutable gpo, IndexSubset indexSubset) { int hashCode = 7; final int hashMultiplier = 23; { String[] stringArray = gpo.getFieldsString(); int[] srcIndex = indexSubset.fieldsStringIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + stringArray[srcIndex[index]].hashCode(); } } } { boolean[] booleanArray = gpo.getFieldsBoolean(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + (booleanArray[srcIndex[index]] ? 1 : 0); } } } { char[] charArray = gpo.getFieldsCharacter(); int[] srcIndex = indexSubset.fieldsCharacterIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + Character.getNumericValue(charArray[srcIndex[index]]); } } } { byte[] byteArray = gpo.getFieldsByte(); int[] srcIndex = indexSubset.fieldsByteIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + byteArray[srcIndex[index]]; } } } { short[] shortArray = gpo.getFieldsShort(); int[] srcIndex = indexSubset.fieldsShortIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + shortArray[srcIndex[index]]; } } } { int[] integerArray = gpo.getFieldsInteger(); int[] srcIndex = indexSubset.fieldsIntegerIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + integerArray[srcIndex[index]]; } } } { long[] longArray = gpo.getFieldsLong(); int[] srcIndex = indexSubset.fieldsLongIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } long element = longArray[srcIndex[index]]; int elementHash = (int) (element ^ (element >>> 32)); hashCode = hashMultiplier * hashCode + elementHash; } } } { float[] floatArray = gpo.getFieldsFloat(); int[] srcIndex = indexSubset.fieldsFloatIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + Float.floatToIntBits(floatArray[srcIndex[index]]); } } } { double[] doubleArray = gpo.getFieldsDouble(); int[] srcIndex = indexSubset.fieldsDoubleIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } long element = Double.doubleToLongBits(doubleArray[srcIndex[index]]); int elementHash = (int) (element ^ (element >>> 32)); hashCode = hashMultiplier * hashCode + elementHash; } } } { Object[] objectArray = gpo.getFieldsObject(); int[] srcIndex = indexSubset.fieldsObjectIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } hashCode = hashMultiplier * hashCode + objectArray[srcIndex[index]].hashCode(); } } } return hashCode; } public static boolean equals(GPOMutable dest, GPOMutable src) { { String[] destString = dest.getFieldsString(); String[] srcString = src.getFieldsString(); if (destString != null) { for (int index = 0; index < srcString.length; index++) { if (!destString[index].equals(srcString[index])) { return false; } } } } { boolean[] destBoolean = dest.getFieldsBoolean(); boolean[] srcBoolean = src.getFieldsBoolean(); if (destBoolean != null) { for (int index = 0; index < srcBoolean.length; index++) { if (destBoolean[index] != srcBoolean[index]) { return false; } } } } { char[] destChar = dest.getFieldsCharacter(); char[] srcChar = src.getFieldsCharacter(); if (destChar != null) { for (int index = 0; index < srcChar.length; index++) { if (destChar[index] != srcChar[index]) { return false; } } } } { byte[] destByte = dest.getFieldsByte(); byte[] srcByte = src.getFieldsByte(); if (destByte != null) { for (int index = 0; index < srcByte.length; index++) { if (destByte[index] != srcByte[index]) { return false; } } } } { short[] destShort = dest.getFieldsShort(); short[] srcShort = src.getFieldsShort(); if (destShort != null) { for (int index = 0; index < srcShort.length; index++) { if (destShort[index] != srcShort[index]) { return false; } } } } { int[] destInteger = dest.getFieldsInteger(); int[] srcInteger = src.getFieldsInteger(); if (destInteger != null) { for (int index = 0; index < srcInteger.length; index++) { if (destInteger[index] != srcInteger[index]) { return false; } } } } { long[] destLong = dest.getFieldsLong(); long[] srcLong = src.getFieldsLong(); if (destLong != null) { for (int index = 0; index < srcLong.length; index++) { if (destLong[index] != srcLong[index]) { return false; } } } } { float[] destFloat = dest.getFieldsFloat(); float[] srcFloat = src.getFieldsFloat(); if (destFloat != null) { for (int index = 0; index < srcFloat.length; index++) { if (destFloat[index] != srcFloat[index]) { return false; } } } } { double[] destDouble = dest.getFieldsDouble(); double[] srcDouble = src.getFieldsDouble(); if (destDouble != null) { for (int index = 0; index < srcDouble.length; index++) { if (destDouble[index] != srcDouble[index]) { return false; } } } } { Object[] destObject = dest.getFieldsObject(); Object[] srcObject = src.getFieldsObject(); if (destObject != null) { for (int index = 0; index < srcObject.length; index++) { if (!destObject[index].equals(srcObject[index])) { return false; } } } } return true; } public static boolean subsetEquals(GPOMutable dest, GPOMutable src, IndexSubset indexSubset) { { String[] destString = dest.getFieldsString(); String[] srcString = src.getFieldsString(); int[] srcIndex = indexSubset.fieldsStringIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (!destString[srcIndex[index]].equals(srcString[srcIndex[index]])) { return false; } } } } { boolean[] destBoolean = dest.getFieldsBoolean(); boolean[] srcBoolean = src.getFieldsBoolean(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destBoolean[srcIndex[index]] != srcBoolean[srcIndex[index]]) { return false; } } } } { char[] destChar = dest.getFieldsCharacter(); char[] srcChar = src.getFieldsCharacter(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destChar[srcIndex[index]] != srcChar[srcIndex[index]]) { return false; } } } } { byte[] destByte = dest.getFieldsByte(); byte[] srcByte = src.getFieldsByte(); int[] srcIndex = indexSubset.fieldsByteIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destByte[srcIndex[index]] != srcByte[srcIndex[index]]) { return false; } } } } { short[] destShort = dest.getFieldsShort(); short[] srcShort = src.getFieldsShort(); int[] srcIndex = indexSubset.fieldsShortIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destShort[srcIndex[index]] != srcShort[srcIndex[index]]) { return false; } } } } { int[] destInteger = dest.getFieldsInteger(); int[] srcInteger = src.getFieldsInteger(); int[] srcIndex = indexSubset.fieldsIntegerIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destInteger[srcIndex[index]] != srcInteger[srcIndex[index]]) { return false; } } } } { long[] destLong = dest.getFieldsLong(); long[] srcLong = src.getFieldsLong(); int[] srcIndex = indexSubset.fieldsLongIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destLong[srcIndex[index]] != srcLong[srcIndex[index]]) { return false; } } } } { float[] destFloat = dest.getFieldsFloat(); float[] srcFloat = src.getFieldsFloat(); int[] srcIndex = indexSubset.fieldsFloatIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destFloat[srcIndex[index]] != srcFloat[srcIndex[index]]) { return false; } } } } { double[] destDouble = dest.getFieldsDouble(); double[] srcDouble = src.getFieldsDouble(); int[] srcIndex = indexSubset.fieldsDoubleIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destDouble[srcIndex[index]] != srcDouble[srcIndex[index]]) { return false; } } } } { Object[] destObject = dest.getFieldsObject(); Object[] srcObject = src.getFieldsObject(); int[] srcIndex = indexSubset.fieldsObjectIndexSubset; if (srcIndex != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (!destObject[srcIndex[index]].equals(srcObject[srcIndex[index]])) { return false; } } } } return true; } public static boolean indirectEquals(GPOMutable dest, GPOMutable src, IndexSubset indexSubset) { { String[] destString = dest.getFieldsString(); String[] srcString = src.getFieldsString(); int[] srcIndex = indexSubset.fieldsStringIndexSubset; if (destString != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (!destString[index].equals(srcString[srcIndex[index]])) { return false; } } } } { boolean[] destBoolean = dest.getFieldsBoolean(); boolean[] srcBoolean = src.getFieldsBoolean(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (destBoolean != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destBoolean[index] != srcBoolean[srcIndex[index]]) { return false; } } } } { char[] destChar = dest.getFieldsCharacter(); char[] srcChar = src.getFieldsCharacter(); int[] srcIndex = indexSubset.fieldsBooleanIndexSubset; if (destChar != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destChar[index] != srcChar[srcIndex[index]]) { return false; } } } } { byte[] destByte = dest.getFieldsByte(); byte[] srcByte = src.getFieldsByte(); int[] srcIndex = indexSubset.fieldsByteIndexSubset; if (destByte != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destByte[index] != srcByte[srcIndex[index]]) { return false; } } } } { short[] destShort = dest.getFieldsShort(); short[] srcShort = src.getFieldsShort(); int[] srcIndex = indexSubset.fieldsShortIndexSubset; if (destShort != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destShort[index] != srcShort[srcIndex[index]]) { return false; } } } } { int[] destInteger = dest.getFieldsInteger(); int[] srcInteger = src.getFieldsInteger(); int[] srcIndex = indexSubset.fieldsIntegerIndexSubset; if (destInteger != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destInteger[index] != srcInteger[srcIndex[index]]) { return false; } } } } { long[] destLong = dest.getFieldsLong(); long[] srcLong = src.getFieldsLong(); int[] srcIndex = indexSubset.fieldsLongIndexSubset; if (destLong != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destLong[index] != srcLong[srcIndex[index]]) { return false; } } } } { float[] destFloat = dest.getFieldsFloat(); float[] srcFloat = src.getFieldsFloat(); int[] srcIndex = indexSubset.fieldsFloatIndexSubset; if (destFloat != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destFloat[index] != srcFloat[srcIndex[index]]) { return false; } } } } { double[] destDouble = dest.getFieldsDouble(); double[] srcDouble = src.getFieldsDouble(); int[] srcIndex = indexSubset.fieldsDoubleIndexSubset; if (destDouble != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (destDouble[index] != srcDouble[srcIndex[index]]) { return false; } } } } { Object[] destObject = dest.getFieldsObject(); Object[] srcObject = src.getFieldsObject(); int[] srcIndex = indexSubset.fieldsObjectIndexSubset; if (destObject != null) { for (int index = 0; index < srcIndex.length; index++) { if (srcIndex[index] == -1) { continue; } if (!destObject[index].equals(srcObject[srcIndex[index]])) { return false; } } } } return true; } public static void zeroFillNumeric(GPOMutable value) { if (value.getFieldsByte() != null) { Arrays.fill(value.getFieldsByte(), (byte) 0); } if (value.getFieldsShort() != null) { Arrays.fill(value.getFieldsShort(), (short) 0); } if (value.getFieldsInteger() != null) { Arrays.fill(value.getFieldsInteger(), 0); } if (value.getFieldsLong() != null) { Arrays.fill(value.getFieldsLong(), 0L); } if (value.getFieldsFloat() != null) { Arrays.fill(value.getFieldsFloat(), 0.0f); } if (value.getFieldsDouble() != null) { Arrays.fill(value.getFieldsDouble(), 0.0); } } public static IndexSubset computeSubIndices(FieldsDescriptor child, FieldsDescriptor parent) { IndexSubset indexSubset = new IndexSubset(); for (Map.Entry<Type, List<String>> entry : child.getTypeToFields().entrySet()) { Type type = entry.getKey(); List<String> childFields = entry.getValue(); List<String> parentFields = parent.getTypeToFields().get(type); int size = child.getTypeToSize().get(type); int[] indices; if (child.getTypeToFields().get(type) != null && child.getCompressedTypes().contains(type)) { indices = new int[1]; } else { indices = new int[size]; for (int index = 0; index < size; index++) { if (parentFields == null) { indices[index] = -1; } else { indices[index] = parentFields.indexOf(childFields.get(index)); } } } switch (type) { case BOOLEAN: { indexSubset.fieldsBooleanIndexSubset = indices; break; } case CHAR: { indexSubset.fieldsCharacterIndexSubset = indices; break; } case STRING: { indexSubset.fieldsStringIndexSubset = indices; break; } case BYTE: { indexSubset.fieldsByteIndexSubset = indices; break; } case SHORT: { indexSubset.fieldsShortIndexSubset = indices; break; } case INTEGER: { indexSubset.fieldsIntegerIndexSubset = indices; break; } case LONG: { indexSubset.fieldsLongIndexSubset = indices; break; } case FLOAT: { indexSubset.fieldsFloatIndexSubset = indices; break; } case DOUBLE: { indexSubset.fieldsDoubleIndexSubset = indices; break; } default: { throw new UnsupportedOperationException("Type " + type); } } } return indexSubset; } /** * This object is used to define the subset of data contained in a {@link GPOMutable} * object that we are interested in. */ public static class IndexSubset implements Serializable { private static final long serialVersionUID = 201506251015L; /** * Index of boolean fields of interest. Null if there are no boolean fields of interest. */ public int[] fieldsBooleanIndexSubset; /** * Index of character fields of interest. Null if there are no character fields of interest. */ public int[] fieldsCharacterIndexSubset; /** * Index of byte fields of interest. Null if there are no byte fields of interest. */ public int[] fieldsByteIndexSubset; /** * Index of short fields of interest. Null if there are no short fields of interest. */ public int[] fieldsShortIndexSubset; /** * Index of integer fields of interest. Null if there are no integer fields of interest. */ public int[] fieldsIntegerIndexSubset; /** * Index of long fields of interest. Null if there are no long fields of interest. */ public int[] fieldsLongIndexSubset; /** * Index of float fields of interest. Null if there are no float fields of interest. */ public int[] fieldsFloatIndexSubset; /** * Index of double fields of interest. Null if there are no double fields of interest. */ public int[] fieldsDoubleIndexSubset; /** * Index of String fields of interest. Null if there are no String fields of interest. */ public int[] fieldsStringIndexSubset; /** * Index of Object fields of interest. Null if there are no Object fields of interest. */ public int[] fieldsObjectIndexSubset; public IndexSubset() { //Do nothing } @Override public String toString() { return "IndexSubset{" + "fieldsBooleanIndexSubset=" + fieldsBooleanIndexSubset + ", fieldsCharacterIndexSubset=" + fieldsCharacterIndexSubset + ", fieldsByteIndexSubset=" + fieldsByteIndexSubset + ", fieldsShortIndexSubset=" + fieldsShortIndexSubset + ", fieldsIntegerIndexSubset=" + fieldsIntegerIndexSubset + ", fieldsLongIndexSubset=" + fieldsLongIndexSubset + ", fieldsFloatIndexSubset=" + fieldsFloatIndexSubset + ", fieldsDoubleIndexSubset=" + fieldsDoubleIndexSubset + ", fieldsStringIndexSubset=" + fieldsStringIndexSubset + '}'; } } public static Map<String, Object> getDestringedData(FieldsDescriptor fd, Map<String, String> stringMap) { Map<String, Object> fieldToData = Maps.newHashMap(); Map<String, Type> fieldToType = fd.getFieldToType(); for (Map.Entry<String, String> entry : stringMap.entrySet()) { Object objValue; String valueString = entry.getValue(); Type valueType = fieldToType.get(entry.getKey()); switch (valueType) { case BOOLEAN: { objValue = Boolean.valueOf(valueString); break; } case BYTE: { objValue = Byte.valueOf(valueString); break; } case SHORT: { objValue = Short.valueOf(valueString); break; } case INTEGER: { objValue = Integer.valueOf(valueString); break; } case LONG: { objValue = Long.valueOf(valueString); break; } case FLOAT: { objValue = Float.valueOf(valueString); break; } case DOUBLE: { objValue = Double.valueOf(valueString); break; } case STRING: { objValue = valueString; break; } case OBJECT: throw new UnsupportedOperationException("The given type " + entry.getValue() + " is unsupported."); default: throw new UnsupportedOperationException("The given type " + entry.getValue() + " is unsupported."); } fieldToData.put(entry.getKey(), objValue); } return fieldToData; } public static Map<String, Object> convertToMapIntersection(GPOMutable gpo, Fields fields) { Map<String, Object> values = Maps.newHashMap(); for (String field : fields.getFields()) { if (!gpo.getFieldDescriptor().getFields().getFields().contains(field)) { continue; } Object valueObj = gpo.getField(field); values.put(field, valueObj); } return values; } /** * Determines if the given value is within the range of the specified type. * @param type The type to determine the range of. Valid types can be byte or short. * @param val The value to check the range of. * @return True if the given int value is within the range of the specified type, false otherwise. */ public static boolean insideRange(Type type, int val) { switch (type) { case BYTE: { return !(val < (int) Byte.MIN_VALUE || val > (int) Byte.MAX_VALUE); } case SHORT: { return !(val < (int) Short.MIN_VALUE || val > (int) Short.MAX_VALUE); } default: throw new UnsupportedOperationException("This operation is not supported for the type " + type); } } /** * Returns true if the given type is of type byte, short, or integer. * @param type The type to check. * @return True if the given type is of type byte, short or integer. */ public static boolean numericTypeIntOrSmaller(Type type) { return type == Type.BYTE || type == Type.SHORT || type == Type.INTEGER; } }