From 8997c3b60d356c108fc4d797b5b01b11527f5232 Mon Sep 17 00:00:00 2001 From: Maciej Lach Date: Tue, 6 Oct 2015 11:50:15 +0200 Subject: [PATCH] Collections serialization support in DefaultQWriter --- CHANGELOG.txt | 1 + doc/Type-conversion.md | 10 + .../com/exxeleron/qjava/DefaultQWriter.java | 315 ++++++++++++------ src/main/java/com/exxeleron/qjava/QType.java | 17 + .../java/com/exxeleron/qjava/QWriter.java | 22 ++ .../com/exxeleron/qjava/QExpressions.java | 56 ++-- 6 files changed, 299 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8b231a0..bdffabf 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -3,6 +3,7 @@ ------------------------------------------------------------------------------ - API redesign: enable custom serializers & deserializers + - Collections serialization support in DefaultQWriter - Improve memory reuse in QWriter - Improve performance while iterating over QTable, QDictionary and QKeyedTable: partial reimplementation of java.lang.reflect.Array diff --git a/doc/Type-conversion.md b/doc/Type-conversion.md index 5ad1d93..a76d7d9 100644 --- a/doc/Type-conversion.md +++ b/doc/Type-conversion.md @@ -58,6 +58,16 @@ Note that q list are represented as arrays of primitive type by the qJava library. It is possible to send to q arrays of primitive type (e.g. `int[]`) as well as of boxed type (e.g. `Integer[]`). +`DefaultQWriter` supports serialization of Java `Collection`s. Q type is +derived from the first element of the `Collection`, e.g.: + +```java +new ArrayList(Arrays.asList(new Integer[] { 0, 1, 2, 3 })); // serialized as integer list +new ArrayList(Arrays.asList(new Object[] { null, 2, 3, "test" })); // serialized as general list + +new ArrayList(Arrays.asList(new Object[] { 1, "test" })); // serialization error, assumed to be integer-only list +``` + ### Temporal types q language provides multiple types for operating on temporal data. The qJava library provides a corresponding temporal class for each q temporal type. diff --git a/src/main/java/com/exxeleron/qjava/DefaultQWriter.java b/src/main/java/com/exxeleron/qjava/DefaultQWriter.java index b13e7a8..55d017e 100644 --- a/src/main/java/com/exxeleron/qjava/DefaultQWriter.java +++ b/src/main/java/com/exxeleron/qjava/DefaultQWriter.java @@ -16,8 +16,10 @@ package com.exxeleron.qjava; import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.UUID; @@ -29,47 +31,50 @@ public class DefaultQWriter extends QWriter { /** * @see com.exxeleron.qjava.QWriter#writeObject(java.lang.Object) */ + @Override protected void writeObject( final Object obj ) throws IOException, QException { - final QType qtype = getQType(obj); - - if ( qtype == QType.STRING ) { - writeString((char[]) obj); - } else if ( qtype == QType.GENERAL_LIST ) { - writeGeneralList((Object[]) obj); - } else if ( qtype == QType.NULL_ITEM ) { - writeNullItem(); - } else if ( qtype == QType.ERROR ) { - writeError((Exception) obj); - } else if ( qtype == QType.DICTIONARY ) { - writeDictionary((QDictionary) obj); - } else if ( qtype == QType.TABLE ) { - writeTable((QTable) obj); - } else if ( qtype == QType.KEYED_TABLE ) { - writeKeyedTable((QKeyedTable) obj); - } else if ( qtype.getTypeCode() < 0 ) { - writeAtom(obj, qtype); - } else if ( qtype.getTypeCode() >= QType.BOOL_LIST.getTypeCode() && qtype.getTypeCode() <= QType.TIME_LIST.getTypeCode() ) { - writeList(obj, qtype); - } else if ( qtype == QType.LAMBDA ) { - writeLambda((QLambda) obj); - } else if ( qtype == QType.PROJECTION ) { - writeProjection((QProjection) obj); + if ( obj instanceof Collection ) { + writeCollection((Collection) obj); } else { - throw new QWriterException("Unable to serialize q type: " + qtype); + final QType qtype = getQType(obj); + checkProtocolVersionCompatibility(qtype); + + if ( qtype == QType.STRING ) { + writeString((char[]) obj); + } else if ( qtype == QType.GENERAL_LIST ) { + writeGeneralList((Object[]) obj); + } else if ( qtype == QType.NULL_ITEM ) { + writeNullItem(); + } else if ( qtype == QType.ERROR ) { + writeError((Exception) obj); + } else if ( qtype == QType.DICTIONARY ) { + writeDictionary((QDictionary) obj); + } else if ( qtype == QType.TABLE ) { + writeTable((QTable) obj); + } else if ( qtype == QType.KEYED_TABLE ) { + writeKeyedTable((QKeyedTable) obj); + } else if ( qtype.getTypeCode() < 0 ) { + writeAtom(obj, qtype); + } else if ( qtype.getTypeCode() >= QType.BOOL_LIST.getTypeCode() && qtype.getTypeCode() <= QType.TIME_LIST.getTypeCode() ) { + writeList(obj, qtype); + } else if ( qtype == QType.LAMBDA ) { + writeLambda((QLambda) obj); + } else if ( qtype == QType.PROJECTION ) { + writeProjection((QProjection) obj); + } else { + throw new QWriterException("Unable to serialize q type: " + qtype); + } } } @SuppressWarnings("incomplete-switch") - protected void writeAtom( final Object obj, final QType qtype ) throws IOException, QException { + protected void writeAtom( final Object obj, final QType qtype ) throws IOException { writer.writeByte(qtype.getTypeCode()); switch ( qtype ) { case BOOL: writer.writeByte((byte) ((Boolean) obj ? 1 : 0)); break; case GUID: - if ( protocolVersion < 3 ) { - throw new QWriterException("kdb+ protocol version violation: guid not supported pre kdb+ v3.0"); - } writeGuid((UUID) obj); break; case BYTE: @@ -97,9 +102,6 @@ protected void writeAtom( final Object obj, final QType qtype ) throws IOExcepti writeSymbol((String) obj); break; case TIMESTAMP: - if ( protocolVersion < 1 ) { - throw new QWriterException("kdb+ protocol version violation: timestamp not supported pre kdb+ v2.6"); - } writer.writeLong(((QTimestamp) obj).getValue()); break; case MONTH: @@ -112,9 +114,6 @@ protected void writeAtom( final Object obj, final QType qtype ) throws IOExcepti writer.writeDouble(((QDateTime) obj).getValue()); break; case TIMESPAN: - if ( protocolVersion < 1 ) { - throw new QWriterException("kdb+ protocol version violation: timespan not supported pre kdb+ v2.6"); - } writer.writeLong(((QTimespan) obj).getValue()); break; case MINUTE: @@ -130,7 +129,7 @@ protected void writeAtom( final Object obj, final QType qtype ) throws IOExcepti } @SuppressWarnings("incomplete-switch") - protected void writeList( final Object obj, final QType qtype ) throws IOException, QException { + protected void writeList( final Object obj, final QType qtype ) throws IOException { writer.writeByte(qtype.getTypeCode()); writer.writeByte((byte) 0); // attributes @@ -139,26 +138,23 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof boolean[] ) { final boolean[] list = (boolean[]) obj; writer.writeInt(list.length); - for ( final boolean a : list ) { - writer.writeByte((byte) (a ? 1 : 0)); + for ( final boolean e : list ) { + writer.writeByte((byte) (e ? 1 : 0)); } } else if ( obj instanceof Boolean[] ) { final Boolean[] list = (Boolean[]) obj; writer.writeInt(list.length); - for ( final Boolean a : list ) { - writer.writeByte((byte) (a ? 1 : 0)); + for ( final Boolean e : list ) { + writer.writeByte((byte) (e ? 1 : 0)); } } break; } case GUID_LIST: { - if ( protocolVersion < 3 ) { - throw new QWriterException("kdb+ protocol version violation: guid not supported pre kdb+ v3.0"); - } final UUID[] list = (UUID[]) obj; writer.writeInt(list.length); - for ( final UUID a : list ) { - writeGuid(a); + for ( final UUID e : list ) { + writeGuid(e); } break; } @@ -166,14 +162,14 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof byte[] ) { final byte[] list = (byte[]) obj; writer.writeInt(list.length); - for ( final byte a : list ) { - writer.writeByte(a); + for ( final byte e : list ) { + writer.writeByte(e); } } else if ( obj instanceof Byte[] ) { final Byte[] list = (Byte[]) obj; writer.writeInt(list.length); - for ( final Byte a : list ) { - writer.writeByte(a); + for ( final Byte e : list ) { + writer.writeByte(e); } } break; @@ -182,14 +178,14 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof short[] ) { final short[] list = (short[]) obj; writer.writeInt(list.length); - for ( final short a : list ) { - writer.writeShort(a); + for ( final short e : list ) { + writer.writeShort(e); } } else if ( obj instanceof Short[] ) { final Short[] list = (Short[]) obj; writer.writeInt(list.length); - for ( final Short a : list ) { - writer.writeShort(a); + for ( final Short e : list ) { + writer.writeShort(e); } } break; @@ -198,14 +194,14 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof int[] ) { final int[] list = (int[]) obj; writer.writeInt(list.length); - for ( final int a : list ) { - writer.writeInt(a); + for ( final int e : list ) { + writer.writeInt(e); } } else if ( obj instanceof Integer[] ) { final Integer[] list = (Integer[]) obj; writer.writeInt(list.length); - for ( final Integer a : list ) { - writer.writeInt(a); + for ( final Integer e : list ) { + writer.writeInt(e); } } break; @@ -214,14 +210,14 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof long[] ) { final long[] list = (long[]) obj; writer.writeInt(list.length); - for ( final long a : list ) { - writer.writeLong(a); + for ( final long e : list ) { + writer.writeLong(e); } } else if ( obj instanceof Long[] ) { final Long[] list = (Long[]) obj; writer.writeInt(list.length); - for ( final Long a : list ) { - writer.writeLong(a); + for ( final Long e : list ) { + writer.writeLong(e); } } break; @@ -230,14 +226,14 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof float[] ) { final float[] list = (float[]) obj; writer.writeInt(list.length); - for ( final float a : list ) { - writer.writeFloat(a); + for ( final float e : list ) { + writer.writeFloat(e); } } else if ( obj instanceof Float[] ) { final Float[] list = (Float[]) obj; writer.writeInt(list.length); - for ( final Float a : list ) { - writer.writeFloat(a); + for ( final Float e : list ) { + writer.writeFloat(e); } } break; @@ -246,14 +242,14 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti if ( obj instanceof double[] ) { final double[] list = (double[]) obj; writer.writeInt(list.length); - for ( final double a : list ) { - writer.writeDouble(a); + for ( final double e : list ) { + writer.writeDouble(e); } } else if ( obj instanceof Double[] ) { final Double[] list = (Double[]) obj; writer.writeInt(list.length); - for ( final Double a : list ) { - writer.writeDouble(a); + for ( final Double e : list ) { + writer.writeDouble(e); } } break; @@ -261,78 +257,203 @@ protected void writeList( final Object obj, final QType qtype ) throws IOExcepti case SYMBOL_LIST: { final String[] list = (String[]) obj; writer.writeInt(list.length); - for ( final String a : list ) { - writeSymbol(a); + for ( final String e : list ) { + writeSymbol(e); } break; } case TIMESTAMP_LIST: { - if ( protocolVersion < 1 ) { - throw new QWriterException("kdb+ protocol version violation: timestamp not supported pre kdb+ v2.6"); - } final QTimestamp[] list = (QTimestamp[]) obj; writer.writeInt(list.length); - for ( final QTimestamp a : list ) { - writer.writeLong(a.getValue()); + for ( final QTimestamp e : list ) { + writer.writeLong(e.getValue()); } break; } case MONTH_LIST: { final QMonth[] list = (QMonth[]) obj; writer.writeInt(list.length); - for ( final QMonth a : list ) { - writer.writeInt(a.getValue()); + for ( final QMonth e : list ) { + writer.writeInt(e.getValue()); } break; } case DATE_LIST: { final QDate[] list = (QDate[]) obj; writer.writeInt(list.length); - for ( final QDate a : list ) { - writer.writeInt(a.getValue()); + for ( final QDate e : list ) { + writer.writeInt(e.getValue()); } break; } case DATETIME_LIST: { final QDateTime[] list = (QDateTime[]) obj; writer.writeInt(list.length); - for ( final QDateTime a : list ) { - writer.writeDouble(a.getValue()); + for ( final QDateTime e : list ) { + writer.writeDouble(e.getValue()); } break; } case TIMESPAN_LIST: { - if ( protocolVersion < 1 ) { - throw new QWriterException("kdb+ protocol version violation: timespan not supported pre kdb+ v2.6"); - } final QTimespan[] list = (QTimespan[]) obj; writer.writeInt(list.length); - for ( final QTimespan a : list ) { - writer.writeLong(a.getValue()); + for ( final QTimespan e : list ) { + writer.writeLong(e.getValue()); } break; } case MINUTE_LIST: { final QMinute[] list = (QMinute[]) obj; writer.writeInt(list.length); - for ( final QMinute a : list ) { - writer.writeInt(a.getValue()); + for ( final QMinute e : list ) { + writer.writeInt(e.getValue()); } break; } case SECOND_LIST: { final QSecond[] list = (QSecond[]) obj; writer.writeInt(list.length); - for ( final QSecond a : list ) { - writer.writeInt(a.getValue()); + for ( final QSecond e : list ) { + writer.writeInt(e.getValue()); } break; } case TIME_LIST: { final QTime[] list = (QTime[]) obj; writer.writeInt(list.length); - for ( final QTime a : list ) { - writer.writeInt(a.getValue()); + for ( final QTime e : list ) { + writer.writeInt(e.getValue()); + } + break; + } + } + } + + @SuppressWarnings("incomplete-switch") + protected void writeCollection( final Collection collection ) throws IOException, QException { + final Iterator it = collection.iterator(); + QType qtype = QType.GENERAL_LIST; + if ( it.hasNext() ) { + final Object firstElem = it.next(); + qtype = firstElem != null && toQ.containsKey(firstElem.getClass()) ? toQ.get(firstElem.getClass()) : QType.GENERAL_LIST; + if ( qtype != QType.STRING ) { + qtype = QType.valueOf((byte) (-1 * qtype.getTypeCode())); + } else { + qtype = QType.GENERAL_LIST; + } + } + + checkProtocolVersionCompatibility(qtype); + + writer.writeByte(qtype.getTypeCode()); + writer.writeByte((byte) 0); // attributes + writer.writeInt(collection.size()); + + switch ( qtype ) { + case BOOL_LIST: { + for ( final Object e : collection ) { + writer.writeByte((byte) ((Boolean) e ? 1 : 0)); + } + break; + } + case GUID_LIST: { + for ( final Object e : collection ) { + writeGuid((UUID) e); + } + break; + } + case BYTE_LIST: { + for ( final Object e : collection ) { + writer.writeByte((Byte) e); + } + break; + } + case SHORT_LIST: { + for ( final Object e : collection ) { + writer.writeShort((Short) e); + } + break; + } + case INT_LIST: { + for ( final Object e : collection ) { + writer.writeInt((Integer) e); + } + break; + } + case LONG_LIST: { + for ( final Object e : collection ) { + writer.writeLong((Long) e); + } + break; + } + case FLOAT_LIST: { + for ( final Object e : collection ) { + writer.writeFloat((Float) e); + } + break; + } + case DOUBLE_LIST: { + for ( final Object e : collection ) { + writer.writeDouble((Double) e); + } + break; + } + case SYMBOL_LIST: { + for ( final Object e : collection ) { + writeSymbol((String) e); + } + break; + } + case TIMESTAMP_LIST: { + for ( final Object e : collection ) { + writer.writeLong(((QTimestamp) e).getValue()); + } + break; + } + case MONTH_LIST: + for ( final Object e : collection ) { + writer.writeInt(((QMonth) e).getValue()); + } + break; + case DATE_LIST: { + for ( final Object e : collection ) { + writer.writeInt(((QDate) e).getValue()); + } + break; + } + case DATETIME_LIST: { + for ( final Object e : collection ) { + writer.writeDouble(((QDateTime) e).getValue()); + } + break; + } + case TIMESPAN_LIST: { + for ( final Object e : collection ) { + writer.writeLong(((QTimespan) e).getValue()); + } + break; + } + case MINUTE_LIST: { + for ( final Object e : collection ) { + writer.writeInt(((QMinute) e).getValue()); + } + break; + } + case SECOND_LIST: { + for ( final Object e : collection ) { + writer.writeInt(((QSecond) e).getValue()); + } + break; + } + case TIME_LIST: { + for ( final Object e : collection ) { + writer.writeInt(((QTime) e).getValue()); + } + break; + } + case GENERAL_LIST: { + for ( final Object e : collection ) { + writeObject(e); } break; } @@ -353,11 +474,7 @@ protected void writeSymbol( final String s ) throws IOException { writer.writeByte((byte) 0); } - protected void writeGuid( final UUID obj ) throws QException { - if ( protocolVersion < 3 ) { - throw new QWriterException("kdb+ protocol version violation: Guid not supported pre kdb+ v3.0"); - } - + protected void writeGuid( final UUID obj ) { writer.writeLongBigEndian(obj.getMostSignificantBits()); writer.writeLongBigEndian(obj.getLeastSignificantBits()); } @@ -477,7 +594,7 @@ protected void writeProjection( final QProjection p ) throws IOException, QExcep /** * Returns default mapping for particular java object to representative q type. - * + * * @param obj * Requested object * @return {@link QType} enum being a result of q serialization diff --git a/src/main/java/com/exxeleron/qjava/QType.java b/src/main/java/com/exxeleron/qjava/QType.java index 9110309..168dd7c 100644 --- a/src/main/java/com/exxeleron/qjava/QType.java +++ b/src/main/java/com/exxeleron/qjava/QType.java @@ -128,6 +128,23 @@ byte getTypeCode() { }); + /** + * Returns {@link QType} based on type code identifier. + * + * @param typecode + * type code identifier + * @return {@link QType} enum bound with type code identifier + * @throws IllegalArgumentException + * in case q type code is unknown + */ + public static QType valueOf( final byte typecode ) { + if ( lookup.containsKey(typecode) ) { + return lookup.get(typecode); + } else { + throw new IllegalArgumentException("Invalid q type code: " + typecode); + } + } + /** * Returns {@link QType} based on type code identifier. * diff --git a/src/main/java/com/exxeleron/qjava/QWriter.java b/src/main/java/com/exxeleron/qjava/QWriter.java index df2aba7..aa70a6c 100644 --- a/src/main/java/com/exxeleron/qjava/QWriter.java +++ b/src/main/java/com/exxeleron/qjava/QWriter.java @@ -125,4 +125,26 @@ public int write( final Object obj, final QConnection.MessageType msgType ) thro */ protected abstract void writeObject( final Object obj ) throws IOException, QException; + /** + * Verifies whether specified q type is compatible with current protocol version. + * + * @param qtype + * qtype to be checked + * @throws QWriterException + * if specified q type is not valid in current protocol + */ + protected void checkProtocolVersionCompatibility( final QType qtype ) throws QWriterException { + if ( protocolVersion < 3 && (qtype == QType.GUID || qtype == QType.GUID_LIST) ) { + throw new QWriterException("kdb+ protocol version violation: guid not supported pre kdb+ v3.0"); + } + + if ( protocolVersion < 1 && (qtype == QType.TIMESPAN || qtype == QType.TIMESPAN_LIST) ) { + throw new QWriterException("kdb+ protocol version violation: timespan not supported pre kdb+ v2.6"); + } + + if ( protocolVersion < 1 && (qtype == QType.TIMESTAMP || qtype == QType.TIMESTAMP_LIST) ) { + throw new QWriterException("kdb+ protocol version violation: timestamp not supported pre kdb+ v2.6"); + } + } + } diff --git a/src/test/java/com/exxeleron/qjava/QExpressions.java b/src/test/java/com/exxeleron/qjava/QExpressions.java index 2360514..2267c5f 100644 --- a/src/test/java/com/exxeleron/qjava/QExpressions.java +++ b/src/test/java/com/exxeleron/qjava/QExpressions.java @@ -18,6 +18,7 @@ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -34,15 +35,15 @@ private void initExpressions() throws QException { reference.put("1+`", new Object[] { new QException("type") }); reference.put("()", new Object[] { new Object[0] }); reference.put("::", new Object[] { null }); - reference.put("1", new Object[] { 1L }); - reference.put("1i", new Object[] { 1 }); - reference.put("-234h", new Object[] { (short) -234 }); - reference.put("1b", new Object[] { true }); - reference.put("0x2a", new Object[] { (byte) 0x2a }); - reference.put("89421099511627575j", new Object[] { 89421099511627575L }); - reference.put("3.234", new Object[] { 3.234 }); - reference.put("5.5e", new Object[] { (float) 5.5 }); - reference.put("\"0\"", new Object[] { '0' }); + reference.put("1", new Object[] { 1L, Long.valueOf(1) }); + reference.put("1i", new Object[] { 1, Integer.valueOf(1) }); + reference.put("-234h", new Object[] { (short) -234, Short.valueOf((short) -234) }); + reference.put("1b", new Object[] { true, Boolean.TRUE }); + reference.put("0x2a", new Object[] { (byte) 0x2a, Byte.valueOf((byte) 0x2a) }); + reference.put("89421099511627575j", new Object[] { 89421099511627575L, Long.valueOf(89421099511627575L) }); + reference.put("3.234", new Object[] { 3.234, Double.valueOf(3.234) }); + reference.put("5.5e", new Object[] { (float) 5.5, Float.valueOf((float) 5.5) }); + reference.put("\"0\"", new Object[] { '0', Character.valueOf('0') }); reference.put("\"abc\"", new Object[] { "abc".toCharArray() }); reference.put("\"\"", new Object[] { "".toCharArray() }); reference.put("\"quick brown fox jumps over a lazy dog\"", new Object[] { "quick brown fox jumps over a lazy dog".toCharArray() }); @@ -75,23 +76,32 @@ private void initExpressions() throws QException { reference.put("0Nu", new Object[] { QType.getQNull(QType.MINUTE) }); reference.put("0Nv", new Object[] { QType.getQNull(QType.SECOND) }); reference.put("0Nt", new Object[] { QType.getQNull(QType.TIME) }); - reference.put("(0b;1b;0b)", new Object[] { new boolean[] { false, true, false }, new Boolean[] { false, true, false } }); - reference.put("(0x01;0x02;0xff)", new Object[] { new byte[] { 1, 2, (byte) 255 }, new Byte[] { 1, 2, (byte) 255 } }); - reference.put("(1h;2h;3h)", new Object[] { new short[] { 1, 2, 3 }, new Short[] { 1, 2, 3 } }); - reference.put("1 2 3", new Object[] { new long[] { 1, 2, 3 }, new Long[] { 1L, 2L, 3L } }); - reference.put("(1i;2i;3i)", new Object[] { new int[] { 1, 2, 3 }, new Integer[] { 1, 2, 3 } }); - reference.put("(1j;2j;3j)", new Object[] { new long[] { 1, 2, 3 }, new Long[] { 1L, 2L, 3L } }); - reference.put("(5.5e; 8.5e)", new Object[] { new float[] { 5.5f, 8.5f }, new Float[] { 5.5f, 8.5f } }); - reference.put("3.23 6.46", new Object[] { new double[] { 3.23, 6.46 }, new Double[] { 3.23, 6.46 } }); + reference + .put("(0b;1b;0b)", + new Object[] { new boolean[] { false, true, false }, new Boolean[] { false, true, false }, + Arrays.asList(new Boolean[] { false, true, false }) }); + reference.put("(0x01;0x02;0xff)", + new Object[] { new byte[] { 1, 2, (byte) 255 }, new Byte[] { 1, 2, (byte) 255 }, Arrays.asList(new Byte[] { 1, 2, (byte) 255 }) }); + reference.put("(1h;2h;3h)", new Object[] { new short[] { 1, 2, 3 }, new Short[] { 1, 2, 3 }, Arrays.asList(new Short[] { 1, 2, 3 }) }); + reference.put("1 2 3", new Object[] { new long[] { 1, 2, 3 }, new Long[] { 1L, 2L, 3L }, Arrays.asList(new Long[] { 1L, 2L, 3L }) }); + reference.put("(1i;2i;3i)", new Object[] { new int[] { 1, 2, 3 }, new Integer[] { 1, 2, 3 }, Arrays.asList(new Integer[] { 1, 2, 3 }) }); + reference.put("(1j;2j;3j)", new Object[] { new long[] { 1, 2, 3 }, new Long[] { 1L, 2L, 3L }, Arrays.asList(new Long[] { 1L, 2L, 3L }) }); + reference.put("(5.5e; 8.5e)", new Object[] { new float[] { 5.5f, 8.5f }, new Float[] { 5.5f, 8.5f }, Arrays.asList(new Float[] { 5.5f, 8.5f }) }); + reference.put("3.23 6.46", new Object[] { new double[] { 3.23, 6.46 }, new Double[] { 3.23, 6.46 }, Arrays.asList(new Double[] { 3.23, 6.46 }) }); reference.put("(1;`bcd;\"0bc\";5.5e)", new Object[] { new Object[] { 1L, "bcd", "0bc".toCharArray(), (float) 5.5 } }); reference.put("(42;::;`foo)", new Object[] { new Object[] { 42L, null, "foo" } }); reference.put("(enlist 1h; 2; enlist 3j)", new Object[] { new Object[] { new short[] { 1 }, 2L, new long[] { 3 } } }); - reference.put("`the`quick`brown`fox", new Object[] { new String[] { "the", "quick", "brown", "fox" } }); - reference.put("``quick``fox", new Object[] { new String[] { "", "quick", "", "fox" } }); - reference.put("``", new Object[] { new String[] { "", "" } }); - reference.put("(\"quick\"; \"brown\"; \"fox\"; \"jumps\"; \"over\"; \"a lazy\"; \"dog\")", - new Object[] { new Object[] { "quick".toCharArray(), "brown".toCharArray(), "fox".toCharArray(), "jumps".toCharArray(), "over".toCharArray(), - "a lazy".toCharArray(), "dog".toCharArray() } }); + reference.put("`the`quick`brown`fox", + new Object[] { new String[] { "the", "quick", "brown", "fox" }, Arrays.asList(new String[] { "the", "quick", "brown", "fox" }) }); + reference.put("``quick``fox", new Object[] { new String[] { "", "quick", "", "fox" }, Arrays.asList(new String[] { "", "quick", "", "fox" }) }); + reference.put("``", new Object[] { new String[] { "", "" }, Arrays.asList(new String[] { "", "" }) }); + reference.put( + "(\"quick\"; \"brown\"; \"fox\"; \"jumps\"; \"over\"; \"a lazy\"; \"dog\")", + new Object[] { + new Object[] { "quick".toCharArray(), "brown".toCharArray(), "fox".toCharArray(), "jumps".toCharArray(), "over".toCharArray(), + "a lazy".toCharArray(), "dog".toCharArray() }, + Arrays.asList(new Object[] { "quick".toCharArray(), "brown".toCharArray(), "fox".toCharArray(), "jumps".toCharArray(), + "over".toCharArray(), "a lazy".toCharArray(), "dog".toCharArray() }) }); reference.put("(\"quick\"; \"brown\"; \"fox\")", new Object[] { new char[][] { "quick".toCharArray(), "brown".toCharArray(), "fox".toCharArray() } }); reference.put("2000.01.04D05:36:57.600 0Np", new Object[] { new QTimestamp[] { new QTimestamp(279417600000000L), new QTimestamp(Long.MIN_VALUE) } }); reference.put("(2001.01m; 0Nm)", new Object[] { new QMonth[] { new QMonth(12), new QMonth(Integer.MIN_VALUE) } });