Skip to content

Commit 03bf494

Browse files
committed
Parameterize decoder base types.
1 parent eaa0d81 commit 03bf494

File tree

8 files changed

+101
-60
lines changed

8 files changed

+101
-60
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,14 +507,12 @@ This code would produce the following output:
507507

508508
String values are automatically wrapped in double-quotes and escaped. Instances of `java.util.Date` are encoded as a long value representing epoch time. All other values are encoded via `toString()`.
509509

510-
`CSVDecoder` deserializes a CSV document into an iterable sequence of maps. Rather than loading the entire payload into memory and returning the data as a list, `CSVDecoder` returns the data as a forward-scrolling cursor, allowing consumers to process rows as soon as they are read.
511-
512-
For example, given the CSV above as input, the following code would produce the same results as `JSONDecoder` example:
510+
`CSVDecoder` deserializes a CSV document into an iterable sequence of maps. For example, given the preceding CSV as input, the following code would produce the same output as the earlier `JSONDecoder` example:
513511

514512
```java
515513
CSVDecoder csvDecoder = new CSVDecoder();
516514

517-
Iterable<Map<String, String>> months = csvDecoder.read(inputStream);
515+
List<Map<String, String>> months = csvDecoder.read(inputStream);
518516

519517
for (Map<String, String> month : months) {
520518
System.out.println(String.format("%s has %d days", month.get("name"), month.get("days")));

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
subprojects {
1616
group = 'org.httprpc'
17-
version = '8.2.4'
17+
version = '8.3'
1818

1919
apply plugin: 'java-library'
2020
apply plugin: 'maven-publish'

httprpc-client/src/main/java/org/httprpc/io/CSVDecoder.java

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package org.httprpc.io;
1616

1717
import java.io.IOException;
18-
import java.io.InputStream;
1918
import java.io.Reader;
2019
import java.nio.charset.StandardCharsets;
2120
import java.util.ArrayList;
@@ -24,28 +23,24 @@
2423
import java.util.List;
2524
import java.util.Map;
2625
import java.util.NoSuchElementException;
27-
import java.util.stream.Stream;
26+
import java.util.stream.Collectors;
2827
import java.util.stream.StreamSupport;
2928

3029
/**
3130
* CSV decoder.
3231
*/
33-
@SuppressWarnings("unchecked")
34-
public class CSVDecoder extends Decoder {
35-
/**
36-
* CSV cursor.
37-
*/
38-
public static class Cursor implements Iterable<Map<String, String>> {
39-
private Reader reader;
40-
private char delimiter;
32+
public class CSVDecoder extends Decoder<Iterable<Map<String, String>>> {
33+
private static class Cursor implements Iterable<Map<String, String>> {
34+
Reader reader;
35+
char delimiter;
4136

42-
private StringBuilder valueBuilder = new StringBuilder();
37+
StringBuilder valueBuilder = new StringBuilder();
4338

44-
private List<String> keys = new ArrayList<>();
45-
private List<String> values = new ArrayList<>();
39+
List<String> keys = new ArrayList<>();
40+
List<String> values = new ArrayList<>();
4641

47-
private Iterator<Map<String, String>> iterator = new Iterator<Map<String, String>>() {
48-
private Boolean hasNext = null;
42+
Iterator<Map<String, String>> iterator = new Iterator<Map<String, String>>() {
43+
Boolean hasNext = null;
4944

5045
@Override
5146
public boolean hasNext() {
@@ -94,14 +89,14 @@ public Map<String, String> next() {
9489
}
9590
};
9691

97-
private Cursor(Reader reader, char delimiter) throws IOException {
92+
Cursor(Reader reader, char delimiter) throws IOException {
9893
this.reader = reader;
9994
this.delimiter = delimiter;
10095

10196
readValues(reader, keys, delimiter);
10297
}
10398

104-
private void readValues(Reader reader, List<String> values, char delimiter) throws IOException {
99+
void readValues(Reader reader, List<String> values, char delimiter) throws IOException {
105100
int c = reader.read();
106101

107102
while (c != '\r' && c != '\n' && c != EOF) {
@@ -153,46 +148,59 @@ private void readValues(Reader reader, List<String> values, char delimiter) thro
153148
public Iterator<Map<String, String>> iterator() {
154149
return iterator;
155150
}
156-
157-
/**
158-
* Returns a stream over the results.
159-
*
160-
* @return
161-
* A stream over the results.
162-
*/
163-
public Stream<Map<String, String>> stream() {
164-
return StreamSupport.stream(spliterator(), false);
165-
}
166151
}
167152

153+
private boolean cursor;
168154
private char delimiter;
169155

170156
/**
171157
* Constructs a new CSV decoder.
172158
*/
173159
public CSVDecoder() {
174-
this(',');
160+
this(false);
161+
}
162+
163+
/**
164+
* Constructs a new CSV decoder.
165+
*
166+
* @param cursor
167+
* <code>true</code> if the results should be returned as a scrolling cursor;
168+
* <code>false</code>, otherwise.
169+
*/
170+
public CSVDecoder(boolean cursor) {
171+
this(cursor, ',');
175172
}
176173

177174
/**
178175
* Constructs a new CSV decoder.
179176
*
177+
* @param cursor
178+
* <code>true</code> if the results should be returned as a scrolling cursor;
179+
* <code>false</code>, otherwise.
180+
*
180181
* @param delimiter
181182
* The character to use as a field delimiter.
182183
*/
183-
public CSVDecoder(char delimiter) {
184+
public CSVDecoder(boolean cursor, char delimiter) {
184185
super(StandardCharsets.ISO_8859_1);
185186

187+
this.cursor = cursor;
186188
this.delimiter = delimiter;
187189
}
188190

189191
@Override
190-
public Cursor read(InputStream inputStream) throws IOException {
191-
return super.read(inputStream);
192-
}
192+
@SuppressWarnings("unchecked")
193+
public <U extends Iterable<Map<String, String>>> U read(Reader reader) throws IOException {
194+
if (reader == null) {
195+
throw new IllegalArgumentException();
196+
}
193197

194-
@Override
195-
public Cursor read(Reader reader) throws IOException {
196-
return new Cursor(new BufferedReader(reader), delimiter);
198+
Cursor cursor = new Cursor(new BufferedReader(reader), delimiter);
199+
200+
if (this.cursor) {
201+
return (U)cursor;
202+
} else {
203+
return (U)StreamSupport.stream(cursor.spliterator(), false).collect(Collectors.toList());
204+
}
197205
}
198206
}

httprpc-client/src/main/java/org/httprpc/io/Decoder.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222

2323
/**
2424
* Abstract base class for decoders.
25+
*
26+
* @param <T>
27+
* The type of value produced by the decoder.
2528
*/
26-
public abstract class Decoder {
29+
public abstract class Decoder<T> {
2730
private Charset charset;
2831

2932
protected static final int EOF = -1;
@@ -34,7 +37,7 @@ public abstract class Decoder {
3437
* @param charset
3538
* The character set to use when decoding an input stream.
3639
*/
37-
protected Decoder(Charset charset) {
40+
public Decoder(Charset charset) {
3841
if (charset == null) {
3942
throw new IllegalArgumentException();
4043
}
@@ -55,8 +58,8 @@ public Charset getCharset() {
5558
/**
5659
* Reads a value from an input stream.
5760
*
58-
* @param <T>
59-
* The value type.
61+
* @param <U>
62+
* The decoded value type.
6063
*
6164
* @param inputStream
6265
* The input stream to read from.
@@ -67,7 +70,7 @@ public Charset getCharset() {
6770
* @throws IOException
6871
* If an exception occurs.
6972
*/
70-
public <T> T read(InputStream inputStream) throws IOException {
73+
public <U extends T> U read(InputStream inputStream) throws IOException {
7174
if (inputStream == null) {
7275
throw new IllegalArgumentException();
7376
}
@@ -78,8 +81,8 @@ public <T> T read(InputStream inputStream) throws IOException {
7881
/**
7982
* Reads a value from a character stream.
8083
*
81-
* @param <T>
82-
* The value type.
84+
* @param <U>
85+
* The decoded value type.
8386
*
8487
* @param reader
8588
* The character stream to read from.
@@ -90,5 +93,5 @@ public <T> T read(InputStream inputStream) throws IOException {
9093
* @throws IOException
9194
* If an exception occurs.
9295
*/
93-
public abstract <T> T read(Reader reader) throws IOException;
96+
public abstract <U extends T> U read(Reader reader) throws IOException;
9497
}

httprpc-client/src/main/java/org/httprpc/io/Encoder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* Abstract base class for encoders.
2525
*
2626
* @param <T>
27-
* The value type.
27+
* The type of value consumed by the encoder.
2828
*/
2929
public abstract class Encoder<T> {
3030
private Charset charset;
@@ -35,7 +35,7 @@ public abstract class Encoder<T> {
3535
* @param charset
3636
* The character set to use when encoding an output stream.
3737
*/
38-
protected Encoder(Charset charset) {
38+
public Encoder(Charset charset) {
3939
if (charset == null) {
4040
throw new IllegalArgumentException();
4141
}

httprpc-client/src/main/java/org/httprpc/io/JSONDecoder.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/**
2929
* JSON decoder.
3030
*/
31-
public class JSONDecoder extends Decoder {
31+
public class JSONDecoder extends Decoder<Object> {
3232
private boolean sorted;
3333

3434
private int c = EOF;
@@ -63,7 +63,11 @@ public JSONDecoder(boolean sorted) {
6363

6464
@Override
6565
@SuppressWarnings("unchecked")
66-
public <T> T read(Reader reader) throws IOException {
66+
public <U> U read(Reader reader) throws IOException {
67+
if (reader == null) {
68+
throw new IllegalArgumentException();
69+
}
70+
6771
reader = new BufferedReader(reader);
6872

6973
Object value = null;
@@ -160,7 +164,7 @@ public <T> T read(Reader reader) throws IOException {
160164
skipWhitespace(reader);
161165
}
162166

163-
return (T)value;
167+
return (U)value;
164168
}
165169

166170
private void skipWhitespace(Reader reader) throws IOException {

httprpc-client/src/main/java/org/httprpc/io/TextDecoder.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@
1919
import java.nio.charset.Charset;
2020
import java.nio.charset.StandardCharsets;
2121

22-
@SuppressWarnings("unchecked")
23-
public class TextDecoder extends Decoder {
22+
/**
23+
* Text decoder.
24+
*/
25+
public class TextDecoder extends Decoder<CharSequence> {
26+
private boolean builder;
27+
2428
/**
2529
* Constructs a new text decoder.
2630
*/
@@ -35,11 +39,32 @@ public TextDecoder() {
3539
* The character set to use when decoding the text.
3640
*/
3741
public TextDecoder(Charset charset) {
42+
this(charset, false);
43+
}
44+
45+
/**
46+
* Constructs a new text decoder.
47+
*
48+
* @param charset
49+
* The character set to use when decoding the text.
50+
*
51+
* @param builder
52+
* <code>true</code> if the result should be returned as a mutable builder;
53+
* <code>false</code>, otherwise.
54+
*/
55+
public TextDecoder(Charset charset, boolean builder) {
3856
super(charset);
57+
58+
this.builder = builder;
3959
}
4060

4161
@Override
42-
public String read(Reader reader) throws IOException {
62+
@SuppressWarnings("unchecked")
63+
public <U extends CharSequence> U read(Reader reader) throws IOException {
64+
if (reader == null) {
65+
throw new IllegalArgumentException();
66+
}
67+
4368
reader = new BufferedReader(reader);
4469

4570
StringBuilder stringBuilder = new StringBuilder();
@@ -49,6 +74,10 @@ public String read(Reader reader) throws IOException {
4974
stringBuilder.append((char)c);
5075
}
5176

52-
return stringBuilder.toString();
77+
if (builder) {
78+
return (U)stringBuilder;
79+
} else {
80+
return (U)stringBuilder.toString();
81+
}
5382
}
5483
}

httprpc-client/src/test/java/org/httprpc/io/CSVDecoderTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.List;
2222
import java.util.Map;
2323
import java.util.stream.Collectors;
24+
import java.util.stream.StreamSupport;
2425

2526
import static org.httprpc.util.Collections.entry;
2627
import static org.httprpc.util.Collections.listOf;
@@ -58,8 +59,6 @@ public void testRead() throws IOException {
5859

5960
CSVDecoder csvDecoder = new CSVDecoder();
6061

61-
List<Map<String, String>> actual = csvDecoder.read(reader).stream().collect(Collectors.toList());
62-
63-
assertEquals(expected, actual);
62+
assertEquals(expected, csvDecoder.read(reader));
6463
}
6564
}

0 commit comments

Comments
 (0)