diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ce5193d..0a936e5 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,10 @@ +------------------------------------------------------------------------------ + qJava 2.3.1 [2015.12.x] +------------------------------------------------------------------------------ + + - API redesign: visibility of QType.getTypeCode() method changed to public + - Maps serialization support in DefaultQWriter + ------------------------------------------------------------------------------ qJava 2.3.0 [2015.11.16] ------------------------------------------------------------------------------ diff --git a/doc/Type-conversion.md b/doc/Type-conversion.md index a76d7d9..05a8c81 100644 --- a/doc/Type-conversion.md +++ b/doc/Type-conversion.md @@ -68,6 +68,9 @@ new ArrayList(Arrays.asList(new Object[] { null, 2, 3, "test" })); // se new ArrayList(Arrays.asList(new Object[] { 1, "test" })); // serialization error, assumed to be integer-only list ``` +`DefaultQWriter` supports serialization of Java `Map`s. Note that, keys and values of the map are serialized as q +general lists. + ### 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 55d017e..7df3470 100644 --- a/src/main/java/com/exxeleron/qjava/DefaultQWriter.java +++ b/src/main/java/com/exxeleron/qjava/DefaultQWriter.java @@ -35,6 +35,8 @@ public class DefaultQWriter extends QWriter { protected void writeObject( final Object obj ) throws IOException, QException { if ( obj instanceof Collection ) { writeCollection((Collection) obj); + } else if ( obj instanceof Map ) { + writeMap((Map) obj); } else { final QType qtype = getQType(obj); checkProtocolVersionCompatibility(qtype); @@ -73,58 +75,58 @@ protected void writeAtom( final Object obj, final QType qtype ) throws IOExcepti switch ( qtype ) { case BOOL: writer.writeByte((byte) ((Boolean) obj ? 1 : 0)); - break; + break; case GUID: writeGuid((UUID) obj); - break; + break; case BYTE: writer.writeByte((Byte) obj); - break; + break; case SHORT: writer.writeShort((Short) obj); - break; + break; case INT: writer.writeInt((Integer) obj); - break; + break; case LONG: writer.writeLong((Long) obj); - break; + break; case FLOAT: writer.writeFloat((Float) obj); - break; + break; case DOUBLE: writer.writeDouble((Double) obj); - break; + break; case CHAR: writer.writeByte((byte) (char) (Character) obj); - break; + break; case SYMBOL: writeSymbol((String) obj); - break; + break; case TIMESTAMP: writer.writeLong(((QTimestamp) obj).getValue()); - break; + break; case MONTH: writer.writeInt(((QMonth) obj).getValue()); - break; + break; case DATE: writer.writeInt(((QDate) obj).getValue()); - break; + break; case DATETIME: writer.writeDouble(((QDateTime) obj).getValue()); - break; + break; case TIMESPAN: writer.writeLong(((QTimespan) obj).getValue()); - break; + break; case MINUTE: writer.writeInt(((QMinute) obj).getValue()); - break; + break; case SECOND: writer.writeInt(((QSecond) obj).getValue()); - break; + break; case TIME: writer.writeInt(((QTime) obj).getValue()); - break; + break; } } @@ -414,7 +416,7 @@ protected void writeCollection( final Collection collection ) throws IOExcept for ( final Object e : collection ) { writer.writeInt(((QMonth) e).getValue()); } - break; + break; case DATE_LIST: { for ( final Object e : collection ) { writer.writeInt(((QDate) e).getValue()); @@ -503,6 +505,25 @@ protected void writeDictionary( final QDictionary d ) throws IOException, QExcep writeObject(d.getValues()); } + protected void writeMap( final Map m ) throws IOException, QException { + writer.writeByte(QType.DICTIONARY.getTypeCode()); + writer.writeByte(QType.GENERAL_LIST.getTypeCode()); + writer.writeByte((byte) 0); // attributes + writer.writeInt(m.size()); + + for ( final Object key : m.keySet() ) { + writeObject(key); + } + + writer.writeByte(QType.GENERAL_LIST.getTypeCode()); + writer.writeByte((byte) 0); // attributes + writer.writeInt(m.size()); + + for ( final Object key : m.keySet() ) { + writeObject(m.get(key)); + } + } + protected void writeTable( final QTable t ) throws IOException, QException { writer.writeByte(QType.TABLE.getTypeCode()); writer.writeByte((byte) 0); // attributes diff --git a/src/test/java/com/exxeleron/qjava/QExpressions.java b/src/test/java/com/exxeleron/qjava/QExpressions.java index 2267c5f..abd4d45 100644 --- a/src/test/java/com/exxeleron/qjava/QExpressions.java +++ b/src/test/java/com/exxeleron/qjava/QExpressions.java @@ -31,6 +31,7 @@ class QExpressions { private final Map reference = new LinkedHashMap(); + @SuppressWarnings("serial") private void initExpressions() throws QException { reference.put("1+`", new Object[] { new QException("type") }); reference.put("()", new Object[] { new Object[0] }); @@ -116,8 +117,18 @@ private void initExpressions() throws QException { reference.put("(`x`y!(`a;2))", new Object[] { new QDictionary(new String[] { "x", "y" }, new Object[] { "a", 2L }) }); reference.put("`abc`def`gh!([] one: 1 2 3; two: 4 5 6)", new Object[] { new QDictionary(new String[] { "abc", "def", "gh" }, new QTable( new String[] { "one", "two" }, new Object[] { new long[] { 1, 2, 3 }, new long[] { 4, 5, 6 } })) }); - reference.put("(1;2h;3.3;\"4\")!(`one;2 3;\"456\";(7;8 9))", new Object[] { new QDictionary(new Object[] { 1L, (short) 2, 3.3, '4' }, - new Object[] { "one", new long[] { 2, 3 }, "456".toCharArray(), new Object[] { 7L, new long[] { 8, 9 } } }) }); + reference.put("(1;2h;3.3;\"4\")!(`one;2 3;\"456\";(7;8 9))", new Object[] { + new QDictionary(new Object[] { 1L, (short) 2, 3.3, '4' }, + new Object[] { "one", new long[] { 2, 3 }, "456".toCharArray(), + new Object[] { 7L, new long[] { 8, 9 } } }), + new LinkedHashMap() { + { + put(1L, "one"); + put((short) 2, new long[] { 2, 3 }); + put(3.3, "456".toCharArray()); + put('4', new Object[] { 7L, new long[] { 8, 9 } }); + } + } }); reference.put("(0 1; 2 3)!`first`second", new Object[] { new QDictionary(new Object[] { new long[] { 0, 1 }, new long[] { 2, 3 } }, new String[] { "first", "second" }) }); reference.put("`A`B`C!((1;2.2;3);(`x`y!(`a;2));5.5)", new Object[] { new QDictionary(new String[] { "A", "B", "C" },