X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FSerialUtils.java;h=49817b250f4f170f3547e62355fa3a7b7b4023c3;hb=8c8da42a501ff223ee1340ab71d03df481649e78;hp=657dbec45fb069e26b77cc7423c0c606ffdc6a39;hpb=db31c35860081535d6e7ddc83ab4af573bb0522e;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/serial/SerialUtils.java b/src/be/nikiroo/utils/serial/SerialUtils.java index 657dbec..49817b2 100644 --- a/src/be/nikiroo/utils/serial/SerialUtils.java +++ b/src/be/nikiroo/utils/serial/SerialUtils.java @@ -1,30 +1,102 @@ package be.nikiroo.utils.serial; import java.io.NotSerializableException; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; /** - * Small class to help serialise/deserialise objects. + * Small class to help with serialisation. *

* Note that we do not support inner classes (but we do support nested classes) * and all objects require an empty constructor to be deserialised. * * @author niki */ -class SerialUtils { +public class SerialUtils { private static Map customTypes; static { customTypes = new HashMap(); - // TODO: add "default" custom serialisers + // TODO: add "default" custom serialisers if any (Bitmap?) } + /** + * Create an empty object of the given type. + * + * @param type + * the object type (its class name) + * + * @return the new object + * + * @throws ClassNotFoundException + * if the class cannot be found + * @throws NoSuchMethodException + * if the given class is not compatible with this code + */ + public static Object createObject(String type) + throws ClassNotFoundException, NoSuchMethodException { + + try { + Class clazz = getClass(type); + String className = clazz.getName(); + Object[] args = null; + Constructor ctor = null; + if (className.contains("$")) { + Object javaParent = createObject(className.substring(0, + className.lastIndexOf('$'))); + args = new Object[] { javaParent }; + ctor = clazz.getDeclaredConstructor(new Class[] { javaParent + .getClass() }); + } else { + args = new Object[] {}; + ctor = clazz.getDeclaredConstructor(); + } + + ctor.setAccessible(true); + return ctor.newInstance(args); + } catch (ClassNotFoundException e) { + throw e; + } catch (NoSuchMethodException e) { + throw e; + } catch (Exception e) { + throw new NoSuchMethodException("Cannot instantiate: " + type); + } + } + + /** + * Insert a custom serialiser that will take precedence over the default one + * or the target class. + * + * @param serializer + * the custom serialiser + */ static public void addCustomSerializer(CustomSerializer serializer) { customTypes.put(serializer.getType(), serializer); } + /** + * Serialise the given object into this {@link StringBuilder}. + *

+ * Important: If the operation fails (with a + * {@link NotSerializableException}), the {@link StringBuilder} will be + * corrupted (will contain bad, most probably not importable data). + * + * @param builder + * the output {@link StringBuilder} to serialise to + * @param o + * the object to serialise + * @param map + * the map of already serialised objects (if the given object or + * one of its descendant is already present in it, only an ID + * will be serialised) + * + * @throws NotSerializableException + * if the object cannot be serialised (in this case, the + * {@link StringBuilder} can contain bad, most probably not + * importable data) + */ static void append(StringBuilder builder, Object o, Map map) throws NotSerializableException { @@ -153,6 +225,56 @@ class SerialUtils { } } + /** + * Return the corresponding class or throw an {@link Exception} if it + * cannot. + * + * @param type + * the class name to look for + * + * @return the class (will never be NULL) + * + * @throws ClassNotFoundException + * if the class cannot be found + * @throws NoSuchMethodException + * if the class cannot be created (usually because it or its + * enclosing class doesn't have an empty constructor) + */ + static private Class getClass(String type) + throws ClassNotFoundException, NoSuchMethodException { + Class clazz = null; + try { + clazz = Class.forName(type); + } catch (ClassNotFoundException e) { + int pos = type.length(); + pos = type.lastIndexOf(".", pos); + if (pos >= 0) { + String parentType = type.substring(0, pos); + String nestedType = type.substring(pos + 1); + Class javaParent = null; + try { + javaParent = getClass(parentType); + parentType = javaParent.getName(); + clazz = Class.forName(parentType + "$" + nestedType); + } catch (Exception ee) { + } + + if (javaParent == null) { + throw new NoSuchMethodException( + "Class not found: " + + type + + " (the enclosing class cannot be created: maybe it doesn't have an empty constructor?)"); + } + } + } + + if (clazz == null) { + throw new ClassNotFoundException("Class not found: " + type); + } + + return clazz; + } + // aa bb -> "aa\tbb" private static void encodeString(StringBuilder builder, String raw) { builder.append('\"');