Skip to content

Commit 26dcf22

Browse files
committed
added experimental JSON packer
1 parent 28f8155 commit 26dcf22

4 files changed

Lines changed: 319 additions & 0 deletions

File tree

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
//
2+
// MessagePack for Java
3+
//
4+
// Copyright (C) 2009-2011 FURUHASHI Sadayuki
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
package org.msgpack.packer;
19+
20+
import java.io.IOException;
21+
import java.nio.ByteBuffer;
22+
import java.math.BigInteger;
23+
import org.msgpack.io.Output;
24+
import org.msgpack.MessagePack;
25+
import org.msgpack.MessageTypeException;
26+
27+
28+
public abstract class AbstractJSONPacker extends Packer {
29+
private static final byte[] NULL = new byte[] { 0x6e, 0x75, 0x6c, 0x6c };
30+
private static final byte[] TRUE = new byte[] { 0x74, 0x72, 0x75, 0x65 };
31+
private static final byte[] FALSE = new byte[] { 0x66, 0x61, 0x6c, 0x73, 0x65 };
32+
private static final byte COMMA = 0x2c;
33+
private static final byte COLON = 0x3a;
34+
private static final byte QUOTE = 0x22;
35+
private static final byte LEFT_BR = 0x5b;
36+
private static final byte RIGHT_BR = 0x5d;
37+
private static final byte LEFT_WN = 0x7b;
38+
private static final byte RIGHT_WN = 0x7d;
39+
40+
private static final int FLAG_FIRST_ELEMENT = 0x01;
41+
private static final int FLAG_MAP_KEY = 0x02;
42+
private static final int FLAG_MAP_VALUE = 0x04;
43+
private static final int FLAG_MAP = FLAG_MAP_KEY | FLAG_MAP_VALUE;
44+
45+
protected final Output out;
46+
private int[] flags;
47+
48+
private PackerStack stack = new PackerStack();
49+
50+
protected AbstractJSONPacker(MessagePack msgpack, Output out) {
51+
super(msgpack);
52+
this.out = out;
53+
this.stack = new PackerStack();
54+
this.flags = new int[PackerStack.MAX_STACK_SIZE];
55+
}
56+
57+
public void writeNil() throws IOException {
58+
out.write(NULL, 0, NULL.length);
59+
}
60+
61+
public void writeBoolean(boolean v) throws IOException {
62+
if(v) {
63+
out.write(TRUE, 0, TRUE.length);
64+
} else {
65+
out.write(FALSE, 0, FALSE.length);
66+
}
67+
}
68+
69+
public void writeByte(byte v) throws IOException {
70+
beginElement();
71+
byte[] b = Byte.toString(v).getBytes(); // TODO optimize
72+
out.write(b, 0, b.length);
73+
endElement();
74+
}
75+
76+
public void writeShort(short v) throws IOException {
77+
beginElement();
78+
byte[] b = Short.toString(v).getBytes(); // TODO optimize
79+
out.write(b, 0, b.length);
80+
endElement();
81+
}
82+
83+
public void writeInt(int v) throws IOException {
84+
beginElement();
85+
byte[] b = Integer.toString(v).getBytes(); // TODO optimize
86+
out.write(b, 0, b.length);
87+
endElement();
88+
}
89+
90+
public void writeLong(long v) throws IOException {
91+
beginElement();
92+
byte[] b = Long.toString(v).getBytes(); // TODO optimize
93+
out.write(b, 0, b.length);
94+
endElement();
95+
}
96+
97+
public void writeBigInteger(BigInteger v) throws IOException {
98+
beginElement();
99+
byte[] b = v.toString().getBytes(); // TODO optimize
100+
out.write(b, 0, b.length);
101+
endElement();
102+
}
103+
104+
public void writeFloat(float v) throws IOException {
105+
beginElement();
106+
byte[] b = Float.toString(v).getBytes(); // TODO optimize
107+
out.write(b, 0, b.length);
108+
endElement();
109+
}
110+
111+
public void writeDouble(double v) throws IOException {
112+
beginElement();
113+
byte[] b = Double.toString(v).getBytes(); // TODO optimize
114+
out.write(b, 0, b.length);
115+
endElement();
116+
}
117+
118+
public void writeByteArray(byte[] b, int off, int len) throws IOException {
119+
beginElement();
120+
out.writeByte(QUOTE);
121+
out.write(b, off, len); // FIXME escape
122+
out.writeByte(QUOTE);
123+
endElement();
124+
}
125+
126+
public void writeByteBuffer(ByteBuffer bb) throws IOException {
127+
beginElement();
128+
out.writeByte(QUOTE);
129+
int pos = bb.position();
130+
try {
131+
out.write(bb); // FIXME escape
132+
} finally {
133+
bb.position(pos);
134+
}
135+
out.writeByte(QUOTE);
136+
endElement();
137+
}
138+
139+
public void writeString(String s) throws IOException {
140+
beginElement();
141+
byte[] b = s.getBytes();
142+
out.writeByte(QUOTE);
143+
out.write(b, 0, b.length); // FIXME escape
144+
out.writeByte(QUOTE);
145+
endElement();
146+
}
147+
148+
public void writeArrayBegin(int size) throws IOException {
149+
beginElement();
150+
out.writeByte(LEFT_BR);
151+
endElement();
152+
stack.pushArray(size);
153+
flags[stack.getDepth()] = FLAG_FIRST_ELEMENT;
154+
}
155+
156+
public void writeArrayEnd(boolean check) throws IOException {
157+
if(!stack.topIsArray()) {
158+
throw new MessageTypeException("writeArrayEnd() is called but writeArrayBegin() is not called");
159+
}
160+
161+
int remain = stack.getTopCount();
162+
if(remain > 0) {
163+
if(check) {
164+
throw new MessageTypeException("writeArrayEnd(check=true) is called but the array is not end: "+remain);
165+
}
166+
for(int i=0; i < remain; i++) {
167+
writeNil();
168+
}
169+
}
170+
stack.pop();
171+
172+
out.writeByte(RIGHT_BR);
173+
}
174+
175+
public void writeMapBegin(int size) throws IOException {
176+
beginElement();
177+
out.writeByte(LEFT_WN);
178+
endElement();
179+
stack.pushMap(size);
180+
flags[stack.getDepth()] = FLAG_FIRST_ELEMENT | FLAG_MAP_KEY;
181+
}
182+
183+
public void writeMapEnd(boolean check) throws IOException {
184+
if(!stack.topIsMap()) {
185+
throw new MessageTypeException("writeMapEnd() is called but writeMapBegin() is not called");
186+
}
187+
188+
int remain = stack.getTopCount();
189+
if(remain > 0) {
190+
if(check) {
191+
throw new MessageTypeException("writeMapEnd(check=true) is called but the map is not end: "+remain);
192+
}
193+
for(int i=0; i < remain; i++) {
194+
writeNil();
195+
}
196+
}
197+
stack.pop();
198+
199+
out.writeByte(RIGHT_WN);
200+
}
201+
202+
private void beginElement() throws IOException {
203+
int flag = flags[stack.getDepth()];
204+
if((flag & FLAG_MAP_VALUE) != 0) {
205+
out.writeByte(COLON);
206+
} else if(stack.getDepth() > 0 && (flag & FLAG_FIRST_ELEMENT) == 0) {
207+
out.writeByte(COMMA);
208+
}
209+
}
210+
211+
private void endElement() throws IOException {
212+
int flag = flags[stack.getDepth()];
213+
if((flag & FLAG_MAP_KEY) != 0) {
214+
flag &= ~FLAG_MAP_KEY;
215+
flag |= FLAG_MAP_VALUE;
216+
} else if((flag & FLAG_MAP_VALUE) != 0) {
217+
flag &= ~FLAG_MAP_VALUE;
218+
flag |= FLAG_MAP_KEY;
219+
}
220+
flag &= ~FLAG_FIRST_ELEMENT;
221+
flags[stack.getDepth()] = flag;
222+
stack.reduceCount();
223+
}
224+
}
225+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// MessagePack for Java
3+
//
4+
// Copyright (C) 2009-2011 FURUHASHI Sadayuki
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
package org.msgpack.packer;
19+
20+
import java.io.OutputStream;
21+
22+
import org.msgpack.MessagePack;
23+
import org.msgpack.io.StreamOutput;
24+
25+
26+
public class JSONStreamPacker extends AbstractJSONPacker {
27+
public JSONStreamPacker(OutputStream stream) {
28+
this(new MessagePack(), stream);
29+
}
30+
31+
public JSONStreamPacker(MessagePack msgpack, OutputStream stream) {
32+
super(msgpack, new StreamOutput(stream));
33+
}
34+
}
35+

