package be.nikiroo.utils.serial;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.NotSerializableException;
import java.util.Map;
import java.util.UnknownFormatConversionException;
+import be.nikiroo.utils.IOUtils;
import be.nikiroo.utils.Image;
+import be.nikiroo.utils.NextableInputStream;
+import be.nikiroo.utils.NextableInputStreamStep;
+import be.nikiroo.utils.StringUtils;
/**
* Small class to help with serialisation.
// Array types:
customTypes.put("[]", new CustomSerializer() {
@Override
- protected String toString(Object value) {
+ protected void toStream(OutputStream out, Object value)
+ throws IOException {
+ // TODO: we use \n to separate, and b64 to un-\n -- but we could
+ // use \\n ?
String type = value.getClass().getCanonicalName();
type = type.substring(0, type.length() - 2); // remove the []
- StringBuilder builder = new StringBuilder();
- builder.append(type).append("\n");
+ write(out, type);
+ write(out, "\n");
try {
for (int i = 0; true; i++) {
Object item = Array.get(value, i);
// encode it normally if direct value
- if (!SerialUtils.encode(builder, item)) {
+ if (!SerialUtils.encode(out, item)) {
try {
- // use ZIP: if not
- new Exporter().append(item).appendTo(builder,
- true, false);
+ // TODO: use ZIP: if not?
+ new Exporter(out).append(item);
} catch (NotSerializableException e) {
throw new UnknownFormatConversionException(e
.getMessage());
}
}
- builder.append("\n");
+ write(out, "\n");
}
} catch (ArrayIndexOutOfBoundsException e) {
// Done.
}
-
- return builder.toString();
- }
-
- @Override
- protected String getType() {
- return "[]";
}
@Override
- protected Object fromString(String content) throws IOException {
- String[] tab = content.split("\n");
+ protected Object fromStream(InputStream in) throws IOException {
+ NextableInputStream stream = new NextableInputStream(in,
+ new NextableInputStreamStep('\n'));
try {
+ List<Object> list = new ArrayList<Object>();
+ stream.next();
+ String type = IOUtils.readSmallStream(stream);
+
+ while (stream.next()) {
+ Object value = new Importer().read(stream).getValue();
+ list.add(value);
+ }
+
Object array = Array.newInstance(
- SerialUtils.getClass(tab[0]), tab.length - 1);
- for (int i = 1; i < tab.length; i++) {
- Object value = new Importer().read(tab[i]).getValue();
- Array.set(array, i - 1, value);
+ SerialUtils.getClass(type), list.size());
+ for (int i = 0; i < list.size(); i++) {
+ Array.set(array, i, list.get(i));
}
return array;
throw new IOException(e.getMessage());
}
}
+
+ @Override
+ protected String getType() {
+ return "[]";
+ }
});
// URL:
customTypes.put("java.net.URL", new CustomSerializer() {
+
@Override
- protected String toString(Object value) {
+ protected void toStream(OutputStream out, Object value)
+ throws IOException {
+ String val = "";
if (value != null) {
- return ((URL) value).toString();
+ val = ((URL) value).toString();
}
- return null;
+
+ out.write(val.getBytes("UTF-8"));
}
@Override
- protected Object fromString(String content) throws IOException {
- if (content != null) {
- return new URL(content);
+ protected Object fromStream(InputStream in) throws IOException {
+ String val = IOUtils.readSmallStream(in);
+ if (!val.isEmpty()) {
+ return new URL(val);
}
+
return null;
}
// 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();
+ protected void toStream(OutputStream out, Object value)
+ throws IOException {
+ Image img = (Image) value;
+ OutputStream encoded = StringUtils.base64(out, false, false);
+ try {
+ InputStream in = img.newInputStream();
+ try {
+ IOUtils.write(in, encoded);
+ } finally {
+ in.close();
+ }
+ } finally {
+ encoded.close();
+ }
}
@Override
}
@Override
- protected Object fromString(String content) {
+ protected Object fromStream(InputStream in) throws IOException {
try {
- return new Image(content);
+ return new Image(in);
} catch (IOException e) {
throw new UnknownFormatConversionException(e.getMessage());
}
ctor = clazz.getDeclaredConstructor(classes
.toArray(new Class[] {}));
} catch (NoSuchMethodException nsme) {
- // TODO: it seems e do not always need a parameter for each
+ // TODO: it seems we do not always need a parameter for each
// level, so we currently try "ALL" levels or "FIRST" level
// only -> we should check the actual rule and use it
ctor = clazz.getDeclaredConstructor(classes.get(0));
// custom:TYPE_NAME:"content is String-encoded"
String type = CustomSerializer.typeOf(encodedValue);
if (customTypes.containsKey(type)) {
- return customTypes.get(type).decode(encodedValue);
+ // TODO: we should start with a stream
+ InputStream streamEncodedValue = new ByteArrayInputStream(
+ encodedValue.getBytes("UTF-8"));
+ try {
+ return customTypes.get(type).decode(streamEncodedValue);
+ } finally {
+ streamEncodedValue.close();
+ }
}
throw new IOException("Unknown custom type: " + type);
} else if (encodedValue.equals("NULL")
static void encodeString(OutputStream out, InputStream raw)
throws IOException {
out.write('\"');
- byte buffer[] = new byte[4069];
+ byte buffer[] = new byte[4096];
for (int len = 0; (len = raw.read(buffer)) > 0;) {
for (int i = 0; i < len; i++) {
// TODO: not 100% correct, look up howto for UTF-8