msgpack-jruby 1.0.0-java → 1.1.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -1,5 +1,4 @@
1
1
  *.gem
2
2
  .bundle
3
- Gemfile.lock
4
3
  pkg/*
5
- /benchmark
4
+ /benchmark
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm --create use jruby-1.6.2@msgpack-jruby
1
+ rvm --create use jruby-1.6.7@msgpack-jruby
data/Gemfile CHANGED
@@ -1,11 +1,13 @@
1
1
  source :rubygems
2
2
 
3
- gemspec
3
+ gem 'jruby-openssl'
4
4
 
5
5
  group :test do
6
6
  gem 'rspec'
7
7
  gem 'viiite'
8
8
  gem 'ffi-ncurses'
9
9
  gem 'bson'
10
+ gem 'bson_ext', :platforms => :mri
10
11
  gem 'json'
12
+ gem 'msgpack', :platforms => :mri
11
13
  end
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ alf (0.10.1)
5
+ highline (~> 1.6.2)
6
+ myrrha (~> 1.2.1)
7
+ quickl (~> 0.4.1)
8
+ bouncy-castle-java (1.5.0146.1)
9
+ bson (1.5.2)
10
+ bson (1.5.2-java)
11
+ bson_ext (1.5.2)
12
+ bson (= 1.5.2)
13
+ diff-lcs (1.1.3)
14
+ ffi (1.0.9)
15
+ ffi (1.0.9-java)
16
+ ffi-ncurses (0.3.3)
17
+ ffi (>= 0.6.3)
18
+ gnuplot (2.3.6)
19
+ highline (1.6.2)
20
+ jruby-openssl (0.7.4)
21
+ bouncy-castle-java
22
+ json (1.5.0)
23
+ json (1.5.0-java)
24
+ msgpack (0.4.6)
25
+ myrrha (1.2.1)
26
+ quickl (0.4.1)
27
+ rspec (2.6.0)
28
+ rspec-core (~> 2.6.0)
29
+ rspec-expectations (~> 2.6.0)
30
+ rspec-mocks (~> 2.6.0)
31
+ rspec-core (2.6.4)
32
+ rspec-expectations (2.6.0)
33
+ diff-lcs (~> 1.1.2)
34
+ rspec-mocks (2.6.0)
35
+ viiite (0.1.0)
36
+ alf (~> 0.10.0)
37
+ gnuplot (~> 2.3.6)
38
+ quickl (~> 0.4.0)
39
+
40
+ PLATFORMS
41
+ java
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ bson
46
+ bson_ext
47
+ ffi-ncurses
48
+ jruby-openssl
49
+ json
50
+ msgpack
51
+ rspec
52
+ viiite
data/Rakefile CHANGED
@@ -1,22 +1,56 @@
1
- require 'bundler'
1
+ $: << 'lib'
2
2
 
3
+ require 'bundler/setup'
4
+ require 'msgpack/version'
3
5
 
4
- Bundler::GemHelper.install_tasks
5
6
 
6
7
  task :clean do
7
- rm Dir['lib/ext/**/*.class']
8
+ rm Dir['ext/java/**/*.class']
8
9
  end
9
10
 
10
11
  task :compile do
