/**
* Tranfer of byte arrays is very memory consuming
* --> idea: create a string out of it and transfer it in one chuck.
* But: creating strings with many bytes does not work either properly (in Chrome and FF at least)
* So we create several smaller strings out of the byte array and transfer that one.
*
*/
@SuppressWarnings("UnusedDeclaration")
public class AByteArray_CustomFieldSerializer extends CustomFieldSerializer<AByteArray> {
private static final int CHUNK_SIZE = 50000;
@Override
public void deserializeInstance(SerializationStreamReader serializationStreamReader, AByteArray instance) throws SerializationException {
deserialize(serializationStreamReader, instance);
}
@Override
public void serializeInstance(SerializationStreamWriter serializationStreamWriter, AByteArray instance) throws SerializationException {
serialize(serializationStreamWriter, instance);
}
@SuppressWarnings("unused")
public static void deserialize(SerializationStreamReader reader, AByteArray instance) throws SerializationException {
// nothing here
}
public static void serialize(SerializationStreamWriter writer, AByteArray instance) throws SerializationException {
try {
writeBytes(writer, instance.getBytes());
} catch (UnsupportedEncodingException e) {
ICommonLogger.Logger.error(e.getMessage(), e);
}
}
private static void writeBytes(SerializationStreamWriter writer, byte[] bytes) throws UnsupportedEncodingException, SerializationException {
int length = bytes.length;
writer.writeInt(length);
int pos = 0;
while (pos < length) {
String string = createString(bytes, pos, Math.min(CHUNK_SIZE, length-pos));
writer.writeString(string);
pos += CHUNK_SIZE;
}
}
static String createString(byte[] bytes, int from, int len) throws UnsupportedEncodingException {
byte subBytes[] = getSubArray(bytes, from, len);
return ABase64.createString(ABase64.encode(subBytes));
}
private static byte[] getSubArray(byte[] source, int from, int len) {
byte[] ret = new byte[len];
// System.arraycopy() is slow in GWT
//noinspection ManualArrayCopy
for (int i = 0; i < ret.length; i++) {
ret[i] = source[from+i];
}
return ret;
}
@Override
public boolean hasCustomInstantiateInstance() {
return true;
}
public static AByteArray instantiate(SerializationStreamReader reader) throws SerializationException {
try {
return AByteArray.create(readByteArray(reader));
} catch (UnsupportedEncodingException e) {
ICommonLogger.Logger.error(e.getMessage(), e);
return null;
}
}
private static byte[] readByteArray(SerializationStreamReader reader) throws SerializationException, UnsupportedEncodingException {
int size = reader.readInt();
byte[] bytes = new byte[size];
int pos = 0;
while (pos < size) {
String string = reader.readString();
byte[] subBytes = ABase64.decode(ABase64.getBytes(string));
append(bytes, subBytes, pos);
pos += subBytes.length;
}
return bytes;
}
private static void append(byte[] target, byte[] source, int pos) {
for (int i = 0; i < source.length; i++) {
target[pos + i] = source[i];
}
}
@Override
public AByteArray instantiateInstance(SerializationStreamReader streamReader) throws SerializationException {
return instantiate(streamReader);
}
}
byte[]
if you're worried at all about payload size (byte[] will be on average something like 3-4x to send it though it will compress well at least, whereas base64 is always about 1.3x bigger than the original data)
@niloc132 the code is from 2013. I don't remember exactly anymore what was the reason. Yeah we have our own base64 implementation. But If I remember correctly the problem was in ABase64.createString(byte[] bytes)
which only uses new String(bytes, IStandardEncoding.STANDARD_ENCODING)
public static String createString(byte[] bytes) throws UnsupportedEncodingException {
return new String(bytes, IStandardEncoding.STANDARD_ENCODING);
}
I also remember that System.arraycopy() was always slow in GWT. But this seems to be fixed in the trunk now.
Is there any way to send an arraybuffer (provided through JS File API, wrapped into an Uint8Array) via GWT-RPC as byte array?
I got a workaround for this
@JeffQuesado_twitter Thanks, yes that would work although I am trying to avoid copying given that the file might be large.
Intl.DateTimeFormat
through JsInterop, or have a look at https://github.com/treblereel/gwt-datetime (available on Vertispan's repository)
byte[]
type back, then you must instantiate the byte[] in java and copy the values over