Java tutorial
/****************************************************************************** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is: Jsoda * The Initial Developer of the Original Code is: William Wong (williamw520@gmail.com) * Portions created by William Wong are Copyright (C) 2012 William Wong, All Rights Reserved. * ******************************************************************************/ package wwutil.jsoda; import java.io.*; import java.util.*; import java.math.*; import java.lang.reflect.*; import org.apache.commons.beanutils.ConvertUtils; import org.codehaus.jackson.map.ObjectMapper; import com.amazonaws.services.simpledb.util.SimpleDBUtils; import wwutil.sys.TlsMap; class DataUtil { private static TlsMap.Factory<ObjectMapper> sTlsObjectMapper = new TlsMap.Factory<ObjectMapper>() { public ObjectMapper create(Object key) { return new ObjectMapper(); } }; static String getFieldValueStr(Object dataObj, Field field) throws Exception { Object value = field.get(dataObj); return encodeValueToAttrStr(value, field.getType()); } static void setFieldValueStr(Object dataObj, Field field, String attrStr) throws Exception { Object value = decodeAttrStrToValue(attrStr, field.getType()); field.set(dataObj, value); } /** Caller should handle custom valueType first before calling this. * E.g. DynamoDB's Set<String> and Set<long> fields are encoded as Multi-Value AttributeValue. */ @SuppressWarnings("unchecked") static String encodeValueToAttrStr(Object value, Class valueType) { if (value == null) return null; // Caller needs to handle null correctly, e.g. skip storing AttributeValue. if (valueType == String.class) return value.toString(); // NOTE: Don't change encoding and padding once data have been created. Different encoding will mess up sorting. // Stringify basic type and encode them for sorting. if (valueType == Byte.class || valueType == byte.class) { Byte casted = (Byte) ConvertUtils.convert(value, Byte.class); return SimpleDBUtils.encodeZeroPadding(casted.intValue(), 3); // 0-Padded for sorting } else if (valueType == Short.class || valueType == short.class) { Short casted = (Short) ConvertUtils.convert(value, Short.class); return SimpleDBUtils.encodeZeroPadding(casted.intValue(), 5); // 0-Padded for sorting } else if (valueType == Integer.class || valueType == int.class) { Integer casted = (Integer) ConvertUtils.convert(value, Integer.class); return SimpleDBUtils.encodeZeroPadding(casted.intValue(), 10); // 0-Padded for sorting } else if (valueType == Long.class || valueType == long.class) { Long casted = (Long) ConvertUtils.convert(value, Long.class); return SimpleDBUtils.encodeZeroPadding(casted.longValue(), 19); // 0-Padded for sorting } else if (valueType == Float.class || valueType == float.class) { Float casted = (Float) ConvertUtils.convert(value, Float.class); return SimpleDBUtils.encodeZeroPadding(casted.floatValue(), 16); // 0-Padded for sorting } else if (valueType == Double.class || valueType == double.class) { // SimpleDBUtils has no padding for double. Just convert it to String. return value.toString(); } else if (valueType == Boolean.class || valueType == boolean.class) { return value.toString(); } else if (valueType == Character.class || valueType == char.class) { return value.toString(); } else if (valueType == Date.class) { return SimpleDBUtils.encodeDate((Date) value); } else if (valueType.isEnum()) { return ((Enum) value).name(); } // JSONify the rest. return toJson(value); } /** Caller should handle custom valueType first before calling this. */ @SuppressWarnings("unchecked") static Object decodeAttrStrToValue(String attrStr, Class valueType) throws Exception { // Set null if input is null. if (attrStr == null) return null; if (valueType == String.class) return attrStr; // Return string type as it is. // non-String field having "" is treated as null. if (attrStr.equals("")) return null; if (valueType == Byte.class || valueType == byte.class) { return new Byte((byte) SimpleDBUtils.decodeZeroPaddingInt(attrStr)); } else if (valueType == Short.class || valueType == short.class) { return new Short((short) SimpleDBUtils.decodeZeroPaddingInt(attrStr)); } else if (valueType == Integer.class || valueType == int.class) { return new Integer(SimpleDBUtils.decodeZeroPaddingInt(attrStr)); } else if (valueType == Long.class || valueType == long.class) { return new Long(SimpleDBUtils.decodeZeroPaddingLong(attrStr)); } else if (valueType == Float.class || valueType == float.class) { return new Float(SimpleDBUtils.decodeZeroPaddingFloat(attrStr)); } else if (valueType == Double.class || valueType == double.class) { return new Double(attrStr); } else if (valueType == Boolean.class || valueType == boolean.class) { return new Boolean(attrStr); } else if (valueType == Character.class || valueType == char.class) { return attrStr.charAt(0); } else if (valueType == Date.class) { return SimpleDBUtils.decodeDate(attrStr); } else if (valueType.isEnum()) { return Enum.valueOf(valueType, attrStr); } // de-JSONify the rest. return fromJson(attrStr, valueType); } /** Check whether a value/valueType can be encoded, so that it can be used as condition value in query. */ static boolean canBeEncoded(Object value, Class valueType) { if (value == null) return true; if (valueType == String.class) return true; // Stringify basic type and encode them for sorting. if (valueType == Byte.class || valueType == byte.class) { return true; } else if (valueType == Short.class || valueType == short.class) { return true; } else if (valueType == Integer.class || valueType == int.class) { return true; } else if (valueType == Long.class || valueType == long.class) { return true; } else if (valueType == Float.class || valueType == float.class) { return true; } else if (valueType == Double.class || valueType == double.class) { return true; } else if (valueType == Boolean.class || valueType == boolean.class) { return true; } else if (valueType == Character.class || valueType == char.class) { return true; } else if (valueType == Date.class) { return true; } else if (valueType.isEnum()) { return true; } // JSON string value should not be used in query condition. return false; } @SuppressWarnings("unchecked") public static String toJson(Object value) { try { return TlsMap.get("jsoda_om", sTlsObjectMapper).writeValueAsString(value); } catch (Exception e) { throw new IllegalArgumentException(e); } } @SuppressWarnings("unchecked") public static <T> T fromJson(String jsonStr, Class<T> objType) throws IOException { return (T) TlsMap.get("jsoda_om", sTlsObjectMapper).readValue(jsonStr, objType); } /** Convert Set<paramType> to Set<String> */ static Set<String> toStringSet(Set valueSet, Class paramType) { Set<String> strSet = new HashSet<String>(); for (Object value : valueSet) { strSet.add(encodeValueToAttrStr(value, paramType)); } return strSet; } /** Convert List<String> to Set<paramType> */ static Set<Object> toObjectSet(List<String> strs, Class paramType) throws Exception { Set<Object> set = new HashSet<Object>(); for (String str : strs) { set.add(decodeAttrStrToValue(str, paramType)); } return set; } }