Skip to content

Commit 71a27f5

Browse files
committed
Merge pull request msgpack#325 from msgpack/immutable-config
Support method-chain syntax to create packer and unpacker with immutable config
2 parents 979ffc1 + b1e30b2 commit 71a27f5

File tree

5 files changed

+289
-58
lines changed

5 files changed

+289
-58
lines changed

msgpack-core/src/main/java/org/msgpack/core/MessagePack.java

Lines changed: 235 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -234,18 +234,41 @@ public static MessageUnpacker newDefaultUnpacker(byte[] contents, int offset, in
234234
* MessagePacker configuration.
235235
*/
236236
public static class PackerConfig
237+
implements Cloneable
237238
{
238-
/**
239-
* Use String.getBytes() for converting Java Strings that are smaller than this threshold into UTF8.
240-
* Note that this parameter is subject to change.
241-
*/
242-
public int smallStringOptimizationThreshold = 512;
239+
private int smallStringOptimizationThreshold = 512;
243240

244-
/**
245-
* When the next payload size exceeds this threshold, MessagePacker will call MessageBufferOutput.flush() before
246-
* packing the data.
247-
*/
248-
public int bufferFlushThreshold = 8192;
241+
private int bufferFlushThreshold = 8192;
242+
243+
private int bufferSize = 8192;
244+
245+
public PackerConfig()
246+
{ }
247+
248+
private PackerConfig(PackerConfig copy)
249+
{
250+
this.smallStringOptimizationThreshold = smallStringOptimizationThreshold;
251+
this.bufferFlushThreshold = bufferFlushThreshold;
252+
this.bufferSize = bufferSize;
253+
}
254+
255+
@Override
256+
public PackerConfig clone()
257+
{
258+
return new PackerConfig(this);
259+
}
260+
261+
@Override
262+
public boolean equals(Object obj)
263+
{
264+
if (!(obj instanceof PackerConfig)) {
265+
return false;
266+
}
267+
PackerConfig o = (PackerConfig) obj;
268+
return this.smallStringOptimizationThreshold == o.smallStringOptimizationThreshold
269+
&& this.bufferFlushThreshold == o.bufferFlushThreshold
270+
&& this.bufferSize == o.bufferSize;
271+
}
249272

250273
/**
251274
* Create a packer that outputs the packed data to a given output
@@ -266,7 +289,7 @@ public MessagePacker newPacker(MessageBufferOutput out)
266289
*/
267290
public MessagePacker newPacker(OutputStream out)
268291
{
269-
return newPacker(new OutputStreamBufferOutput(out));
292+
return newPacker(new OutputStreamBufferOutput(out, bufferSize));
270293
}
271294

272295
/**
@@ -277,7 +300,7 @@ public MessagePacker newPacker(OutputStream out)
277300
*/
278301
public MessagePacker newPacker(WritableByteChannel channel)
279302
{
280-
return newPacker(new ChannelBufferOutput(channel));
303+
return newPacker(new ChannelBufferOutput(channel, bufferSize));
281304
}
282305

283306
/**
@@ -289,42 +312,110 @@ public MessageBufferPacker newBufferPacker()
289312
{
290313
return new MessageBufferPacker(this);
291314
}
292-
}
293315

294-
/**
295-
* MessageUnpacker configuration.
296-
*/
297-
public static class UnpackerConfig
298-
{
299316
/**
300-
* Allow unpackBinaryHeader to read str format family (default:true)
317+
* Use String.getBytes() for converting Java Strings that are smaller than this threshold into UTF8.
318+
* Note that this parameter is subject to change.
301319
*/
302-
public boolean allowReadingStringAsBinary = true;
320+
public PackerConfig withSmallStringOptimizationThreshold(int bytes)
321+
{
322+
PackerConfig copy = clone();
323+
copy.smallStringOptimizationThreshold = bytes;
324+
return copy;
325+
}
303326

304-
/**
305-
* Allow unpackRawStringHeader and unpackString to read bin format family (default: true)
306-
*/
307-
public boolean allowReadingBinaryAsString = true;
327+
public int getSmallStringOptimizationThreshold()
328+
{
329+
return smallStringOptimizationThreshold;
330+
}
308331

309332
/**
310-
* Action when encountered a malformed input
333+
* When the next payload size exceeds this threshold, MessagePacker will call MessageBufferOutput.flush() before
334+
* packing the data (default: 8192).
311335
*/
312-
public CodingErrorAction actionOnMalformedString = CodingErrorAction.REPLACE;
336+
public PackerConfig withBufferFlushThreshold(int bytes)
337+
{
338+
PackerConfig copy = clone();
339+
copy.bufferFlushThreshold = bytes;
340+
return copy;
341+
}
313342

314-
/**
315-
* Action when an unmappable character is found
316-
*/
317-
public CodingErrorAction actionOnUnmappableString = CodingErrorAction.REPLACE;
343+
public int getBufferFlushThreshold()
344+
{
345+
return bufferFlushThreshold;
346+
}
318347

319348
/**
320-
* unpackString size limit. (default: Integer.MAX_VALUE)
349+
* When a packer is created with newPacker(OutputStream) or newPacker(WritableByteChannel), the stream will be
350+
* buffered with this size of buffer (default: 8192).
321351
*/
322-
public int stringSizeLimit = Integer.MAX_VALUE;
352+
public PackerConfig withBufferSize(int bytes)
353+
{
354+
PackerConfig copy = clone();
355+
copy.bufferSize = bytes;
356+
return copy;
357+
}
323358

324-
/**
325-
*
326-
*/
327-
public int stringDecoderBufferSize = 8192;
359+
public int getBufferSize()
360+
{
361+
return bufferSize;
362+
}
363+
}
364+
365+
/**
366+
* MessageUnpacker configuration.
367+
*/
368+
public static class UnpackerConfig
369+
implements Cloneable
370+
{
371+
private boolean allowReadingStringAsBinary = true;
372+
373+
private boolean allowReadingBinaryAsString = true;
374+
375+
private CodingErrorAction actionOnMalformedString = CodingErrorAction.REPLACE;
376+
377+
private CodingErrorAction actionOnUnmappableString = CodingErrorAction.REPLACE;
378+
379+
private int stringSizeLimit = Integer.MAX_VALUE;
380+
381+
private int bufferSize = 8192;
382+
383+
private int stringDecoderBufferSize = 8192;
384+
385+
public UnpackerConfig()
386+
{ }
387+
388+
private UnpackerConfig(UnpackerConfig copy)
389+
{
390+
this.allowReadingStringAsBinary = copy.allowReadingStringAsBinary;
391+
this.allowReadingBinaryAsString = copy.allowReadingBinaryAsString;
392+
this.actionOnMalformedString = copy.actionOnMalformedString;
393+
this.actionOnUnmappableString = copy.actionOnUnmappableString;
394+
this.stringSizeLimit = copy.stringSizeLimit;
395+
this.bufferSize = copy.bufferSize;
396+
}
397+
398+
@Override
399+
public UnpackerConfig clone()
400+
{
401+
return new UnpackerConfig(this);
402+
}
403+
404+
@Override
405+
public boolean equals(Object obj)
406+
{
407+
if (!(obj instanceof UnpackerConfig)) {
408+
return false;
409+
}
410+
UnpackerConfig o = (UnpackerConfig) obj;
411+
return this.allowReadingStringAsBinary == o.allowReadingStringAsBinary
412+
&& this.allowReadingBinaryAsString == o.allowReadingBinaryAsString
413+
&& this.actionOnMalformedString == o.actionOnMalformedString
414+
&& this.actionOnUnmappableString == o.actionOnUnmappableString
415+
&& this.stringSizeLimit == o.stringSizeLimit
416+
&& this.stringDecoderBufferSize == o.stringDecoderBufferSize
417+
&& this.bufferSize == o.bufferSize;
418+
}
328419

329420
/**
330421
* Create an unpacker that reads the data from a given input
@@ -345,7 +436,7 @@ public MessageUnpacker newUnpacker(MessageBufferInput in)
345436
*/
346437
public MessageUnpacker newUnpacker(InputStream in)
347438
{
348-
return newUnpacker(new InputStreamBufferInput(in));
439+
return newUnpacker(new InputStreamBufferInput(in, bufferSize));
349440
}
350441

351442
/**
@@ -356,7 +447,7 @@ public MessageUnpacker newUnpacker(InputStream in)
356447
*/
357448
public MessageUnpacker newUnpacker(ReadableByteChannel channel)
358449
{
359-
return newUnpacker(new ChannelBufferInput(channel));
450+
return newUnpacker(new ChannelBufferInput(channel, bufferSize));
360451
}
361452

362453
/**
@@ -380,5 +471,111 @@ public MessageUnpacker newUnpacker(byte[] contents, int offset, int length)
380471
{
381472
return newUnpacker(new ArrayBufferInput(contents, offset, length));
382473
}
474+
475+
/**
476+
* Allow unpackBinaryHeader to read str format family (default: true)
477+
*/
478+
public UnpackerConfig withAllowReadingStringAsBinary(boolean enable)
479+
{
480+
UnpackerConfig copy = clone();
481+
copy.allowReadingStringAsBinary = enable;
482+
return copy;
483+
}
484+
485+
public boolean getAllowReadingStringAsBinary()
486+
{
487+
return allowReadingStringAsBinary;
488+
}
489+
490+
/**
491+
* Allow unpackString and unpackRawStringHeader and unpackString to read bin format family (default: true)
492+
*/
493+
public UnpackerConfig withAllowReadingBinaryAsString(boolean enable)
494+
{
495+
UnpackerConfig copy = clone();
496+
copy.allowReadingBinaryAsString = enable;
497+
return copy;
498+
}
499+
500+
public boolean getAllowReadingBinaryAsString()
501+
{
502+
return allowReadingBinaryAsString;
503+
}
504+
505+
/**
506+
* Action when encountered a malformed input (default: REPLACE)
507+
*/
508+
public UnpackerConfig withActionOnMalformedString(CodingErrorAction action)
509+
{
510+
UnpackerConfig copy = clone();
511+
copy.actionOnMalformedString = action;
512+
return copy;
513+
}
514+
515+
public CodingErrorAction getActionOnMalformedString()
516+
{
517+
return actionOnMalformedString;
518+
}
519+
520+
/**
521+
* Action when an unmappable character is found (default: REPLACE)
522+
*/
523+
public UnpackerConfig withActionOnUnmappableString(CodingErrorAction action)
524+
{
525+
UnpackerConfig copy = clone();
526+
copy.actionOnUnmappableString = action;
527+
return copy;
528+
}
529+
530+
public CodingErrorAction getActionOnUnmappableString()
531+
{
532+
return actionOnUnmappableString;
533+
}
534+
535+
/**
536+
* unpackString size limit (default: Integer.MAX_VALUE).
537+
*/
538+
public UnpackerConfig withStringSizeLimit(int bytes)
539+
{
540+
UnpackerConfig copy = clone();
541+
copy.stringSizeLimit = bytes;
542+
return copy;
543+
}
544+
545+
public int getStringSizeLimit()
546+
{
547+
return stringSizeLimit;
548+
}
549+
550+
/**
551+
*
552+
*/
553+
public UnpackerConfig withStringDecoderBufferSize(int bytes)
554+
{
555+
UnpackerConfig copy = clone();
556+
copy.stringDecoderBufferSize = bytes;
557+
return copy;
558+
}
559+
560+
public int getStringDecoderBufferSize()
561+
{
562+
return stringDecoderBufferSize;
563+
}
564+
565+
/**
566+
* When a packer is created with newUnpacker(OutputStream) or newUnpacker(WritableByteChannel), the stream will be
567+
* buffered with this size of buffer (default: 8192).
568+
*/
569+
public UnpackerConfig withBufferSize(int bytes)
570+
{
571+
UnpackerConfig copy = clone();
572+
copy.bufferSize = bytes;
573+
return copy;
574+
}
575+
576+
public int getBufferSize()
577+
{
578+
return bufferSize;
579+
}
383580
}
384581
}

msgpack-core/src/main/java/org/msgpack/core/MessagePacker.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,8 @@ public class MessagePacker
114114
protected MessagePacker(MessageBufferOutput out, MessagePack.PackerConfig config)
115115
{
116116
this.out = checkNotNull(out, "MessageBufferOutput is null");
117-
// We must copy the configuration parameters here since the config object is mutable
118-
this.smallStringOptimizationThreshold = config.smallStringOptimizationThreshold;
119-
this.bufferFlushThreshold = config.bufferFlushThreshold;
117+
this.smallStringOptimizationThreshold = config.getSmallStringOptimizationThreshold();
118+
this.bufferFlushThreshold = config.getBufferFlushThreshold();
120119
this.position = 0;
121120
this.totalFlushBytes = 0;
122121
}

msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,12 @@ public class MessageUnpacker
130130
protected MessageUnpacker(MessageBufferInput in, MessagePack.UnpackerConfig config)
131131
{
132132
this.in = checkNotNull(in, "MessageBufferInput is null");
133-
// We need to copy the configuration parameters since the config object is mutable
134-
this.allowReadingStringAsBinary = config.allowReadingStringAsBinary;
135-
this.allowReadingBinaryAsString = config.allowReadingBinaryAsString;
136-
this.actionOnMalformedString = config.actionOnMalformedString;
137-
this.actionOnUnmappableString = config.actionOnUnmappableString;
138-
this.stringSizeLimit = config.stringSizeLimit;
139-
this.stringDecoderBufferSize = config.stringDecoderBufferSize;
133+
this.allowReadingStringAsBinary = config.getAllowReadingStringAsBinary();
134+
this.allowReadingBinaryAsString = config.getAllowReadingBinaryAsString();
135+
this.actionOnMalformedString = config.getActionOnMalformedString();
136+
this.actionOnUnmappableString = config.getActionOnUnmappableString();
137+
this.stringSizeLimit = config.getStringSizeLimit();
138+
this.stringDecoderBufferSize = config.getStringDecoderBufferSize();
140139
}
141140

142141
/**

msgpack-core/src/test/java/org/msgpack/core/example/MessagePackExample.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,20 +246,19 @@ public static void configuration()
246246
throws IOException
247247
{
248248
ByteArrayOutputStream out = new ByteArrayOutputStream();
249-
PackerConfig packerConfig = new PackerConfig();
250-
packerConfig.smallStringOptimizationThreshold = 256; // String
251-
MessagePacker packer = packerConfig.newPacker(out);
249+
MessagePacker packer = new PackerConfig()
250+
.withSmallStringOptimizationThreshold(256) // String
251+
.newPacker(out);
252252

253253
packer.packInt(10);
254254
packer.packBoolean(true);
255255
packer.close();
256256

257257
// Unpack data
258-
UnpackerConfig unpackerConfig = new UnpackerConfig();
259-
unpackerConfig.stringDecoderBufferSize = 16 * 1024; // If your data contains many large strings (the default is 8k)
260-
261258
byte[] packedData = out.toByteArray();
262-
MessageUnpacker unpacker = unpackerConfig.newUnpacker(packedData);
259+
MessageUnpacker unpacker = new UnpackerConfig()
260+
.withStringDecoderBufferSize(16 * 1024) // If your data contains many large strings (the default is 8k)
261+
.newUnpacker(packedData);
263262
int i = unpacker.unpackInt(); // 10
264263
boolean b = unpacker.unpackBoolean(); // true
265264
unpacker.close();

0 commit comments

Comments
 (0)