src/main/java/org/msgpack/unpacker/Converter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ public byte[] readByteArray() {
140140
return raw;
141141
}
142142

143+
@Override
144+
public String readString() {
145+
String str = getTop().asRawValue().getString();
146+
stack.reduceCount();
147+
return str;
148+
}
149+
143150
@Override
144151
public int readArrayBegin() {
145152
Value v = getTop();
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.msgpack;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertTrue;
5+
6+
import java.math.BigInteger;
7+
import java.nio.ByteBuffer;
8+
import java.io.IOException;
9+
import java.io.ByteArrayOutputStream;
10+
import java.util.ArrayList;
11+
import java.util.HashMap;
12+
import java.util.Iterator;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
import org.junit.Test;
17+
import org.msgpack.MessagePack;
18+
import org.msgpack.packer.JSONStreamPacker;
19+
import org.msgpack.type.Value;
20+
import org.msgpack.type.ValueFactory;
21+
22+
import org.junit.Test;
23+
24+
public class TestSimpleJSONPackUnpack {
25+
@Test
26+
public void testSimplePackUnpack() throws IOException {
27+
MessagePack msgpack = new MessagePack();
28+
ByteArrayOutputStream bo = new ByteArrayOutputStream();
29+
30+
JSONStreamPacker pk = new JSONStreamPacker(msgpack, bo);
31+
32+
pk.write(
33+
ValueFactory.mapValue(new Value[] {
34+
ValueFactory.rawValue("k1"),
35+
ValueFactory.integerValue(1),
36+
ValueFactory.rawValue("k2"),
37+
ValueFactory.arrayValue(new Value[] {
38+
ValueFactory.rawValue("a"),
39+
ValueFactory.rawValue("b"),
40+
ValueFactory.rawValue("c")
41+
}),
42+
ValueFactory.rawValue("k3"),
43+
ValueFactory.floatValue(0.1)
44+
}));
45+
46+
byte[] raw = bo.toByteArray();
47+
48+
String str = new String(raw);
49+
assertEquals("{\"k1\":1,\"k2\":[\"a\",\"b\",\"c\"],\"k3\":0.1}", str);
50+
}
51+
}
52+

0 commit comments

Comments
 (0)