/* * Copyright (c) 2011-2014 Jeppetto and Jonathan Thompson * * 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 org.iternine.jeppetto.dao.mongodb.enhance; import org.iternine.jeppetto.dao.JeppettoException; import org.iternine.jeppetto.enhance.Enhancer; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.DBRefBase; import org.bson.types.ObjectId; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; public class DBObjectUtil { //------------------------------------------------------------- // Constants //------------------------------------------------------------- private static final Set<Class<?>> NO_CONVERSION_CLASSES = new HashSet<Class<?>>(); //------------------------------------------------------------- // Methods - Public - Static //------------------------------------------------------------- static { //noinspection unchecked Collections.addAll(NO_CONVERSION_CLASSES, Date.class, boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, Number.class, BigDecimal.class, BigInteger.class, String.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Pattern.class, byte[].class, DBRefBase.class, ObjectId.class); } /** * Returns true if the given object is a "mutable" type that needs to be enhanced * as DirtyableDBObject to prevent lost changes. Array types are ok because the default * isDirty method will detect changes there. * * @param object object to check * * @return true if mutable, false otherwise */ public static boolean objectIsMutable(Object object) { if (object == null) { return false; } Class<?> clazz = object.getClass(); return Collection.class.isAssignableFrom(clazz); } public static boolean needsNoConversion(Class clazz) { return NO_CONVERSION_CLASSES.contains(clazz); } public static Object fromObject(Class<?> type, final Object o) { if (o == null) { return null; } else if (type.isAssignableFrom(o.getClass())) { if (List.class.isAssignableFrom(type)) { if (DirtyableDBObjectList.class.isAssignableFrom(o.getClass())) { return o; } return new DirtyableDBObjectList((List) o, true); } else if (Map.class.isAssignableFrom(type)) { if (DirtyableDBObjectMap.class.isAssignableFrom(o.getClass())) { return o; } //noinspection unchecked return new DirtyableDBObjectMap((Map<String, Object>) o); } else if (Set.class.isAssignableFrom(type)) { if (DirtyableDBObjectSet.class.isAssignableFrom(o.getClass())) { return o; } return new DirtyableDBObjectSet((Set) o, true); } return type.cast(o); } else if (Iterable.class.isAssignableFrom(o.getClass()) && Set.class.isAssignableFrom(type)) { throw new JeppettoException(); // return fromSet(o, typeParameters); } else if (o instanceof DBObject) { DBObject copy = (DBObject) EnhancerHelper.getDirtyableDBObjectEnhancer(type).newInstance(); copy.putAll((DBObject) o); return copy; } else if (Enum.class.isAssignableFrom(type) && String.class.isAssignableFrom(o.getClass())) { // noinspection unchecked return Enum.valueOf((Class<Enum>) type, (String) o); } else if (BigDecimal.class == type && Number.class.isAssignableFrom(o.getClass())) { return BigDecimal.valueOf(((Number) o).doubleValue()); } else if (BigInteger.class == type && Number.class.isAssignableFrom(o.getClass())) { return BigInteger.valueOf(((Number) o).longValue()); } else { throw new RuntimeException("Not sure how to convert a " + o + " to a " + type.getSimpleName()); } } public static Object toDBObject(Object object) { // TODO: handle arrays. if (object == null || NO_CONVERSION_CLASSES.contains(object.getClass()) || DirtyableDBObject.class.isAssignableFrom(object.getClass())) { return object; } else if (Map.class.isAssignableFrom(object.getClass())) { //noinspection unchecked return new DirtyableDBObjectMap((Map) object); } else if (List.class.isAssignableFrom(object.getClass())) { return new DirtyableDBObjectList((List) object, true); } else if (Set.class.isAssignableFrom(object.getClass())) { return new DirtyableDBObjectSet((Set) object, true); } else if (Iterable.class.isAssignableFrom(object.getClass())) { throw new RuntimeException("oops..."); // return new DirtyableDBObjectList((Iterable) object); } else if (DBObject.class.isInstance(object)) { BasicDBObject dbo = new BasicDBObject(); DBObject src = (DBObject) object; for (String key : src.keySet()) { Object rawObject = src.get(key); Object dboValue = (rawObject == null) ? null : toDBObject(rawObject); dbo.put(key, dboValue); } return dbo; } else if (Enum.class.isInstance(object)) { return ((Enum) object).name(); } else { Enhancer enhancer = EnhancerHelper.getDirtyableDBObjectEnhancer(object.getClass()); //noinspection unchecked return enhancer.enhance(object); } } }