package mongodb.tools; import mongodb.tools.annotation.Id; import mongodb.tools.annotation.Ignore; import mongodb.tools.annotation.Version; import mongodb.tools.exception.VersionMismatchException; import org.bson.Document; import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; import java.beans.Introspector; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.*; /** * Created by emeric_martineau on 11/03/2015. */ public class MongoDbMapping { /** * Field name of version. */ public static final String VERSION_FIELD = "<version>"; /** * Map to map primitive class. */ private static final Map<Class<?>, Class<?>> primitiveMap = new HashMap<Class<?>, Class<?>>(); static { primitiveMap.put(Boolean.TYPE, Boolean.class); primitiveMap.put(Byte.TYPE, Byte.class); primitiveMap.put(Character.TYPE, Character.class); primitiveMap.put(Short.TYPE, Short.class); primitiveMap.put(Integer.TYPE, Integer.class); primitiveMap.put(Long.TYPE, Long.class); primitiveMap.put(Double.TYPE, Double.class); primitiveMap.put(Float.TYPE, Float.class); primitiveMap.put(Void.TYPE, Void.TYPE); } /** * Convert object to MondogDB object. Support direct object (int, String...) and Iterable. Not support array, Map... * * @see mongodb.tools.annotation.Ignore * @see mongodb.tools.annotation.Id * * @param obj object to convert * * @return mongodb object * * @throws InvocationTargetException * @throws IllegalAccessException */ public static Document toMongo(final Object obj) throws InvocationTargetException, IllegalAccessException { Document result; if (obj == null) { result = null; } else { result = new Document(); Class tClass = obj.getClass(); Version versionAnnotation = (Version) tClass.getAnnotation(Version.class); if (versionAnnotation != null) { result.append(VERSION_FIELD, versionAnnotation.version()); } Method[] methods = tClass.getMethods(); String methodName; // Fielname String fieldName; // Data of field Object data; // Use if data is iterable List temporaryList; // Current object of list Object objList; for (int i = 0; i < methods.length; i++) { methodName = methods[i].getName(); if (methodName.startsWith("get") && !"getClass".equals(methodName) && !methods[i].isAnnotationPresent(Ignore.class) && !methods[i].isAnnotationPresent(Id.class)) { // Found getter. fieldName = Introspector.decapitalize(methods[i].getName().substring(3)); if (methods[i].getParameterCount() == 0) { data = methods[i].invoke(obj); if (data instanceof Iterator) { Iterator it = ((List) data).iterator(); temporaryList = new LinkedList(); while (it.hasNext()) { objList = it.next(); temporaryList.add(toMongo(objList)); } } result.append(fieldName, data); } } } } return result; } /** * Convert MongoDb object to POJO * * @param mongoObj mongodb object * @param clazz class to instanciate * * @return object * * @throws IllegalAccessException * @throws InstantiationException * @throws VersionMismatchException if object is strict and version not match */ public static Object fromMongoDb(final Document mongoObj, final Class clazz) throws IllegalAccessException, InstantiationException, VersionMismatchException, InvocationTargetException, ClassNotFoundException { Object result; if (mongoObj == null) { result = null; } else { result = clazz.newInstance(); Class tClass = result.getClass(); Method[] methods = tClass.getMethods(); /* Class annotation */ Version versionAnnotation = (Version) tClass.getAnnotation(Version.class); String property; Object value; /* Setter method */ Method setter; /* Parameter of setter */ Class<?> parameter; Type[] type; for (Map.Entry<String, Object> setKey : mongoObj.entrySet()) { property = setKey.getKey(); value = setKey.getValue(); if (VERSION_FIELD.equals(property)) { // Check version if (versionAnnotation != null && versionAnnotation.strict()) { int version = Integer.valueOf((String) value); if (version != versionAnnotation.version()) { throw new VersionMismatchException(String.format("Version %d found, version %d expected.", version, versionAnnotation.version())); } } } else { setter = findSetter(methods, property); if (setter != null) { parameter = setter.getParameterTypes()[0]; type = setter.getGenericParameterTypes(); if (parameter.isPrimitive()) { invokePrimitive(result, setter, parameter, value); } else if (parameter.isEnum()) { invokeEnum(result, setter, parameter, value); } else if (parameter.isArray()) { // TODO } else if (parameter.getName().equals("java.lang.String")) { setter.invoke(result, value); } else if (parameter == List.class) { invokeList(result, setter, type, value); } System.out.println(parameter); // si c'est un talbeau // si c'est une map } } } } return result; } /** * Find method setter with only one parameter. * * @param methods methods list * @param fieldName fieldName * * @return method */ private static Method findSetter(final Method[] methods, final String fieldName) { String methodName = "set".concat(Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1)); System.out.println(fieldName); // Search method Method m = null; for (Method currentMethod : methods) { if (methodName.equals(currentMethod.getName())) { // Now check only one parameter if (currentMethod.getParameterCount() == 1) { m = currentMethod; break; } } } return m; } /** * Invoke primitive setter. * * @param obj object to call setter * @param m method to call * @param parameter parametter of setter * @param value value to setup * * @throws InvocationTargetException * @throws IllegalAccessException */ private static void invokePrimitive(Object obj, Method m, Class<?> parameter, Object value) throws InvocationTargetException, IllegalAccessException { if (parameter == Boolean.TYPE) { m.invoke(obj, Boolean.valueOf((String) value)); } else if (parameter == Byte.TYPE) { m.invoke(obj, Byte.valueOf((String) value)); } else if (parameter == Character.TYPE) { m.invoke(obj, Character.valueOf((char) value)); } else if (parameter == Short.TYPE) { m.invoke(obj, Short.valueOf((String) value)); } else if (parameter == Integer.TYPE) { m.invoke(obj, Integer.valueOf((String) value)); } else if (parameter == Long.TYPE) { m.invoke(obj, Long.valueOf((String) value)); } else if (parameter == Double.TYPE) { m.invoke(obj, Double.valueOf((String) value)); } else if (parameter == Float.TYPE) { m.invoke(obj, Float.valueOf((String) value)); } } /** * Invoke enum setter. * * @param obj object to call setter * @param m method to call * @param parameter parametter of setter * @param value value to setup * * @throws InvocationTargetException * @throws IllegalAccessException */ private static void invokeEnum(Object obj, Method m, Class<?> parameter, Object value) throws InvocationTargetException, IllegalAccessException { Enum enumValue = Enum.valueOf((Class<Enum>) parameter, (String) value); m.invoke(obj, enumValue); } /** * Invoke collection setter. * * @param obj object to call setter * @param m method to call * @param parameter parametter of setter * @param value value to setup * * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException */ private static void invokeList(Object obj, Method m, Type[] parameter, Object value) throws InvocationTargetException, IllegalAccessException, InstantiationException, VersionMismatchException, ClassNotFoundException { List srcList = (List) value; List destList = null; Class classOfList = getGenericClass(parameter); if (value != null) { destList = new ArrayList(srcList.size()); for (Object item : srcList) { if (item == null) { destList.add(null); }else if (item instanceof Document) { fromMongoDb((Document) item, classOfList); } else { destList.add(item); } } } m.invoke(obj, destList); } /** * Found type of generic * * @param parameter parameter of method * * @return class to be instanciate * * @throws ClassNotFoundException */ private static Class getGenericClass(Type[] parameter) throws ClassNotFoundException { Type type = ((ParameterizedTypeImpl) parameter[0]).getActualTypeArguments()[0]; return Class.forName(type.getTypeName()); } }
jeudi 11 juin 2015
Java et la réflexion [4/4]
Maintenant que vous maîtriser les annotations et la réflexion en java, voici le code source complet du convertissant Java -> Mongo/Mongo -> Java :
Inscription à :
Publier les commentaires (Atom)
Aucun commentaire:
Enregistrer un commentaire