Skip to content

Commit b41508a

Browse files
committed
Make MapOfLists Generic
This moves the Writer interface from StreamOutput into Writeable, as a peer of its inner Reader interface. This should hopefully help to avoid random functional interfaces being created for the same purpose. It also makes use of the moved class by updating writeMapOfLists and readMapOfLists.
1 parent e171d0e commit b41508a

File tree

6 files changed

+88
-35
lines changed

6 files changed

+88
-35
lines changed

core/src/main/java/org/elasticsearch/ElasticsearchException.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public ElasticsearchException(String msg, Throwable cause, Object... args) {
101101
public ElasticsearchException(StreamInput in) throws IOException {
102102
super(in.readOptionalString(), in.readException());
103103
readStackTrace(this, in);
104-
headers.putAll(in.readMapOfLists());
104+
headers.putAll(in.readMapOfLists(StreamInput::readString, StreamInput::readString));
105105
}
106106

107107
/**
@@ -196,7 +196,7 @@ public void writeTo(StreamOutput out) throws IOException {
196196
out.writeOptionalString(this.getMessage());
197197
out.writeException(this.getCause());
198198
writeStackTraces(this, out);
199-
out.writeMapOfLists(headers);
199+
out.writeMapOfLists(headers, StreamOutput::writeString, StreamOutput::writeString);
200200
}
201201

202202
public static ElasticsearchException readException(StreamInput input, int id) throws IOException {

core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -431,27 +431,35 @@ public <K, V> Map<K, V> readMap(Writeable.Reader<K> keyReader, Writeable.Reader<
431431
return map;
432432
}
433433

434-
@Nullable
435-
@SuppressWarnings("unchecked")
436-
public Map<String, Object> readMap() throws IOException {
437-
return (Map<String, Object>) readGenericValue();
438-
}
439-
440434
/**
441-
* Read a map of strings to string lists.
435+
* Read a {@link Map} of {@code K}-type keys to {@code V}-type {@link List}s.
436+
* <pre><code>
437+
* Map&lt;String, List&lt;String&gt;&gt; map = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
438+
* </code></pre>
439+
*
440+
* @param keyReader The key reader
441+
* @param valueReader The value reader
442+
* @return Never {@code null}.
442443
*/
443-
public Map<String, List<String>> readMapOfLists() throws IOException {
444-
int size = readVInt();
444+
public <K, V> Map<K, List<V>> readMapOfLists(final Writeable.Reader<K> keyReader, final Writeable.Reader<V> valueReader)
445+
throws IOException {
446+
final int size = readVInt();
445447
if (size == 0) {
446448
return Collections.emptyMap();
447449
}
448-
Map<String, List<String>> map = new HashMap<>(size);
450+
final Map<K, List<V>> map = new HashMap<>(size);
449451
for (int i = 0; i < size; ++i) {
450-
map.put(readString(), readList(StreamInput::readString));
452+
map.put(keyReader.read(this), readList(valueReader));
451453
}
452454
return map;
453455
}
454456

457+
@Nullable
458+
@SuppressWarnings("unchecked")
459+
public Map<String, Object> readMap() throws IOException {
460+
return (Map<String, Object>) readGenericValue();
461+
}
462+
455463
@SuppressWarnings({"unchecked"})
456464
@Nullable
457465
public Object readGenericValue() throws IOException {

core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.elasticsearch.common.Nullable;
3333
import org.elasticsearch.common.bytes.BytesReference;
3434
import org.elasticsearch.common.geo.GeoPoint;
35+
import org.elasticsearch.common.io.stream.Writeable.Writer;
3536
import org.elasticsearch.common.text.Text;
3637
import org.joda.time.DateTimeZone;
3738
import org.joda.time.ReadableInstant;
@@ -413,25 +414,28 @@ public void writeMap(@Nullable Map<String, Object> map) throws IOException {
413414
}
414415

415416
/**
416-
* Writes a map of strings to string lists.
417+
* Write a {@link Map} of {@code K}-type keys to {@code V}-type {@link List}s.
418+
* <pre><code>
419+
* Map&lt;String, List&lt;String&gt;&gt; map = ...;
420+
* out.writeMapOfLists(map, StreamOutput::writeString, StreamOutput::writeString);
421+
* </code></pre>
422+
*
423+
* @param keyWriter The key writer
424+
* @param valueWriter The value writer
417425
*/
418-
public void writeMapOfLists(Map<String, List<String>> map) throws IOException {
426+
public <K, V> void writeMapOfLists(final Map<K, List<V>> map, final Writer<K> keyWriter, final Writer<V> valueWriter)
427+
throws IOException {
419428
writeVInt(map.size());
420429

421-
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
422-
writeString(entry.getKey());
430+
for (final Map.Entry<K, List<V>> entry : map.entrySet()) {
431+
keyWriter.write(this, entry.getKey());
423432
writeVInt(entry.getValue().size());
424-
for (String v : entry.getValue()) {
425-
writeString(v);
433+
for (final V value : entry.getValue()) {
434+
valueWriter.write(this, value);
426435
}
427436
}
428437
}
429438

430-
@FunctionalInterface
431-
interface Writer {
432-
void write(StreamOutput o, Object value) throws IOException;
433-
}
434-
435439
private static final Map<Class<?>, Writer> WRITERS;
436440

437441
static {

core/src/main/java/org/elasticsearch/common/io/stream/Writeable.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,69 @@
2525
* Implementers can be written to a {@linkplain StreamOutput} and read from a {@linkplain StreamInput}. This allows them to be "thrown
2626
* across the wire" using Elasticsearch's internal protocol. If the implementer also implements equals and hashCode then a copy made by
2727
* serializing and deserializing must be equal and have the same hashCode. It isn't required that such a copy be entirely unchanged.
28-
*
28+
* <p>
2929
* Prefer implementing this interface over implementing {@link Streamable} where possible. Lots of code depends on {@linkplain Streamable}
3030
* so this isn't always possible.
3131
*/
3232
public interface Writeable {
33+
3334
/**
3435
* Write this into the {@linkplain StreamOutput}.
3536
*/
36-
void writeTo(StreamOutput out) throws IOException;
37+
void writeTo(final StreamOutput out) throws IOException;
38+
39+
/**
40+
* Reference to a method that can write some object to a {@link StreamOutput}.
41+
* <p>
42+
* By convention this is a method from {@link StreamOutput} itself (e.g., {@link StreamOutput#writeString}). If the value can be
43+
* {@code null}, then the "optional" variant of methods should be used!
44+
* <p>
45+
* Most classes should implement {@link Writeable} and the {@link Writeable#writeTo(StreamOutput)} method should <em>use</em>
46+
* {@link StreamOutput} methods directly or this indirectly:
47+
* <pre><code>
48+
* public void writeTo(StreamOutput out) throws IOException {
49+
* out.writeVInt(someValue);
50+
* out.writeMapOfLists(someMap, StreamOutput::writeString, StreamOutput::writeString);
51+
* }
52+
* </code></pre>
53+
*/
54+
@FunctionalInterface
55+
interface Writer<V> {
56+
57+
/**
58+
* Write {@code V}-type {@code value} to the {@code out}put stream.
59+
*
60+
* @param out Output to write the {@code value} too
61+
* @param value The value to add
62+
*/
63+
void write(final StreamOutput out, final V value) throws IOException;
64+
65+
}
3766

3867
/**
3968
* Reference to a method that can read some object from a stream. By convention this is a constructor that takes
4069
* {@linkplain StreamInput} as an argument for most classes and a static method for things like enums. Returning null from one of these
4170
* is always wrong - for that we use methods like {@link StreamInput#readOptionalWriteable(Reader)}.
71+
* <p>
72+
* As most classes will implement this via a constructor (or a static method in the case of enumerations), it's something that should
73+
* look like:
74+
* <pre><code>
75+
* public MyClass(final StreamInput in) throws IOException {
76+
* this.someValue = in.readVInt();
77+
* this.someMap = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
78+
* }
79+
* </code></pre>
4280
*/
4381
@FunctionalInterface
44-
interface Reader<R> {
82+
interface Reader<V> {
83+
4584
/**
46-
* Read R from a stream.
85+
* Read {@code V}-type value from a stream.
86+
*
87+
* @param in Input to read the value from
4788
*/
48-
R read(StreamInput in) throws IOException;
89+
V read(final StreamInput in) throws IOException;
90+
4991
}
92+
5093
}

core/src/main/java/org/elasticsearch/common/util/concurrent/ThreadContext.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ private ThreadContextStruct(StreamInput in) throws IOException {
269269
}
270270

271271
this.requestHeaders = requestHeaders;
272-
this.responseHeaders = in.readMapOfLists();
272+
this.responseHeaders = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
273273
this.transientHeaders = Collections.emptyMap();
274274
}
275275

@@ -370,7 +370,7 @@ private void writeTo(StreamOutput out, Map<String, String> defaultHeaders) throw
370370
out.writeString(entry.getValue());
371371
}
372372

373-
out.writeMapOfLists(responseHeaders);
373+
out.writeMapOfLists(responseHeaders, StreamOutput::writeString, StreamOutput::writeString);
374374
}
375375
}
376376

core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
import java.io.IOException;
3232
import java.util.ArrayList;
33-
import java.util.Arrays;
3433
import java.util.Collections;
3534
import java.util.HashMap;
3635
import java.util.List;
@@ -42,7 +41,6 @@
4241
import static org.hamcrest.Matchers.equalTo;
4342
import static org.hamcrest.Matchers.hasSize;
4443
import static org.hamcrest.Matchers.is;
45-
import static org.hamcrest.Matchers.startsWith;
4644

4745
/**
4846
* Tests for {@link BytesStreamOutput} paging behaviour.
@@ -462,11 +460,11 @@ public void testWriteMapOfLists() throws IOException {
462460
}
463461

464462
final BytesStreamOutput out = new BytesStreamOutput();
465-
out.writeMapOfLists(expected);
463+
out.writeMapOfLists(expected, StreamOutput::writeString, StreamOutput::writeString);
466464

467465
final StreamInput in = StreamInput.wrap(BytesReference.toBytes(out.bytes()));
468466

469-
final Map<String, List<String>> loaded = in.readMapOfLists();
467+
final Map<String, List<String>> loaded = in.readMapOfLists(StreamInput::readString, StreamInput::readString);
470468

471469
assertThat(loaded.size(), equalTo(expected.size()));
472470

0 commit comments

Comments
 (0)