Skip to content

Commit 486e1b8

Browse files
committed
#37 Support binary format
1 parent 93ad14c commit 486e1b8

File tree

16 files changed

+538
-23
lines changed

16 files changed

+538
-23
lines changed

jsurfer-all/pom.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,31 @@
3636
<artifactId>jsurfer-jackson</artifactId>
3737
<version>${project.version}</version>
3838
</dependency>
39+
<dependency>
40+
<groupId>com.fasterxml.jackson.dataformat</groupId>
41+
<artifactId>jackson-dataformat-cbor</artifactId>
42+
<version>${jackson.version}</version>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.fasterxml.jackson.dataformat</groupId>
46+
<artifactId>jackson-dataformat-smile</artifactId>
47+
<version>${jackson.version}</version>
48+
</dependency>
49+
<dependency>
50+
<groupId>com.fasterxml.jackson.dataformat</groupId>
51+
<artifactId>jackson-dataformat-ion</artifactId>
52+
<version>${jackson.version}</version>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.fasterxml.jackson.dataformat</groupId>
56+
<artifactId>jackson-dataformat-protobuf</artifactId>
57+
<version>${jackson.version}</version>
58+
</dependency>
59+
<dependency>
60+
<groupId>com.fasterxml.jackson.dataformat</groupId>
61+
<artifactId>jackson-dataformat-avro</artifactId>
62+
<version>${jackson.version}</version>
63+
</dependency>
3964
<dependency>
4065
<groupId>com.github.jsurfer</groupId>
4166
<artifactId>jsurfer-jsonsimple</artifactId>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.jsfr.json;
2+
3+
public class Employee {
4+
public String name;
5+
public int age;
6+
public String[] emails;
7+
public Employee boss;
8+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.jsfr.json;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
6+
import org.jsfr.json.provider.JacksonProvider;
7+
import org.junit.Before;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.IOException;
11+
import java.io.InputStream;
12+
13+
public class JacksonCBORParserTest extends JsonSurferTest {
14+
15+
@Before
16+
public void setUp() throws Exception {
17+
provider = new JacksonProvider();
18+
surfer = new JsonSurfer(new JacksonParser(new CBORFactory()), provider);
19+
}
20+
21+
@Override
22+
protected InputStream read(String resourceName) throws IOException {
23+
ObjectMapper om = new ObjectMapper();
24+
JsonNode node = om.readTree(this.readAsString(resourceName));
25+
CBORFactory f = new CBORFactory();
26+
ObjectMapper cborMapper = new ObjectMapper(f);
27+
byte[] cborData = cborMapper.writeValueAsBytes(node);
28+
return new ByteArrayInputStream(cborData);
29+
}
30+
31+
@Override
32+
public void testCollectAllFromString() throws Exception {
33+
// skip non-byte-based source
34+
}
35+
36+
@Override
37+
public void testCollectOneFromString() throws Exception {
38+
// skip non-byte-based source
39+
}
40+
41+
@Override
42+
public void testWildcardAtRoot() throws Exception {
43+
// skip non-byte-based source
44+
}
45+
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.jsfr.json;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.dataformat.ion.IonFactory;
6+
import org.jsfr.json.provider.JacksonProvider;
7+
import org.junit.Before;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.IOException;
11+
import java.io.InputStream;
12+
13+
public class JacksonIonParserTest extends JsonSurferTest {
14+
15+
@Before
16+
public void setUp() throws Exception {
17+
provider = new JacksonProvider();
18+
surfer = new JsonSurfer(new JacksonParser(new IonFactory()), provider);
19+
}
20+
21+
@Override
22+
protected InputStream read(String resourceName) throws IOException {
23+
ObjectMapper om = new ObjectMapper();
24+
JsonNode node = om.readTree(this.readAsString(resourceName));
25+
IonFactory f = new IonFactory();
26+
ObjectMapper cborMapper = new ObjectMapper(f);
27+
byte[] ionData = cborMapper.writeValueAsBytes(node);
28+
return new ByteArrayInputStream(ionData);
29+
}
30+
31+
@Override
32+
public void testCollectAllFromString() throws Exception {
33+
// skip non-byte-based source
34+
}
35+
36+
@Override
37+
public void testCollectOneFromString() throws Exception {
38+
// skip non-byte-based source
39+
}
40+
41+
@Override
42+
public void testWildcardAtRoot() throws Exception {
43+
// skip non-byte-based source
44+
}
45+
46+
}

jsurfer-all/src/test/java/org/jsfr/json/JacksonParserTest.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,22 @@
2424

2525
package org.jsfr.json;
2626

27+
import com.fasterxml.jackson.databind.ObjectMapper;
28+
import com.fasterxml.jackson.dataformat.avro.AvroFactory;
29+
import com.fasterxml.jackson.dataformat.avro.AvroMapper;
30+
import com.fasterxml.jackson.dataformat.avro.AvroSchema;
31+
import com.fasterxml.jackson.dataformat.protobuf.ProtobufFactory;
32+
import com.fasterxml.jackson.dataformat.protobuf.ProtobufMapper;
33+
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchema;
34+
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader;
35+
import org.apache.avro.Schema;
2736
import org.jsfr.json.provider.JacksonProvider;
2837
import org.junit.Before;
38+
import org.junit.Ignore;
2939
import org.junit.Test;
3040

41+
import java.io.ByteArrayInputStream;
42+
3143
import static org.junit.Assert.assertFalse;
3244
import static org.junit.Assert.assertTrue;
3345
import static org.mockito.Matchers.any;
@@ -64,4 +76,70 @@ public void testNonBlockingParser() throws Exception {
6476
verify(mockListener).onValue(eq(provider.primitive("abcd")), any(ParsingContext.class));
6577
}
6678

79+
@Ignore
80+
@Test
81+
public void testProtobufParser() throws Exception {
82+
JsonPathListener mockListener = mock(JsonPathListener.class);
83+
84+
ObjectMapper mapper = new ProtobufMapper();
85+
String protobuf_str = "message Employee {\n"
86+
+ " required string name = 1;\n"
87+
+ " required int32 age = 2;\n"
88+
+ " repeated string emails = 3;\n"
89+
+ " optional Employee boss = 4;\n"
90+
+ "}\n";
91+
final ProtobufSchema schema = ProtobufSchemaLoader.std.parse(protobuf_str);
92+
93+
// Employee boss = new Employee();
94+
// boss.age = 30;
95+
// boss.emails = new String[]{"bar@gmail.com"};
96+
// boss.name = "bar";
97+
98+
Employee empl = new Employee();
99+
empl.age = 30;
100+
empl.emails = new String[]{"foo@gmail.com"};
101+
empl.name = "foo";
102+
// empl.boss = boss;
103+
104+
byte[] protobufData = mapper.writer(schema)
105+
.writeValueAsBytes(empl);
106+
107+
// TODO Jackson's bug
108+
JsonSurfer protobufSurfer = new JsonSurfer(new JacksonParser(new ProtobufFactory(), schema), provider);
109+
SurfingConfiguration config = protobufSurfer.configBuilder().bind("$.name", mockListener).build();
110+
protobufSurfer.surf(new ByteArrayInputStream(protobufData), config);
111+
verify(mockListener).onValue(eq(provider.primitive("foo")), any(ParsingContext.class));
112+
}
113+
114+
@Test
115+
public void testAvroParser() throws Exception {
116+
JsonPathListener mockListener = mock(JsonPathListener.class);
117+
118+
String SCHEMA_JSON = "{\n"
119+
+ "\"type\": \"record\",\n"
120+
+ "\"name\": \"Employee\",\n"
121+
+ "\"fields\": [\n"
122+
+ " {\"name\": \"name\", \"type\": \"string\"},\n"
123+
+ " {\"name\": \"age\", \"type\": \"int\"},\n"
124+
+ " {\"name\": \"emails\", \"type\": {\"type\": \"array\", \"items\": \"string\"}},\n"
125+
+ " {\"name\": \"boss\", \"type\": [\"Employee\",\"null\"]}\n"
126+
+ "]}";
127+
Schema raw = new Schema.Parser().setValidate(true).parse(SCHEMA_JSON);
128+
final AvroSchema schema = new AvroSchema(raw);
129+
130+
Employee empl = new Employee();
131+
empl.age = 30;
132+
empl.emails = new String[]{"foo@gmail.com"};
133+
empl.name = "foo";
134+
135+
AvroMapper mapper = new AvroMapper();
136+
byte[] avroData = mapper.writer(schema)
137+
.writeValueAsBytes(empl);
138+
139+
JsonSurfer avroSurfer = new JsonSurfer(new JacksonParser(new AvroFactory(), schema), provider);
140+
SurfingConfiguration config = avroSurfer.configBuilder().bind("$.name", mockListener).build();
141+
avroSurfer.surf(new ByteArrayInputStream(avroData), config);
142+
verify(mockListener).onValue(eq(provider.primitive("foo")), any(ParsingContext.class));
143+
}
144+
67145
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.jsfr.json;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
6+
import org.jsfr.json.provider.JacksonProvider;
7+
import org.junit.Before;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.IOException;
11+
import java.io.InputStream;
12+
13+
public class JacksonSmileParserTest extends JsonSurferTest {
14+
15+
@Before
16+
public void setUp() throws Exception {
17+
provider = new JacksonProvider();
18+
surfer = new JsonSurfer(new JacksonParser(new SmileFactory()), provider);
19+
}
20+
21+
@Override
22+
protected InputStream read(String resourceName) throws IOException {
23+
ObjectMapper om = new ObjectMapper();
24+
JsonNode node = om.readTree(this.readAsString(resourceName));
25+
SmileFactory f = new SmileFactory();
26+
ObjectMapper cborMapper = new ObjectMapper(f);
27+
byte[] smileData = cborMapper.writeValueAsBytes(node);
28+
return new ByteArrayInputStream(smileData);
29+
}
30+
31+
@Override
32+
public void testCollectAllFromString() throws Exception {
33+
// skip non-byte-based source
34+
}
35+
36+
@Override
37+
public void testCollectOneFromString() throws Exception {
38+
// skip non-byte-based source
39+
}
40+
41+
@Override
42+
public void testWildcardAtRoot() throws Exception {
43+
// skip non-byte-based source
44+
}
45+
46+
}

jsurfer-all/src/test/java/org/jsfr/json/JsonSurferTest.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.slf4j.LoggerFactory;
3737

3838
import java.io.IOException;
39+
import java.io.InputStream;
3940
import java.io.InputStreamReader;
4041
import java.io.Reader;
4142
import java.nio.charset.Charset;
@@ -64,6 +65,14 @@ public void onValue(Object value, ParsingContext context) {
6465
}
6566
};
6667

68+
protected InputStream read(String resourceName) throws IOException {
69+
return Resources.getResource(resourceName).openStream();
70+
}
71+
72+
protected String readAsString(String resourceName) throws IOException {
73+
return Resources.toString(Resources.getResource(resourceName), surfer.getParserCharset());
74+
}
75+
6776
@Test
6877
public void testTypeCasting() throws Exception {
6978
surfer.configBuilder()
@@ -111,15 +120,13 @@ public void testWildcardAtRoot() throws Exception {
111120

112121
@Test
113122
public void testTypeBindingOne() throws Exception {
114-
Reader reader = read("sample.json");
115-
Book book = surfer.collectOne(reader, Book.class, JsonPathCompiler.compile("$..book[1]"));
123+
Book book = surfer.collectOne(read("sample.json"), Book.class, JsonPathCompiler.compile("$..book[1]"));
116124
assertEquals("Evelyn Waugh", book.getAuthor());
117125
}
118126

119127
@Test
120128
public void testTypeBindingCollection() throws Exception {
121-
Reader reader = read("sample.json");
122-
Collection<Book> book = surfer.collectAll(reader, Book.class, JsonPathCompiler.compile("$..book[*]"));
129+
Collection<Book> book = surfer.collectAll(read("sample.json"), Book.class, JsonPathCompiler.compile("$..book[*]"));
123130
assertEquals(4, book.size());
124131
assertEquals("Nigel Rees", book.iterator().next().getAuthor());
125132
}
@@ -445,14 +452,6 @@ public void testAnyIndex() throws Exception {
445452
.onValue(anyObject(), any(ParsingContext.class));
446453
}
447454

448-
protected Reader read(String resourceName) throws IOException {
449-
return new InputStreamReader(Resources.getResource(resourceName).openStream(), Charset.forName("UTF-8"));
450-
}
451-
452-
protected String readAsString(String resourceName) throws IOException {
453-
return Resources.toString(Resources.getResource(resourceName), Charset.forName("UTF-8"));
454-
}
455-
456455
@Test
457456
public void testWildcardCombination() throws Exception {
458457
JsonPathListener mockListener = mock(JsonPathListener.class);

jsurfer-core/src/main/java/org/jsfr/json/JsonParserAdapter.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
package org.jsfr.json;
2626

27+
import java.io.InputStream;
2728
import java.io.Reader;
2829

2930
/**
@@ -36,7 +37,9 @@ public interface JsonParserAdapter {
3637
*
3738
* @param reader reader
3839
* @param context SurfingContext
40+
* @deprecated use {@link #parse(InputStream, SurfingContext)} instead
3941
*/
42+
@Deprecated
4043
void parse(Reader reader, SurfingContext context);
4144

4245
/**
@@ -47,13 +50,23 @@ public interface JsonParserAdapter {
4750
*/
4851
void parse(String json, SurfingContext context);
4952

53+
/**
54+
* Create and start a resumable parser
55+
*
56+
* @param inputStream inputStream
57+
* @param context SurfingContext
58+
*/
59+
void parse(InputStream inputStream, SurfingContext context);
60+
5061
/**
5162
* Create a resumable parser
5263
*
5364
* @param reader Json source
5465
* @param context Surfing context
5566
* @return Resumable Parser
67+
* @deprecated use {@link #createResumableParser(InputStream, SurfingContext)} instead
5668
*/
69+
@Deprecated
5770
ResumableParser createResumableParser(Reader reader, SurfingContext context);
5871

5972
/**
@@ -65,6 +78,15 @@ public interface JsonParserAdapter {
6578
*/
6679
ResumableParser createResumableParser(String json, SurfingContext context);
6780

81+
/**
82+
* Create a resumable parser
83+
*
84+
* @param json Json source
85+
* @param context Surfing context
86+
* @return Resumable Parser
87+
*/
88+
ResumableParser createResumableParser(InputStream json, SurfingContext context);
89+
6890
/**
6991
* Create a NonBlockingParser
7092
*

0 commit comments

Comments
 (0)