X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fserial%2FSerialUtils.java;h=114f80b2576a57a08177d944adfe755da2665544;hb=949445eeaa6bc10572cc7bdc916de802f9ef817d;hp=73f2027abb75480957beb087681495fa75009363;hpb=5bc55b5183dcc811d06ef7cf2e26b43329a0ae34;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/serial/SerialUtils.java b/src/be/nikiroo/utils/serial/SerialUtils.java index 73f2027..114f80b 100644 --- a/src/be/nikiroo/utils/serial/SerialUtils.java +++ b/src/be/nikiroo/utils/serial/SerialUtils.java @@ -1,17 +1,19 @@ package be.nikiroo.utils.serial; -import java.awt.image.BufferedImage; import java.io.IOException; import java.io.NotSerializableException; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UnknownFormatConversionException; -import be.nikiroo.utils.ImageUtils; +import be.nikiroo.utils.Image; /** * Small class to help with serialisation. @@ -37,6 +39,7 @@ import be.nikiroo.utils.ImageUtils; *
  • Enum (any enum whose name and value is known by the caller)
  • *
  • java.awt.image.BufferedImage (as a {@link CustomSerializer})
  • *
  • An array of the above (as a {@link CustomSerializer})
  • + *
  • URL
  • * * * @author niki @@ -85,7 +88,7 @@ public class SerialUtils { } @Override - protected Object fromString(String content) { + protected Object fromString(String content) throws IOException { String[] tab = content.split("\n"); try { @@ -98,31 +101,54 @@ public class SerialUtils { return array; } catch (Exception e) { - throw new UnknownFormatConversionException(e.getMessage()); + if (e instanceof IOException) { + throw (IOException) e; + } + throw new IOException(e.getMessage()); } } }); - // Images (this is currently the only supported image type by default) - customTypes.put("java.awt.image.BufferedImage", new CustomSerializer() { + // URL: + customTypes.put("java.net.URL", new CustomSerializer() { @Override protected String toString(Object value) { - try { - return ImageUtils.toBase64((BufferedImage) value); - } catch (IOException e) { - throw new UnknownFormatConversionException(e.getMessage()); + if (value != null) { + return ((URL) value).toString(); + } + return null; + } + + @Override + protected Object fromString(String content) throws IOException { + if (content != null) { + return new URL(content); } + return null; } @Override protected String getType() { - return "java.awt.image.BufferedImage"; + return "java.net.URL"; + } + }); + + // Images (this is currently the only supported image type by default) + customTypes.put("be.nikiroo.utils.Image", new CustomSerializer() { + @Override + protected String toString(Object value) { + return ((Image) value).toBase64(); + } + + @Override + protected String getType() { + return "be.nikiroo.utils.Image"; } @Override protected Object fromString(String content) { try { - return ImageUtils.fromBase64(content); + return new Image(content); } catch (IOException e) { throw new UnknownFormatConversionException(e.getMessage()); } @@ -146,27 +172,59 @@ public class SerialUtils { public static Object createObject(String type) throws ClassNotFoundException, NoSuchMethodException { + String desc = null; + try { Class clazz = getClass(type); String className = clazz.getName(); - Object[] args = null; + List args = new ArrayList(); + List> classes = new ArrayList>(); 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() }); + for (String parentName = className.substring(0, + className.lastIndexOf('$'));; parentName = parentName + .substring(0, parentName.lastIndexOf('$'))) { + Object parent = createObject(parentName); + args.add(parent); + classes.add(parent.getClass()); + + if (!parentName.contains("$")) { + break; + } + } + + // Better error description in case there is no empty + // constructor: + desc = ""; + String end = ""; + for (Class parent = clazz; parent != null + && !parent.equals(Object.class); parent = parent + .getSuperclass()) { + if (!desc.isEmpty()) { + desc += " [:"; + end += "]"; + } + desc += parent; + } + desc += end; + // + + ctor = clazz.getDeclaredConstructor(classes + .toArray(new Class[] {})); + desc = null; } else { - args = new Object[] {}; ctor = clazz.getDeclaredConstructor(); } ctor.setAccessible(true); - return ctor.newInstance(args); + return ctor.newInstance(args.toArray()); } catch (ClassNotFoundException e) { throw e; } catch (NoSuchMethodException e) { + if (desc != null) { + throw new NoSuchMethodException("Empty constructor not found: " + + desc); + } throw e; } catch (Exception e) { throw new NoSuchMethodException("Cannot instantiate: " + type); @@ -217,10 +275,8 @@ public class SerialUtils { fields = o.getClass().getDeclaredFields(); type = o.getClass().getCanonicalName(); if (type == null) { - throw new NotSerializableException( - String.format( - "Cannot find the class for this object: %s (it could be an inner class, which is not supported)", - o)); + // Anonymous inner classes support + type = o.getClass().getName(); } id = Integer.toString(hash); if (map.containsKey(hash)) { @@ -270,7 +326,13 @@ public class SerialUtils { } /** - * Encode the object into the given builder if possible (if supported). + * Encode the object into the given builder if possible and if supported. + *

    + * A supported object in this context means an object we can directly + * encode, like an Integer or a String. Custom objects and arrays are also + * considered supported, but compound objects are not supported here. + *

    + * For compound objects, you should use {@link Exporter}. * * @param builder * the builder to append to @@ -283,7 +345,9 @@ public class SerialUtils { static boolean encode(StringBuilder builder, Object value) { if (value == null) { builder.append("NULL"); - } else if (value.getClass().getCanonicalName().endsWith("[]")) { + } else if (value.getClass().getSimpleName().endsWith("[]")) { + // Simple name does support [] suffix and do not return NULL for + // inner anonymous classes return customTypes.get("[]").encode(builder, value); } else if (customTypes.containsKey(value.getClass().getCanonicalName())) { return customTypes.get(value.getClass().getCanonicalName())// @@ -319,31 +383,36 @@ public class SerialUtils { } /** - * Decode the data into an equivalent source object. + * Decode the data into an equivalent supported source object. + *

    + * A supported object in this context means an object we can directly + * encode, like an Integer or a String. Custom objects and arrays are also + * considered supported, but compound objects are not supported here. + *

    + * For compound objects, you should use {@link Importer}. * * @param encodedValue * the encoded data, cannot be NULL * * @return the object (can be NULL for NULL encoded values) * - * @throws UnknownFormatConversionException + * @throws IOException * if the content cannot be converted */ - static Object decode(String encodedValue) { - String cut = ""; - if (encodedValue.length() > 1) { - cut = encodedValue.substring(0, encodedValue.length() - 1); - } - + static Object decode(String encodedValue) throws IOException { try { + String cut = ""; + if (encodedValue.length() > 1) { + cut = encodedValue.substring(0, encodedValue.length() - 1); + } + if (CustomSerializer.isCustom(encodedValue)) { // custom:TYPE_NAME:"content is String-encoded" String type = CustomSerializer.typeOf(encodedValue); if (customTypes.containsKey(type)) { return customTypes.get(type).decode(encodedValue); } - throw new UnknownFormatConversionException( - "Unknown custom type: " + type); + throw new IOException("Unknown custom type: " + type); } else if (encodedValue.equals("NULL") || encodedValue.equals("null")) { return null; @@ -371,10 +440,10 @@ public class SerialUtils { return Integer.parseInt(encodedValue); } } catch (Exception e) { - if (e instanceof UnknownFormatConversionException) { - throw (UnknownFormatConversionException) e; + if (e instanceof IOException) { + throw (IOException) e; } - throw new UnknownFormatConversionException(e.getMessage()); + throw new IOException(e.getMessage()); } } @@ -499,6 +568,6 @@ public class SerialUtils { } } - return builder.substring(1, builder.length() - 1).toString(); + return builder.substring(1, builder.length() - 1); } }