11
- exec %(javac -source 1.6 -target 1.6 -cp lib/ext/msgpack-0.5.2-devel.jar:$MY_RUBY_HOME/lib/jruby.jar -d lib/ext ext/java/org/msgpack/**/*.java)
12
+ classpath = (Dir["lib/ext/*.jar"] + ["#{ENV['MY_RUBY_HOME']}/lib/jruby.jar"]).join(':')
13
+ system %(javac -Xlint:-options -source 1.6 -target 1.6 -cp #{classpath} ext/java/*.java ext/java/org/msgpack/jruby/*.java)
14
+ exit($?.exitstatus) unless $?.success?
12
15
  end
13
16
 
14
- BENCHMARK_RUBIES = ['1.9.2-p290', 'jruby-1.6.2', 'jruby-1.6.4']
15
- BENCHMARK_GEMSET = 'msgpack-jruby-benchmarking'
17
+ task :package => :compile do
18
+ class_files = Dir['ext/java/**/*.class'].map { |path| path = path.sub('ext/java/', ''); "-C ext/java '#{path}'" }
19
+ system %(jar cf lib/ext/msgpack_jruby.jar #{class_files.join(' ')})
20
+ exit($?.exitstatus) unless $?.success?
21
+ end
16
22
 
17
- task :benchmark do
18
- rubies = BENCHMARK_RUBIES.map { |rb| "#{rb}@#{BENCHMARK_GEMSET}" }
19
- cmd = %(rvm #{rubies.join(',')} exec viiite run spec/benchmark.rb | tee benchmark | viiite report --hierarchy --regroup=bench,ruby)
20
- puts cmd
21
- system cmd
23
+ task :release do
24
+ version_string = "v#{MessagePack::VERSION}"
25
+ unless %x(git tag -l).include?(version_string)
26
+ system %(git tag -a #{version_string} -m #{version_string})
27
+ end
28
+ system %(gem build msgpack-jruby.gemspec && gem push msgpack-jruby-*.gem && mv msgpack-jruby-*.gem pkg)
22
29
  end
30
+
31
+ namespace :benchmark do
32
+ BENCHMARK_RUBIES = ['1.9.2-p0', 'jruby-1.6.5', 'jruby-head']
33
+ BENCHMARK_GEMSET = 'msgpack-jruby-benchmarking'
34
+
35
+ task :run do
36
+ rubies = BENCHMARK_RUBIES.map { |rb| "#{rb}@#{BENCHMARK_GEMSET}" }
37
+ cmd = %(rvm #{rubies.join(',')} exec viiite run spec/benchmark.rb | tee benchmark | viiite report --hierarchy --regroup=bench,lib,ruby)
38
+ puts cmd
39
+ system cmd
40
+ end
41
+
42
+ task :quick do
43
+ cmd = %(IMPLEMENTATIONS=msgpack viiite run spec/benchmark.rb | viiite report --hierarchy --regroup=bench)
44
+ puts cmd
45
+ system cmd
46
+ end
47
+
48
+ task :setup do
49
+ rubies = BENCHMARK_RUBIES.map { |rb| "#{rb}@#{BENCHMARK_GEMSET}" }
50
+ rubies.each do |ruby_version|
51
+ cmd = %(rvm-shell #{ruby_version} -c 'bundle check || bundle install')
52
+ puts cmd
53
+ system cmd
54
+ end
55
+ end
56
+ end
data/ext/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.class
@@ -0,0 +1,15 @@
1
+ import java.io.IOException;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.runtime.load.BasicLibraryService;
5
+
6
+ import org.msgpack.jruby.MessagePackLibrary;
7
+
8
+
9
+ public class MsgpackJrubyService implements BasicLibraryService {
10
+ public boolean basicLoad(final Ruby runtime) throws IOException {
11
+ new MessagePackLibrary().load(runtime, false);
12
+ return true;
13
+ }
14
+ }
15
+
@@ -0,0 +1,229 @@
1
+ package org.msgpack.jruby;
2
+
3
+
4
+ import java.io.InputStream;
5
+ import java.io.ByteArrayInputStream;
6
+ import java.io.IOException;
7
+
8
+ import org.jruby.Ruby;
9
+ import org.jruby.RubyModule;
10
+ import org.jruby.RubyClass;
11
+ import org.jruby.RubyString;
12
+ import org.jruby.RubyObject;
13
+ import org.jruby.RubyIO;
14
+ import org.jruby.RubyStringIO;
15
+ import org.jruby.RubyNumeric;
16
+ import org.jruby.RubyEnumerator;
17
+ import org.jruby.runtime.load.Library;
18
+ import org.jruby.runtime.callback.Callback;
19
+ import org.jruby.runtime.builtin.IRubyObject;
20
+ import org.jruby.runtime.Arity;
21
+ import org.jruby.runtime.Block;
22
+ import org.jruby.runtime.ObjectAllocator;
23
+ import org.jruby.runtime.ThreadContext;
24
+ import org.jruby.anno.JRubyClass;
25
+ import org.jruby.anno.JRubyModule;
26
+ import org.jruby.anno.JRubyMethod;
27
+ import org.jruby.util.IOInputStream;
28
+
29
+ import static org.jruby.runtime.Visibility.*;
30
+
31
+ import org.msgpack.MessagePack;
32
+ import org.msgpack.packer.BufferPacker;
33
+ import org.msgpack.packer.Packer;
34
+ import org.msgpack.unpacker.MessagePackBufferUnpacker;
35
+ import org.msgpack.unpacker.MessagePackUnpacker;
36
+ import org.msgpack.unpacker.UnpackerIterator;
37
+ import org.msgpack.type.Value;
38
+ import org.msgpack.io.Input;
39
+ import org.msgpack.io.LinkedBufferInput;
40
+ import org.msgpack.io.StreamInput;
41
+
42
+
43
+ public class MessagePackLibrary implements Library {
44
+ public void load(Ruby runtime, boolean wrap) throws IOException {
45
+ MessagePack msgPack = new MessagePack();
46
+ RubyModule msgpackModule = runtime.defineModule("MessagePack");
47
+ msgpackModule.defineAnnotatedMethods(MessagePackModule.class);
48
+ RubyClass standardErrorClass = runtime.getStandardError();
49
+ RubyClass unpackErrorClass = msgpackModule.defineClassUnder("UnpackError", standardErrorClass, standardErrorClass.getAllocator());
50
+ RubyClass unpackerClass = msgpackModule.defineClassUnder("Unpacker", runtime.getObject(), new UnpackerAllocator(msgPack));
51
+ unpackerClass.defineAnnotatedMethods(Unpacker.class);
52
+ }
53
+
54
+ @JRubyModule(name = "MessagePack")
55
+ public static class MessagePackModule {
56
+ private static MessagePack msgPack = new MessagePack();
57
+ private static RubyObjectUnpacker unpacker = new RubyObjectUnpacker(msgPack);
58
+
59
+ @JRubyMethod(module = true, required = 1)
60
+ public static IRubyObject pack(ThreadContext ctx, IRubyObject recv, IRubyObject obj) throws IOException {
61
+ BufferPacker bufferedPacker = msgPack.createBufferPacker();
62
+ Packer packer = new RubyObjectPacker(msgPack, bufferedPacker).write(obj);
63
+ return RubyString.newString(ctx.getRuntime(), bufferedPacker.toByteArray());
64
+ }
65
+
66
+ @JRubyMethod(module = true, required = 1)
67
+ public static IRubyObject unpack(ThreadContext ctx, IRubyObject recv, IRubyObject obj) throws IOException {
68
+ return unpacker.unpack(obj.asString());
69
+ }
70
+ }
71
+
72
+ private static class UnpackerAllocator implements ObjectAllocator {
73
+ private MessagePack msgPack;
74
+
75
+ public UnpackerAllocator(MessagePack msgPack) {
76
+ this.msgPack = msgPack;
77
+ }
78
+
79
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
80
+ return new Unpacker(runtime, klass, msgPack);
81
+ }
82
+ }
83
+
84
+ @JRubyClass(name="MessagePack::Unpacker")
85
+ public static class Unpacker extends RubyObject {
86
+ private MessagePack msgPack;
87
+ private RubyObjectUnpacker rubyObjectUnpacker;
88
+ private MessagePackBufferUnpacker bufferUnpacker;
89
+ private MessagePackUnpacker streamUnpacker;
90
+ private IRubyObject stream;
91
+ private IRubyObject data;
92
+
93
+ public Unpacker(Ruby runtime, RubyClass type, MessagePack msgPack) {
94
+ super(runtime, type);
95
+ this.msgPack = msgPack;
96
+ this.rubyObjectUnpacker = new RubyObjectUnpacker(msgPack);
97
+ this.bufferUnpacker = null;
98
+ this.streamUnpacker = null;
99
+ this.stream = null;
100
+ this.data = null;
101
+ }
102
+
103
+ @JRubyMethod(name = "initialize", optional = 1, visibility = PRIVATE)
104
+ public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
105
+ if (args.length > 0) {
106
+ setStream(ctx, args[0]);
107
+ }
108
+ return this;
109
+ }
110
+
111
+ @JRubyMethod(required = 2)
112
+ public IRubyObject execute(ThreadContext ctx, IRubyObject data, IRubyObject offset) {
113
+ return executeLimit(ctx, data, offset, null);
114
+ }
115
+
116
+ @JRubyMethod(name = "execute_limit", required = 3)
117
+ public IRubyObject executeLimit(ThreadContext ctx, IRubyObject data, IRubyObject offset, IRubyObject limit) {
118
+ this.data = null;
119
+ try {
120
+ int jOffset = RubyNumeric.fix2int(offset);
121
+ int jLimit = -1;
122
+ if (limit != null) {
123
+ jLimit = RubyNumeric.fix2int(limit);
124
+ }
125
+ byte[] bytes = data.asString().getBytes();
126
+ MessagePackBufferUnpacker localBufferUnpacker = new MessagePackBufferUnpacker(msgPack, bytes.length);
127
+ localBufferUnpacker.wrap(bytes, jOffset, jLimit == -1 ? bytes.length - jOffset : jLimit);
128
+ this.data = rubyObjectUnpacker.valueToRubyObject(ctx.getRuntime(), localBufferUnpacker.readValue());
129
+ return ctx.getRuntime().newFixnum(jOffset + localBufferUnpacker.getReadByteCount());
130
+ } catch (IOException ioe) {
131
+ // TODO: how to throw Ruby exceptions?
132
+ return ctx.getRuntime().getNil();
133
+ }
134
+ }
135
+
136
+ @JRubyMethod(name = "data")
137
+ public IRubyObject getData(ThreadContext ctx) {
138
+ if (data == null) {
139
+ return ctx.getRuntime().getNil();
140
+ } else {
141
+ return data;
142
+ }
143
+ }
144
+
145
+ @JRubyMethod(name = "finished?")
146
+ public IRubyObject finished_q(ThreadContext ctx) {
147
+ return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue();
148
+ }
149
+
150
+ @JRubyMethod(required = 1)
151
+ public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
152
+ streamUnpacker = null;
153
+ byte[] bytes = data.asString().getBytes();
154
+ if (bufferUnpacker == null) {
155
+ bufferUnpacker = new MessagePackBufferUnpacker(msgPack);
156
+ }
157
+ bufferUnpacker.feed(bytes);
158
+ return ctx.getRuntime().getNil();
159
+ }
160
+
161
+ @JRubyMethod(name = "feed_each", required = 1)
162
+ public IRubyObject feedEach(ThreadContext ctx, IRubyObject data, Block block) {
163
+ feed(ctx, data);
164
+ each(ctx, block);
165
+ return ctx.getRuntime().getNil();
166
+ }
167
+
168
+ @JRubyMethod
169
+ public IRubyObject each(ThreadContext ctx, Block block) {
170
+ MessagePackUnpacker localUnpacker = null;
171
+ if (bufferUnpacker == null && streamUnpacker != null) {
172
+ localUnpacker = streamUnpacker;
173
+ } else if (bufferUnpacker != null) {
174
+ localUnpacker = bufferUnpacker;
175
+ } else {
176
+ return ctx.getRuntime().getNil();
177
+ }
178
+ if (block.isGiven()) {
179
+ for (Value value : localUnpacker) {
180
+ IRubyObject rubyObject = rubyObjectUnpacker.valueToRubyObject(ctx.getRuntime(), value);
181
+ block.yield(ctx, rubyObject);
182
+ }
183
+ return ctx.getRuntime().getNil();
184
+ } else {
185
+ return RubyEnumerator.RubyEnumeratorKernel.obj_to_enum(ctx, this, Block.NULL_BLOCK);
186
+ }
187
+ }
188
+
189
+ @JRubyMethod
190
+ public IRubyObject fill(ThreadContext ctx) {
191
+ return ctx.getRuntime().getNil();
192
+ }
193
+
194
+ @JRubyMethod
195
+ public IRubyObject reset(ThreadContext ctx) {
196
+ if (bufferUnpacker != null) {
197
+ bufferUnpacker.reset();
198
+ }
199
+ if (streamUnpacker != null) {
200
+ streamUnpacker.reset();
201
+ }
202
+ return ctx.getRuntime().getNil();
203
+ }
204
+
205
+ @JRubyMethod(name = "stream")
206
+ public IRubyObject getStream(ThreadContext ctx) {
207
+ if (stream == null) {
208
+ return ctx.getRuntime().getNil();
209
+ } else {
210
+ return stream;
211
+ }
212
+ }
213
+
214
+ @JRubyMethod(name = "stream=", required = 1)
215
+ public IRubyObject setStream(ThreadContext ctx, IRubyObject stream) {
216
+ bufferUnpacker = null;
217
+ this.stream = stream;
218
+ if (stream instanceof RubyStringIO) {
219
+ // TODO: RubyStringIO returns negative numbers when read through IOInputStream#read
220
+ IRubyObject str = ((RubyStringIO) stream).string();
221
+ byte[] bytes = ((RubyString) str).getBytes();
222
+ streamUnpacker = new MessagePackUnpacker(msgPack, new ByteArrayInputStream(bytes));
223
+ } else {
224
+ streamUnpacker = new MessagePackUnpacker(msgPack, new IOInputStream(stream));
225
+ }
226
+ return getStream(ctx);
227
+ }
228
+ }
229
+ }
@@ -0,0 +1,111 @@
1
+ package org.msgpack.jruby;
2
+
3
+
4
+ import java.io.IOException;
5
+
6
+ import org.msgpack.MessagePack;
7
+ import org.msgpack.packer.Packer;
8
+ import org.msgpack.packer.MessagePackBufferPacker;
9
+
10
+ import org.jruby.RubyObject;
11
+ import org.jruby.RubyNil;
12
+ import org.jruby.RubyBoolean;
13
+ import org.jruby.RubyBignum;
14
+ import org.jruby.RubyInteger;
15
+ import org.jruby.RubyFixnum;
16
+ import org.jruby.RubyFloat;
17
+ import org.jruby.RubyString;
18
+ import org.jruby.RubySymbol;
19
+ import org.jruby.RubyArray;
20
+ import org.jruby.RubyHash;
21
+ import org.jruby.runtime.builtin.IRubyObject;
22
+
23
+
24
+ public class RubyObjectPacker extends MessagePackBufferPacker {
25
+ private final Packer packer;
26
+
27
+ public RubyObjectPacker(MessagePack msgPack, Packer packer) {
28
+ super(msgPack);
29
+ this.packer = packer;
30
+ }
31
+
32
+ public Packer write(IRubyObject o) throws IOException {
33
+ if (o == null || o instanceof RubyNil) {
34
+ packer.writeNil();
35
+ return this;
36
+ } else if (o instanceof RubyBoolean) {
37
+ packer.write(((RubyBoolean) o).isTrue());
38
+ return this;
39
+ } else if (o instanceof RubyBignum) {
40
+ return write((RubyBignum) o);
41
+ } else if (o instanceof RubyInteger) {
42
+ return write((RubyInteger) o);
43
+ } else if (o instanceof RubyFixnum) {
44
+ return write((RubyFixnum) o);
45
+ } else if (o instanceof RubyFloat) {
46
+ return write((RubyFloat) o);
47
+ } else if (o instanceof RubyString) {
48
+ return write((RubyString) o);
49
+ } else if (o instanceof RubySymbol) {
50
+ return write((RubySymbol) o);
51
+ } else if (o instanceof RubyArray) {
52
+ return write((RubyArray) o);
53
+ } else if (o instanceof RubyHash) {
54
+ return write((RubyHash) o);
55
+ } else {
56
+ throw o.getRuntime().newArgumentError(String.format("Cannot pack type: %s", o.getClass().getName()));
57
+ }
58
+ }
59
+
60
+ public final Packer write(RubyBignum bignum) throws IOException {
61
+ packer.write(bignum.getBigIntegerValue());
62
+ return this;
63
+ }
64
+
65
+ public final Packer write(RubyInteger integer) throws IOException {
66
+ packer.write(integer.getLongValue());
67
+ return this;
68
+ }
69
+
70
+ public final Packer write(RubyFixnum fixnum) throws IOException {
71
+ packer.write(fixnum.getLongValue());
72
+ return this;
73
+ }
74
+
75
+ public final Packer write(RubyFloat flt) throws IOException {
76
+ packer.write(flt.getDoubleValue());
77
+ return this;
78
+ }
79
+
80
+ public final Packer write(RubyString str) throws IOException {
81
+ packer.write(str.getBytes());
82
+ return this;
83
+ }
84
+
85
+ public final Packer write(RubySymbol sym) throws IOException {
86
+ return write((RubyString) sym.to_s());
87
+ }
88
+
89
+ public final Packer write(RubyArray array) throws IOException {
90
+ int count = array.size();
91
+ packer.writeArrayBegin(count);
92
+ for (int i = 0; i < count; i++) {
93
+ write((RubyObject) array.entry(i));
94
+ }
95
+ packer.writeArrayEnd();
96
+ return this;
97
+ }
98
+
99
+ public final Packer write(RubyHash hash) throws IOException {
100
+ int count = hash.size();
101
+ packer.writeMapBegin(count);
102
+ RubyArray keys = hash.keys();
103
+ RubyArray values = hash.rb_values();
104
+ for (int i = 0; i < count; i++) {
105
+ write((RubyObject) keys.entry(i));
106
+ write((RubyObject) values.entry(i));
107
+ }
108
+ packer.writeMapEnd();
109
+ return this;
110
+ }
111
+ }
@@ -0,0 +1,114 @@
1
+ package org.msgpack.jruby;
2
+
3
+
4
+ import java.io.IOException;
5
+
6
+ import org.msgpack.MessagePack;
7
+ import org.msgpack.MessageTypeException;
8
+ import org.msgpack.unpacker.MessagePackBufferUnpacker;
9
+ import org.msgpack.type.Value;
10
+ import org.msgpack.type.ValueType;
11
+ import org.msgpack.type.BooleanValue;
12
+ import org.msgpack.type.IntegerValue;
13
+ import org.msgpack.type.FloatValue;
14
+ import org.msgpack.type.ArrayValue;
15
+ import org.msgpack.type.MapValue;
16
+ import org.msgpack.type.RawValue;
17
+
18
+ import org.jruby.Ruby;
19
+ import org.jruby.RubyObject;
20
+ import org.jruby.RubyNil;
21
+ import org.jruby.RubyBoolean;
22
+ import org.jruby.RubyBignum;
23
+ import org.jruby.RubyInteger;
24
+ import org.jruby.RubyFixnum;
25
+ import org.jruby.RubyFloat;
26
+ import org.jruby.RubyString;
27
+ import org.jruby.RubySymbol;
28
+ import org.jruby.RubyArray;
29
+ import org.jruby.RubyHash;
30
+ import org.jruby.runtime.builtin.IRubyObject;
31
+
32
+
33
+ public class RubyObjectUnpacker {
34
+ private final MessagePack msgPack;
35
+
36
+ public RubyObjectUnpacker(MessagePack msgPack) {
37
+ this.msgPack = msgPack;
38
+ }
39
+
40
+ public IRubyObject unpack(RubyString str) throws IOException {
41
+ return unpack(str.getRuntime(), str.getBytes());
42
+ }
43
+
44
+ public IRubyObject unpack(Ruby runtime, byte[] data) throws IOException {
45
+ MessagePackBufferUnpacker unpacker = new MessagePackBufferUnpacker(msgPack);
46
+ unpacker.wrap(data);
47
+ return valueToRubyObject(runtime, unpacker.readValue());
48
+ }
49
+
50
+ IRubyObject valueToRubyObject(Ruby runtime, Value value) {
51
+ switch (value.getType()) {
52
+ case NIL:
53
+ return runtime.getNil();
54
+ case BOOLEAN:
55
+ return convert(runtime, value.asBooleanValue());
56
+ case INTEGER:
57
+ return convert(runtime, value.asIntegerValue());
58
+ case FLOAT:
59
+ return convert(runtime, value.asFloatValue());
60
+ case ARRAY:
61
+ return convert(runtime, value.asArrayValue());
62
+ case MAP:
63
+ return convert(runtime, value.asMapValue());
64
+ case RAW:
65
+ return convert(runtime, value.asRawValue());
66
+ default:
67
+ throw runtime.newArgumentError(String.format("Unexpected value: %s", value.toString()));
68
+ }
69
+ }
70
+
71
+ private IRubyObject convert(Ruby runtime, BooleanValue value) {
72
+ return RubyBoolean.newBoolean(runtime, value.asBooleanValue().getBoolean());
73
+ }
74
+
75
+ private IRubyObject convert(Ruby runtime, IntegerValue value) {
76
+ // TODO: is there any way of checking for bignums up front?
77
+ IntegerValue iv = value.asIntegerValue();
78
+ try {
79
+ return RubyFixnum.newFixnum(runtime, iv.getLong());
80
+ } catch (MessageTypeException mte) {
81
+ return RubyBignum.newBignum(runtime, iv.getBigInteger());
82
+ }
83
+ }
84
+
85
+ private IRubyObject convert(Ruby runtime, FloatValue value) {
86
+ return RubyFloat.newFloat(runtime, value.asFloatValue().getDouble());
87
+ }
88
+
89
+ private IRubyObject convert(Ruby runtime, ArrayValue value) {
90
+ Value[] elements = value.asArrayValue().getElementArray();
91
+ int elementCount = elements.length;
92
+ IRubyObject[] rubyObjects = new IRubyObject[elementCount];
93
+ for (int i = 0; i < elementCount; i++) {
94
+ rubyObjects[i] = valueToRubyObject(runtime, elements[i]);
95
+ }
96
+ return RubyArray.newArray(runtime, rubyObjects);
97
+ }
98
+
99
+ private IRubyObject convert(Ruby runtime, MapValue value) {
100
+ Value[] keysAndValues = value.asMapValue().getKeyValueArray();
101
+ int kvCount = keysAndValues.length;
102
+ RubyHash hash = RubyHash.newHash(runtime);
103
+ for (int i = 0; i < kvCount; i += 2) {
104
+ Value k = keysAndValues[i];
105
+ Value v = keysAndValues[i + 1];
106
+ hash.put(valueToRubyObject(runtime, k), valueToRubyObject(runtime, v));
107
+ }
108
+ return hash;
109
+ }
110
+
111
+ private IRubyObject convert(Ruby runtime, RawValue value) {
112
+ return RubyString.newString(runtime, value.asRawValue().getByteArray());
113
+ }
114
+ }
Binary file
Binary file
Binary file
@@ -1,3 +1,3 @@
1
1
  module MessagePack
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.3'
3
3
  end
data/lib/msgpack.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'java'
4
-
5
- $CLASSPATH << File.expand_path('../ext', __FILE__) << File.expand_path('../ext/msgpack-0.5.2-devel.jar', __FILE__)
3
+ $: << File.expand_path('../ext', __FILE__)
6
4
 
7
- MessagePack = org.msgpack.jruby.MessagePack
5
+ require 'java'
6
+ require 'javassist-3.15.0-GA'
7
+ require 'msgpack-0.6.6'
8
+ require 'msgpack_jruby'
data/spec/benchmark.rb CHANGED
@@ -10,17 +10,23 @@ require 'msgpack'
10
10
  require 'json'
11
11
  require 'bson'
12
12
 
13
+ if RUBY_PLATFORM.include?('java')
14
+ BSON_IMPL = BSON::BSON_JAVA
15
+ else
16
+ BSON_IMPL = BSON::BSON_C
17
+ end
13
18
 
14
19
  OBJECT_STRUCTURE = {'x' => ['y', 34, 2**30 + 3, 2.1223423423356, {'hello' => 'world', '5' => [63, 'asjdl']}]}
15
20
  ENCODED_MSGPACK = "\x81\xA1x\x95\xA1y\"\xCE@\x00\x00\x03\xCB@\x00\xFA\x8E\x9F9\xFA\xC1\x82\xA5hello\xA5world\xA15\x92?\xA5asjdl"
16
21
  ENCODED_BSON = "d\x00\x00\x00\x04x\x00\\\x00\x00\x00\x020\x00\x02\x00\x00\x00y\x00\x101\x00\"\x00\x00\x00\x102\x00\x03\x00\x00@\x013\x00\xC1\xFA9\x9F\x8E\xFA\x00@\x034\x002\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x045\x00\x19\x00\x00\x00\x100\x00?\x00\x00\x00\x021\x00\x06\x00\x00\x00asjdl\x00\x00\x00\x00\x00"
17
22
  ENCODED_JSON = '{"x":["y",34,1073741827,2.1223423423356,{"hello":"world","5":[63,"asjdl"]}]}'
18
23
  ITERATIONS = 1_00_000
24
+ IMPLEMENTATIONS = ENV.fetch('IMPLEMENTATIONS', 'json,bson,msgpack').split(',').map(&:to_sym)
19
25
 
20
26
  Viiite.bm do |b|
21
27
  b.variation_point :ruby, Viiite.which_ruby
22
28
 
23
- [:json, :msgpack].each do |lib|
29
+ IMPLEMENTATIONS.each do |lib|
24
30
  b.variation_point :lib, lib
25
31
 
26
32
 
@@ -28,7 +34,7 @@ Viiite.bm do |b|
28
34
  ITERATIONS.times do
29
35
  case lib
30
36
  when :msgpack then MessagePack.pack(OBJECT_STRUCTURE)
31
- when :bson then BSON::BSON_JAVA.serialize(OBJECT_STRUCTURE).to_s
37
+ when :bson then BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s
32
38
  when :json then OBJECT_STRUCTURE.to_json
33
39
  end
34
40
  end
@@ -38,7 +44,7 @@ Viiite.bm do |b|
38
44
  ITERATIONS.times do
39
45
  case lib
40
46
  when :msgpack then MessagePack.unpack(ENCODED_MSGPACK)
41
- when :bson then BSON::BSON_JAVA.deserialize(ENCODED_BSON)
47
+ when :bson then BSON_IMPL.deserialize(ENCODED_BSON)
42
48
  when :json then JSON.parse(ENCODED_JSON)
43
49
  end
44
50
  end
@@ -48,7 +54,7 @@ Viiite.bm do |b|
48
54
  ITERATIONS.times do
49
55
  case lib
50
56
  when :msgpack then MessagePack.unpack(MessagePack.pack(OBJECT_STRUCTURE))
51
- when :bson then BSON::BSON_JAVA.deserialize(BSON::BSON_JAVA.serialize(OBJECT_STRUCTURE).to_s)
57
+ when :bson then BSON_IMPL.deserialize(BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s)
52
58
  when :json then JSON.parse(OBJECT_STRUCTURE.to_json)
53
59
  end
54
60
  end
@@ -58,7 +64,7 @@ Viiite.bm do |b|
58
64
  ITERATIONS.times do
59
65
  case lib
60
66
  when :msgpack then MessagePack.pack(MessagePack.unpack(ENCODED_MSGPACK))
61
- when :bson then BSON::BSON_JAVA.serialize(BSON::BSON_JAVA.deserialize(ENCODED_BSON)).to_s
67
+ when :bson then BSON_IMPL.serialize(BSON_IMPL.deserialize(ENCODED_BSON)).to_s
62
68
  when :json then OBJECT_STRUCTURE.to_json(JSON.parse(ENCODED_JSON))
63
69
  end
64
70
  end
@@ -0,0 +1,159 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require_relative '../spec_helper'
4
+ require 'stringio'
5
+ require 'tempfile'
6
+
7
+
8
+ describe ::MessagePack::Unpacker do
9
+ subject do
10
+ described_class.new
11
+ end
12
+
13
+ let :buffer1 do
14
+ MessagePack.pack(:foo => 'bar')
15
+ end
16
+
17
+ let :buffer2 do
18
+ MessagePack.pack(:hello => {:world => [1, 2, 3]})
19
+ end
20
+
21
+ let :buffer3 do
22
+ MessagePack.pack(:x => 'y')
23
+ end
24
+
25
+ describe '#execute/#execute_limit/#finished?' do
26
+ let :buffer do
27
+ buffer1 + buffer2 + buffer3
28
+ end
29
+
30
+ it 'extracts an object from the buffer' do
31
+ subject.execute(buffer, 0)
32
+ subject.data.should == {'foo' => 'bar'}
33
+ end
34
+
35
+ it 'extracts an object from the buffer, starting at an offset' do
36
+ subject.execute(buffer, buffer1.length)
37
+ subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
38
+ end
39
+
40
+ it 'extracts an object from the buffer, starting at an offset reading bytes up to a limit' do
41
+ subject.execute_limit(buffer, buffer1.length, buffer2.length)
42
+ subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
43
+ end
44
+
45
+ it 'extracts nothing if the limit cuts an object in half' do
46
+ subject.execute_limit(buffer, buffer1.length, 3)
47
+ subject.data.should be_nil
48
+ end
49
+
50
+ it 'returns the offset where the object ended' do
51
+ subject.execute(buffer, 0).should == buffer1.length
52
+ subject.execute(buffer, buffer1.length).should == buffer1.length + buffer2.length
53
+ end
54
+
55
+ it 'is finished if #data returns an object' do
56
+ subject.execute_limit(buffer, buffer1.length, buffer2.length)
57
+ subject.should be_finished
58
+
59
+ subject.execute_limit(buffer, buffer1.length, 3)
60
+ subject.should_not be_finished
61
+ end
62
+ end
63
+
64
+ describe '#each' do
65
+ context 'with a buffer' do
66
+ it 'yields each object in the buffer' do
67
+ objects = []
68
+ subject.feed(buffer1)
69
+ subject.feed(buffer2)
70
+ subject.feed(buffer3)
71
+ subject.each do |obj|
72
+ objects << obj
73
+ end
74
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
75
+ end
76
+
77
+ it 'returns an enumerator when no block is given' do
78
+ subject.feed(buffer1)
79
+ subject.feed(buffer2)
80
+ subject.feed(buffer3)
81
+ enum = subject.each
82
+ enum.map { |obj| obj.keys.first }.should == %w[foo hello x]
83
+ end
84
+ end
85
+
86
+ context 'with a StringIO stream' do
87
+ it 'yields each object in the stream' do
88
+ objects = []
89
+ subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
90
+ subject.each do |obj|
91
+ objects << obj
92
+ end
93
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
94
+ end
95
+ end
96
+
97
+ context 'with a File stream' do
98
+ it 'yields each object in the stream' do
99
+ objects = []
100
+ file = Tempfile.new('msgpack')
101
+ file.write(buffer1)
102
+ file.write(buffer2)
103
+ file.write(buffer3)
104
+ file.open
105
+ subject.stream = file
106
+ subject.each do |obj|
107
+ objects << obj
108
+ end
109
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
110
+ end
111
+ end
112
+
113
+ context 'with a stream passed to the constructor' do
114
+ it 'yields each object in the stream' do
115
+ objects = []
116
+ unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3))
117
+ unpacker.each do |obj|
118
+ objects << obj
119
+ end
120
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
121
+ end
122
+ end
123
+ end
124
+
125
+ describe '#feed_each' do
126
+ it 'feeds the buffer then runs #each' do
127
+ objects = []
128
+ subject.feed_each(buffer1 + buffer2 + buffer3) do |obj|
129
+ objects << obj
130
+ end
131
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
132
+ end
133
+ end
134
+
135
+ describe '#fill' do
136
+ it 'is a no-op' do
137
+ subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
138
+ subject.fill
139
+ subject.each { |obj| }
140
+ end
141
+ end
142
+
143
+ describe '#reset' do
144
+ context 'with a buffer' do
145
+ it 'is unclear what it is supposed to do'
146
+ end
147
+
148
+ context 'with a stream' do
149
+ it 'is unclear what it is supposed to do'
150
+ end
151
+ end
152
+
153
+ context 'regressions' do
154
+ it 'handles massive arrays (issue #2)' do
155
+ array = ['foo'] * 10_000
156
+ MessagePack.unpack(MessagePack.pack(array)).should have(10_000).items
157
+ end
158
+ end
159
+ end
data/spec/msgpack_spec.rb CHANGED
@@ -69,8 +69,13 @@ describe MessagePack do
69
69
  end
70
70
 
71
71
  context 'with other things' do
72
- it 'raises an error on #pack' do
72
+ it 'raises an error on #pack with an unsupported type' do
73
73
  expect { MessagePack.pack(self) }.to raise_error(ArgumentError, /^Cannot pack type:/)
74
74
  end
75
+
76
+ it 'rasies an error on #unpack with garbage' do
77
+ pending
78
+ expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
79
+ end
75
80
  end
76
81
  end
metadata CHANGED
@@ -1,76 +1,70 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: msgpack-jruby
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 1
7
- - 0
8
- - 0
9
- version: 1.0.0
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.1.3
10
6
  platform: java
11
- authors:
7
+ authors:
12
8
  - Theo Hultberg
13
- autorequire:
9
+ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-09-15 00:00:00 +02:00
18
- default_executable:
12
+ date: 2012-06-14 00:00:00.000000000Z
19
13
  dependencies: []
20
-
21
14
  description: JRuby compatible MessagePack implementation that does not use FFI
22
- email:
15
+ email:
23
16
  - theo@iconara.net
24
17
  executables: []
25
-
26
18
  extensions: []
27
-
28
19
  extra_rdoc_files: []
29
-
30
- files:
20
+ files:
31
21
  - .gitignore
32
22
  - .rspec
33
23
  - .rvmrc
34
24
  - Gemfile
25
+ - Gemfile.lock
35
26
  - Rakefile
36
- - ext/java/org/msgpack/jruby/MessagePack.java
37
- - lib/ext/msgpack-0.5.2-devel.jar
38
- - lib/ext/org/msgpack/jruby/MessagePack.class
27
+ - ext/.gitignore
28
+ - ext/java/MsgpackJrubyService.java
29
+ - ext/java/org/msgpack/jruby/MessagePackLibrary.java
30
+ - ext/java/org/msgpack/jruby/RubyObjectPacker.java
31
+ - ext/java/org/msgpack/jruby/RubyObjectUnpacker.java
32
+ - lib/ext/javassist-3.15.0-GA.jar
33
+ - lib/ext/msgpack-0.6.6.jar
34
+ - lib/ext/msgpack_jruby.jar
39
35
  - lib/msgpack.rb
40
36
  - lib/msgpack/version.rb
41
37
  - msgpack-jruby.gemspec
42
38
  - spec/benchmark.rb
39
+ - spec/msgpack/unpacker_spec.rb
43
40
  - spec/msgpack_spec.rb
44
41
  - spec/spec_helper.rb
45
- has_rdoc: true
46
42
  homepage: http://github.com/iconara/msgpack-jruby
47
43
  licenses: []
48
-
49
- post_install_message:
44
+ post_install_message:
50
45
  rdoc_options: []
51
-
52
- require_paths:
46
+ require_paths:
53
47
  - lib
54
- required_ruby_version: !ruby/object:Gem::Requirement
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- segments:
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ segments:
59
53
  - 0
60
- version: "0"
61
- required_rubygems_version: !ruby/object:Gem::Requirement
62
- requirements:
63
- - - ">="
64
- - !ruby/object:Gem::Version
65
- segments:
66
- - 0
67
- version: "0"
54
+ hash: 2
55
+ version: '0'
56
+ none: false
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ none: false
68
63
  requirements: []
69
-
70
64
  rubyforge_project: msgpack-jruby
71
- rubygems_version: 1.3.6
72
- signing_key:
65
+ rubygems_version: 1.8.15
66
+ signing_key:
73
67
  specification_version: 3
74
68
  summary: MessagePack implementation for JRuby
75
69
  test_files: []
76
-
70
+ ...
@@ -1,156 +0,0 @@
1
- package org.msgpack.jruby;
2
-
3
-
4
- import java.io.IOException;
5
- import java.io.ByteArrayOutputStream;
6
- import java.math.BigInteger;
7
- import java.util.Map;
8
- import java.util.HashMap;
9
- import java.lang.reflect.Field;
10
- import org.jruby.runtime.builtin.IRubyObject;
11
- import org.jruby.Ruby;
12
- import org.jruby.RubyObject;
13
- import org.jruby.RubyString;
14
- import org.jruby.RubySymbol;
15
- import org.jruby.RubyArray;
16
- import org.jruby.RubyHash;
17
- import org.jruby.RubyBoolean;
18
- import org.jruby.RubyInteger;
19
- import org.jruby.RubyFixnum;
20
- import org.jruby.RubyFloat;
21
- import org.jruby.RubyBignum;
22
- import org.jruby.RubyNil;
23
- import org.msgpack.Packer;
24
- import org.msgpack.Unpacker;
25
- import org.msgpack.MessagePackObject;
26
- import org.msgpack.MessageTypeException;
27
- import org.msgpack.object.MapType;
28
-
29
-
30
- public class MessagePack {
31
- private static final MessagePack instance = new MessagePack();
32
-
33
- public static RubyString pack(RubyObject o) throws IOException {
34
- return instance.packObject(o);
35
- }
36
-
37
- public static RubyObject unpack(RubyString s) throws IOException {
38
- return instance.unpackString(s);
39
- }
40
-
41
- public RubyString packObject(IRubyObject o) throws IOException {
42
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
43
- _pack(o, new Packer(stream));
44
- Ruby runtime = o == null ? Ruby.getGlobalRuntime() : o.getRuntime();
45
- return RubyString.newString(runtime, stream.toByteArray());
46
- }
47
-
48
- private void _pack(IRubyObject o, Packer packer) throws IOException {
49
- if (o == null || o instanceof RubyNil) {
50
- packer.packNil();
51
- } else if (o instanceof RubyBoolean) {
52
- packer.packBoolean((Boolean) ((RubyBoolean) o).toJava(Boolean.class));
53
- } else if (o instanceof RubyBignum) {
54
- packer.packBigInteger(((RubyBignum) o).getBigIntegerValue());
55
- } else if (o instanceof RubyInteger) {
56
- packer.packLong(((RubyInteger) o).getLongValue());
57
- } else if (o instanceof RubyFixnum) {
58
- packer.packLong(((RubyFixnum) o).getLongValue());
59
- } else if (o instanceof RubyFloat) {
60
- packer.packDouble(((RubyFloat) o).getDoubleValue());
61
- } else if (o instanceof RubyString) {
62
- byte[] bytes = ((RubyString) o).getBytes();
63
- packer.packRaw(bytes.length);
64
- packer.packRawBody(bytes);
65
- } else if (o instanceof RubySymbol) {
66
- _pack((IRubyObject) ((RubySymbol) o).to_s(), packer);
67
- } else if (o instanceof RubyArray) {
68
- RubyArray array = (RubyArray) o;
69
- int count = array.size();
70
- packer.packArray(count);
71
- for (int i = 0; i < count; i++) {
72
- _pack(array.entry(i), packer);
73
- }
74
- } else if (o instanceof RubyHash) {
75
- RubyHash hash = (RubyHash) o;
76
- int count = hash.size();
77
- packer.packMap(count);
78
- RubyArray keys = hash.keys();
79
- RubyArray values = hash.rb_values();
80
- for (int i = 0; i < count; i++) {
81
- _pack(keys.entry(i), packer);
82
- _pack(values.entry(i), packer);
83
- }
84
- } else {
85
- throw Ruby.getGlobalRuntime().newArgumentError(String.format("Cannot pack type: %s", o.getClass().getName()));
86
- }
87
- }
88
-
89
- public RubyObject unpackString(RubyString blob) throws IOException {
90
- RubyObject obj = null;
91
- Unpacker unpacker = new Unpacker();
92
- unpacker.wrap(blob.getBytes());
93
- return _unpack(unpacker.iterator().next(), blob.getRuntime());
94
- }
95
-
96
- private static Field cachedMapField = null;
97
-
98
- private RubyObject _unpack(MessagePackObject mpo, Ruby runtime) throws IOException {
99
- if (mpo.isNil()) {
100
- return null;
101
- } else if (mpo.isBooleanType()) {
102
- return RubyBoolean.newBoolean(runtime, mpo.asBoolean());
103
- } else if (mpo.isIntegerType()) {
104
- try {
105
- return RubyFixnum.newFixnum(runtime, mpo.asLong());
106
- } catch (MessageTypeException mte) {
107
- return RubyBignum.newBignum(runtime, mpo.asBigInteger());
108
- }
109
- } else if (mpo.isFloatType()) {
110
- return RubyFloat.newFloat(runtime, mpo.asDouble());
111
- } else if (mpo.isArrayType()) {
112
- MessagePackObject[] mpoElements = mpo.asArray();
113
- RubyObject[] elements = new RubyObject[mpoElements.length];
114
- int count = mpoElements.length;
115
- for (int i = 0; i < count; i++ ) {
116
- elements[i] = _unpack(mpoElements[i], runtime);
117
- }
118
- return RubyArray.newArray(runtime, elements);
119
- } else if (mpo.isMapType()) {
120
- // This is hackish, but the only way to make sure that hashes
121
- // keep their order. MessagePack's unpacking subsystem does not
122
- // expose the key/value pair array, only a Map constructed from
123
- // that array. This code first attempts to get that array from a
124
- // private field, and if that fails it falls back on using the
125
- // unordered Map.
126
- RubyHash hash = null;
127
- try {
128
- if (cachedMapField == null) {
129
- cachedMapField = mpo.getClass().getDeclaredField("map");
130
- cachedMapField.setAccessible(true);
131
- }
132
- MessagePackObject[] keyValuePairs = (MessagePackObject[]) cachedMapField.get(mpo);
133
- int count = keyValuePairs.length;
134
- hash = RubyHash.newHash(runtime);
135
- for (int i = 0; i < count; i += 2) {
136
- hash.put(_unpack(keyValuePairs[i], runtime), _unpack(keyValuePairs[i + 1], runtime));
137
- }
138
- } catch (IllegalAccessException iae) {
139
- } catch (NoSuchFieldException nfe) {
140
- }
141
- if (hash == null) {
142
- Map<MessagePackObject, MessagePackObject> mpoMap = mpo.asMap();
143
- hash = RubyHash.newHash(runtime);
144
- for (Map.Entry<MessagePackObject, MessagePackObject> entry : mpoMap.entrySet()) {
145
- hash.put(_unpack(entry.getKey(), runtime), _unpack(entry.getValue(), runtime));
146
- }
147
- }
148
- return hash;
149
-
150
- } else if (mpo.isRawType()) {
151
- return RubyString.newString(runtime, mpo.asByteArray());
152
- } else {
153
- throw runtime.newArgumentError(String.format("Cannot upack type: %s", mpo.getClass().getName()));
154
- }
155
- }
156
- }
Binary file