Merge branch 'master' of git@github.com:msgpack/msgpack

This commit is contained in:
Muga Nishizawa 2010-12-01 21:20:10 +09:00
commit 53b0ee6536
58 changed files with 3795 additions and 126 deletions

View File

@ -18,6 +18,7 @@
package org.msgpack;
import java.lang.annotation.Annotation;
import org.msgpack.template.TemplateRegistry;
public class CustomMessage {
public static void registerPacker(Class<?> target, MessagePacker packer) {
@ -33,6 +34,7 @@ public class CustomMessage {
}
public static void register(Class<?> target, Template tmpl) {
TemplateRegistry.register(target, tmpl);
CustomPacker.register(target, tmpl);
CustomConverter.register(target, tmpl);
CustomUnpacker.register(target, tmpl);

View File

@ -27,6 +27,8 @@ import java.lang.reflect.Method;
import org.msgpack.util.codegen.DynamicTemplate;
import org.msgpack.util.codegen.DynamicOrdinalEnumTemplate;
import org.msgpack.util.codegen.FieldList;
import org.msgpack.template.TemplateRegistry;
import org.msgpack.template.TemplateBuilder;
public class MessagePack {
public static byte[] pack(Object obj) {
@ -150,6 +152,8 @@ public class MessagePack {
}
public static void register(Class<?> target) { // auto-detect
TemplateRegistry.register(target);
Template tmpl;
if(target.isEnum()) {
tmpl = DynamicOrdinalEnumTemplate.create(target);
@ -194,6 +198,7 @@ public class MessagePack {
}
public static void register(Class<?> target, FieldList opts) {
TemplateRegistry.register(target); // FIXME FieldList
Template tmpl = DynamicTemplate.create(target, opts);
CustomPacker.register(target, tmpl);
CustomConverter.register(target, tmpl);
@ -201,6 +206,7 @@ public class MessagePack {
}
public static void register(Class<?> target, Template tmpl) {
TemplateRegistry.register(target, tmpl);
CustomPacker.register(target, tmpl);
CustomConverter.register(target, tmpl);
CustomUnpacker.register(target, tmpl);

View File

@ -21,14 +21,9 @@ import java.util.List;
import java.util.Set;
import java.util.Map;
import java.math.BigInteger;
import org.msgpack.template.ClassTemplate;
import org.msgpack.template.NullableTemplate;
import org.msgpack.template.TemplateRegistry;
public abstract class MessagePackObject implements Cloneable, MessagePackable {
static {
Templates.load();
}
public boolean isNil() {
return false;
}
@ -155,9 +150,11 @@ public abstract class MessagePackObject implements Cloneable, MessagePackable {
return convert((Class<T>)to.getClass(), to);
}
private <T> T convert(Class<T> klass, T to) throws MessageTypeException {
// FIXME nullable?
return (T)convert(new NullableTemplate(new ClassTemplate(klass)), to);
public <T> T convert(Class<T> klass, T to) throws MessageTypeException {
if(isNil()) {
return null;
}
return (T)convert(TemplateRegistry.lookup(klass), to);
}
}

View File

@ -27,5 +27,9 @@ public class MessageTypeException extends RuntimeException {
public MessageTypeException(String s, Throwable t) {
super(s, t);
}
public MessageTypeException(Throwable t) {
super(t);
}
}

View File

@ -25,11 +25,7 @@ import java.util.Set;
import java.util.Map;
import java.util.Collection;
import java.math.BigInteger;
import org.msgpack.annotation.MessagePackDelegate;
import org.msgpack.annotation.MessagePackMessage;
import org.msgpack.annotation.MessagePackOrdinalEnum;
import org.msgpack.util.codegen.DynamicTemplate;
import org.msgpack.template.TemplateRegistry;
/**
* Packer enables you to serialize objects into OutputStream.
@ -48,14 +44,10 @@ import org.msgpack.util.codegen.DynamicTemplate;
* You can serialize objects that implements {@link MessagePackable} interface.
*/
public class Packer {
static {
Templates.load();
}
public static void load() { }
protected byte[] castBytes = new byte[9];
protected ByteBuffer castBuffer = ByteBuffer.wrap(castBytes);
//protected ByteBuffer castBuffer = ByteBuffer.wrap(castBytes);
protected OutputStream out;
public Packer(OutputStream out) {
@ -78,7 +70,9 @@ public class Packer {
if(d < -(1<<7)) {
// signed 16
castBytes[0] = (byte)0xd1;
castBuffer.putShort(1, d);
// castBuffer.putShort(1, d);
castBytes[1] = (byte)(d >> 8);
castBytes[2] = (byte)(d >> 0);
out.write(castBytes, 0, 3);
} else {
// signed 8
@ -98,7 +92,9 @@ public class Packer {
} else {
// unsigned 16
castBytes[0] = (byte)0xcd;
castBuffer.putShort(1, d);
// castBuffer.putShort(1, d);
castBytes[1] = (byte)(d >> 8);
castBytes[2] = (byte)(d >> 0);
out.write(castBytes, 0, 3);
}
}
@ -110,12 +106,18 @@ public class Packer {
if(d < -(1<<15)) {
// signed 32
castBytes[0] = (byte)0xd2;
castBuffer.putInt(1, d);
// castBuffer.putInt(1, d);
castBytes[1] = (byte)(d >> 24);
castBytes[2] = (byte)(d >> 16);
castBytes[3] = (byte)(d >> 8);
castBytes[4] = (byte)(d >> 0);
out.write(castBytes, 0, 5);
} else if(d < -(1<<7)) {
// signed 16
castBytes[0] = (byte)0xd1;
castBuffer.putShort(1, (short)d);
// castBuffer.putShort(1, (short)d);
castBytes[1] = (byte)(d >> 8);
castBytes[2] = (byte)(d >> 0);
out.write(castBytes, 0, 3);
} else {
// signed 8
@ -135,12 +137,18 @@ public class Packer {
} else if(d < (1<<16)) {
// unsigned 16
castBytes[0] = (byte)0xcd;
castBuffer.putShort(1, (short)d);
// castBuffer.putShort(1, (short)d);
castBytes[1] = (byte)(d >> 8);
castBytes[2] = (byte)(d >> 0);
out.write(castBytes, 0, 3);
} else {
// unsigned 32
castBytes[0] = (byte)0xce;
castBuffer.putInt(1, d);
// castBuffer.putInt(1, d);
castBytes[1] = (byte)(d >> 24);
castBytes[2] = (byte)(d >> 16);
castBytes[3] = (byte)(d >> 8);
castBytes[4] = (byte)(d >> 0);
out.write(castBytes, 0, 5);
}
}
@ -153,19 +161,33 @@ public class Packer {
if(d < -(1L<<31)) {
// signed 64
castBytes[0] = (byte)0xd3;
castBuffer.putLong(1, d);
// castBuffer.putLong(1, d);
castBytes[1] = (byte)(d >> 56);
castBytes[2] = (byte)(d >> 48);
castBytes[3] = (byte)(d >> 40);
castBytes[4] = (byte)(d >> 32);
castBytes[5] = (byte)(d >> 24);
castBytes[6] = (byte)(d >> 16);
castBytes[7] = (byte)(d >> 8);
castBytes[8] = (byte)(d >> 0);
out.write(castBytes, 0, 9);
} else {
// signed 32
castBytes[0] = (byte)0xd2;
castBuffer.putInt(1, (int)d);
// castBuffer.putInt(1, (int)d);
castBytes[1] = (byte)(d >> 24);
castBytes[2] = (byte)(d >> 16);
castBytes[3] = (byte)(d >> 8);
castBytes[4] = (byte)(d >> 0);
out.write(castBytes, 0, 5);
}
} else {
if(d < -(1<<7)) {
// signed 16
castBytes[0] = (byte)0xd1;
castBuffer.putShort(1, (short)d);
// castBuffer.putShort(1, (short)d);
castBytes[1] = (byte)(d >> 8);
castBytes[2] = (byte)(d >> 0);
out.write(castBytes, 0, 3);
} else {
// signed 8
@ -187,7 +209,9 @@ public class Packer {
} else {
// unsigned 16
castBytes[0] = (byte)0xcd;
castBuffer.putShort(1, (short)d);
// castBuffer.putShort(1, (short)d);
castBytes[1] = (byte)((d & 0x0000ff00) >> 8);
castBytes[2] = (byte)((d & 0x000000ff) >> 0);
out.write(castBytes, 0, 3);
//System.out.println("pack uint 16 "+(short)d);
}
@ -195,12 +219,24 @@ public class Packer {
if(d < (1L<<32)) {
// unsigned 32
castBytes[0] = (byte)0xce;
castBuffer.putInt(1, (int)d);
// castBuffer.putInt(1, (int)d);
castBytes[1] = (byte)((d & 0xff000000) >> 24);
castBytes[2] = (byte)((d & 0x00ff0000) >> 16);
castBytes[3] = (byte)((d & 0x0000ff00) >> 8);
castBytes[4] = (byte)((d & 0x000000ff) >> 0);
out.write(castBytes, 0, 5);
} else {
// unsigned 64
castBytes[0] = (byte)0xcf;
castBuffer.putLong(1, d);
// castBuffer.putLong(1, d);
castBytes[1] = (byte)(d >> 56);
castBytes[2] = (byte)(d >> 48);
castBytes[3] = (byte)(d >> 40);
castBytes[4] = (byte)(d >> 32);
castBytes[5] = (byte)(d >> 24);
castBytes[6] = (byte)(d >> 16);
castBytes[7] = (byte)(d >> 8);
castBytes[8] = (byte)(d >> 0);
out.write(castBytes, 0, 9);
}
}
@ -222,7 +258,7 @@ public class Packer {
castBytes[6] = barray[barray.length-3];
castBytes[7] = barray[barray.length-2];
castBytes[8] = barray[barray.length-1];
out.write(castBytes);
out.write(castBytes, 0, 9);
return this;
} else {
throw new MessageTypeException("can't pack BigInteger larger than 0xffffffffffffffff");
@ -231,14 +267,28 @@ public class Packer {
public Packer packFloat(float d) throws IOException {
castBytes[0] = (byte)0xca;
castBuffer.putFloat(1, d);
// castBuffer.putFloat(1, d);
int f = Float.floatToRawIntBits(d);
castBytes[1] = (byte)(f >> 24);
castBytes[2] = (byte)(f >> 16);
castBytes[3] = (byte)(f >> 8);
castBytes[4] = (byte)(f >> 0);
out.write(castBytes, 0, 5);
return this;
}
public Packer packDouble(double d) throws IOException {
castBytes[0] = (byte)0xcb;
castBuffer.putDouble(1, d);
// castBuffer.putDouble(1, d);
long f = Double.doubleToRawLongBits(d);
castBytes[1] = (byte)(f >> 56);
castBytes[2] = (byte)(f >> 48);
castBytes[3] = (byte)(f >> 40);
castBytes[4] = (byte)(f >> 32);
castBytes[5] = (byte)(f >> 24);
castBytes[6] = (byte)(f >> 16);
castBytes[7] = (byte)(f >> 8);
castBytes[8] = (byte)(f >> 0);
out.write(castBytes, 0, 9);
return this;
}
@ -268,11 +318,17 @@ public class Packer {
out.write((byte)d);
} else if(n < 65536) {
castBytes[0] = (byte)0xdc;
castBuffer.putShort(1, (short)n);
// castBuffer.putShort(1, (short)n);
castBytes[1] = (byte)(n >> 8);
castBytes[2] = (byte)(n >> 0);
out.write(castBytes, 0, 3);
} else {
castBytes[0] = (byte)0xdd;
castBuffer.putInt(1, n);
// castBuffer.putInt(1, n);
castBytes[1] = (byte)(n >> 24);
castBytes[2] = (byte)(n >> 16);
castBytes[3] = (byte)(n >> 8);
castBytes[4] = (byte)(n >> 0);
out.write(castBytes, 0, 5);
}
return this;
@ -284,11 +340,17 @@ public class Packer {
out.write((byte)d);
} else if(n < 65536) {
castBytes[0] = (byte)0xde;
castBuffer.putShort(1, (short)n);
// castBuffer.putShort(1, (short)n);
castBytes[1] = (byte)(n >> 8);
castBytes[2] = (byte)(n >> 0);
out.write(castBytes, 0, 3);
} else {
castBytes[0] = (byte)0xdf;
castBuffer.putInt(1, n);
// castBuffer.putInt(1, n);
castBytes[1] = (byte)(n >> 24);
castBytes[2] = (byte)(n >> 16);
castBytes[3] = (byte)(n >> 8);
castBytes[4] = (byte)(n >> 0);
out.write(castBytes, 0, 5);
}
return this;
@ -300,11 +362,17 @@ public class Packer {
out.write((byte)d);
} else if(n < 65536) {
castBytes[0] = (byte)0xda;
castBuffer.putShort(1, (short)n);
// castBuffer.putShort(1, (short)n);
castBytes[1] = (byte)(n >> 8);
castBytes[2] = (byte)(n >> 0);
out.write(castBytes, 0, 3);
} else {
castBytes[0] = (byte)0xdb;
castBuffer.putInt(1, n);
// castBuffer.putInt(1, n);
castBytes[1] = (byte)(n >> 24);
castBytes[2] = (byte)(n >> 16);
castBytes[3] = (byte)(n >> 8);
castBytes[4] = (byte)(n >> 0);
out.write(castBytes, 0, 5);
}
return this;
@ -449,7 +517,8 @@ public class Packer {
}
public Packer pack(Object o) throws IOException {
Templates.TAny.pack(this, o);
if(o == null) { return packNil(); }
TemplateRegistry.lookup(o.getClass()).pack(this, o);
return this;
}

View File

@ -20,8 +20,6 @@ package org.msgpack;
import org.msgpack.template.*;
public class Templates {
public static void load() { }
public static Template tNullable(Template elementTemplate) {
return new NullableTemplate(elementTemplate);
}
@ -46,7 +44,11 @@ public class Templates {
}
public static Template tClass(Class target) {
return new ClassTemplate(target);
Template tmpl = TemplateRegistry.lookup(target);
if(tmpl == null) {
// FIXME
}
return tmpl;
}
public static final Template TByte = ByteTemplate.getInstance();

View File

@ -23,8 +23,7 @@ import java.io.IOException;
import java.util.Iterator;
import java.nio.ByteBuffer;
import java.math.BigInteger;
import org.msgpack.template.ClassTemplate;
import org.msgpack.template.NullableTemplate;
import org.msgpack.template.TemplateRegistry;
/**
* Unpacker enables you to deserialize objects from stream.
@ -105,10 +104,6 @@ import org.msgpack.template.NullableTemplate;
* </pre>
*/
public class Unpacker implements Iterable<MessagePackObject> {
static {
Templates.load();
}
// buffer:
// +---------------------------------------------+
// | [object] | [obje| unparsed ... | unused ...|
@ -578,6 +573,19 @@ public class Unpacker implements Iterable<MessagePackObject> {
// return unpackObject();
//}
final public <T> T unpack(T to) throws IOException, MessageTypeException {
return unpack((Class<T>)to.getClass(), to);
}
final public <T> T unpack(Class<T> klass) throws IOException, MessageTypeException {
return unpack(klass, null);
}
final public <T> T unpack(Class<T> klass, T to) throws IOException, MessageTypeException {
if(tryUnpackNull()) { return null; }
return (T)TemplateRegistry.lookup(klass).unpack(this, to);
}
final public Object unpack(Template tmpl) throws IOException, MessageTypeException {
return unpack(tmpl, null);
}
@ -585,18 +593,5 @@ public class Unpacker implements Iterable<MessagePackObject> {
final public <T> T unpack(Template tmpl, T to) throws IOException, MessageTypeException {
return (T)tmpl.unpack(this, to);
}
final public <T> T unpack(Class<T> klass) throws IOException, MessageTypeException {
return unpack(klass, null);
}
final public <T> T unpack(T to) throws IOException, MessageTypeException {
return unpack((Class<T>)to.getClass(), to);
}
final public <T> T unpack(Class<T> klass, T to) throws IOException, MessageTypeException {
// FIXME nullable?
return (T)unpack(new NullableTemplate(new ClassTemplate(klass)), to);
}
}

View File

@ -0,0 +1,28 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Ignore {
}

View File

@ -0,0 +1,29 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
int value();
}

View File

@ -25,4 +25,5 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessagePackDelegate {
String value();
}

View File

@ -21,8 +21,10 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.msgpack.template.FieldOption;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessagePackMessage {
FieldOption value() default FieldOption.DEFAULT;
}

View File

@ -0,0 +1,28 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Required {
}

View File

@ -0,0 +1,462 @@
//
// MessagePack for Java
//
// Copyright (C) 2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.buffer;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
public class VectoredByteBuffer implements GatheringByteChannel, ScatteringByteChannel {
private List<ByteBuffer> vec = new ArrayList<ByteBuffer>();
private ByteBuffer internalBuffer;
private ByteBuffer lastInternalBuffer;
private int chunkSize;
private int referenceThreshold;
public VectoredByteBuffer() {
this(32*1024);
}
public VectoredByteBuffer(int chunkSize) {
this(chunkSize, 32);
}
public VectoredByteBuffer(int chunkSize, int referenceThreshold) {
this.chunkSize = chunkSize;
this.referenceThreshold = referenceThreshold;
internalBuffer = ByteBuffer.allocateDirect(chunkSize);
}
public void setChunkSize(int chunkSize) {
this.chunkSize = chunkSize;
}
public int getChunkSize(int chunkSize) {
return this.chunkSize;
}
public void setReferenceThreshold(int referenceThreshold) {
this.referenceThreshold = referenceThreshold;
}
public int getReferenceThreshold(int referenceThreshold) {
return this.referenceThreshold;
}
@Override
public void close() {
reset();
}
@Override
public boolean isOpen() {
return true; // FIXME?
}
public synchronized void reset() {
vec.clear();
lastInternalBuffer = null;
}
public void write(byte[] b) {
write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) {
if(off < 0 || len < 0 || b.length < off+len) {
throw new IndexOutOfBoundsException();
}
if(referenceThreshold >= 0 && len > referenceThreshold) {
writeReference(b, off, len);
} else {
writeCopy(b, off, len);
}
}
public void write(int b) {
byte[] ba = new byte[1];
ba[0] = (byte)b;
write(ba);
}
@Override
public int write(ByteBuffer src) {
int slen = src.remaining();
if(referenceThreshold >= 0 && slen > referenceThreshold) {
writeCopy(src);
} else {
writeReference(src);
}
return slen;
}
@Override
public synchronized long write(ByteBuffer[] srcs) {
return write(srcs, 0, srcs.length);
}
@Override
public synchronized long write(ByteBuffer[] srcs, int offset, int length) {
if(offset < 0 || length < 0 || srcs.length < offset+length) {
throw new IndexOutOfBoundsException();
}
long total = 0;
for(int i=offset; offset < length; offset++) {
ByteBuffer src = srcs[i];
total += write(src);
}
return total;
}
private synchronized void writeCopy(byte[] b, int off, int len) {
int ipos = internalBuffer.position();
if(internalBuffer.capacity() - ipos < len) {
// allocate new buffer
int nsize = chunkSize > len ? chunkSize : len;
internalBuffer = ByteBuffer.allocateDirect(nsize);
ipos = 0;
} else if(internalBuffer == lastInternalBuffer) {
// optimization: concatenates to the last buffer instead
// of adding new reference
ByteBuffer dup = vec.get(vec.size()-1);
internalBuffer.put(b, off, len);
dup.limit(ipos + len);
return;
}
internalBuffer.put(b, off, len);
ByteBuffer dup = internalBuffer.duplicate();
dup.position(ipos);
dup.mark();
dup.limit(ipos + len);
vec.add(dup);
lastInternalBuffer = internalBuffer;
}
private synchronized void writeCopy(ByteBuffer src) {
int slen = src.remaining();
int ipos = internalBuffer.position();
if(internalBuffer.capacity() - ipos < slen) {
// allocate new buffer
int nsize = chunkSize > slen ? chunkSize : slen;
internalBuffer = ByteBuffer.allocateDirect(nsize);
ipos = 0;
} else if(internalBuffer == lastInternalBuffer) {
// optimization: concatenates to the last buffer instead
// of adding new reference
ByteBuffer dup = vec.get(vec.size()-1);
int dpos = dup.position();
internalBuffer.put(src);
ByteBuffer dup2 = internalBuffer.duplicate();
dup2.position(dpos);
dup2.limit(ipos + slen);
vec.set(vec.size()-1, dup2);
return;
}
internalBuffer.put(src);
ByteBuffer dup = internalBuffer.duplicate();
dup.position(ipos);
dup.mark();
dup.limit(ipos + slen);
vec.add(dup);
lastInternalBuffer = internalBuffer;
}
private synchronized void writeReference(byte[] b, int off, int len) {
ByteBuffer buf = ByteBuffer.wrap(b, off, len);
vec.add(buf);
lastInternalBuffer = null;
}
private synchronized void writeReference(ByteBuffer src) {
ByteBuffer buf = src.duplicate();
vec.add(buf);
lastInternalBuffer = null;
}
public synchronized void writeTo(java.io.OutputStream out) throws IOException {
byte[] tmpbuf = null;
for(int i=0; i < vec.size(); i++) {
ByteBuffer r = vec.get(i);
int rpos = r.position();
int rlen = r.limit() - rpos;
if(r.hasArray()) {
byte[] array = r.array();
out.write(array, rpos, rlen);
} else {
if(tmpbuf == null) {
int max = rlen;
for(int j=i+1; j < vec.size(); j++) {
ByteBuffer c = vec.get(j);
int clen = c.remaining();
if(max < clen) {
max = clen;
}
}
tmpbuf = new byte[max];
}
r.get(tmpbuf, 0, rlen);
r.position(rpos);
out.write(tmpbuf, 0, rlen);
}
}
}
public synchronized byte[] toByteArray() {
byte[] out = new byte[available()];
int off = 0;
for(ByteBuffer r: vec) {
int rpos = r.position();
int rlen = r.limit() - rpos;
r.get(out, off, rlen);
r.position(rpos);
off += rlen;
}
return out;
}
public synchronized int available() {
int total = 0;
for(ByteBuffer r : vec) {
total += r.remaining();
}
return total;
}
public synchronized int read(byte[] b) {
return read(b, 0, b.length);
}
public synchronized int read(byte[] b, int off, int len) {
if(off < 0 || len < 0 || b.length < off+len) {
throw new IndexOutOfBoundsException();
}
int start = len;
while(!vec.isEmpty()) {
ByteBuffer r = vec.get(0);
int rlen = r.remaining();
if(rlen <= len) {
r.get(b, off, rlen);
vec.remove(0);
off += rlen;
len -= rlen;
} else {
r.get(b, off, len);
return start;
}
}
return start - len;
}
public synchronized int read() {
byte[] ba = new byte[1];
if(read(ba) >= 1) {
return ba[0];
} else {
return -1;
}
}
@Override
public synchronized int read(ByteBuffer dst) {
int len = dst.remaining();
int start = len;
while(!vec.isEmpty()) {
ByteBuffer r = vec.get(0);
int rlen = r.remaining();
if(rlen <= len) {
dst.put(r);
vec.remove(0);
len -= rlen;
} else {
int blim = r.limit();
r.limit(len);
try {
dst.put(r);
} finally {
r.limit(blim);
}
return start;
}
}
return start - len;
}
@Override
public synchronized long read(ByteBuffer[] dsts) {
return read(dsts, 0, dsts.length);
}
@Override
public synchronized long read(ByteBuffer[] dsts, int offset, int length) {
if(offset < 0 || length < 0 || dsts.length < offset+length) {
throw new IndexOutOfBoundsException();
}
long total = 0;
for(int i=offset; i < length; i++) {
ByteBuffer dst = dsts[i];
int dlen = dst.remaining();
int rlen = read(dsts[i]);
total += rlen;
if(rlen < dlen) {
return total;
}
}
return total;
}
public synchronized long read(GatheringByteChannel to) throws IOException {
long total = to.write((ByteBuffer[])vec.toArray());
while(!vec.isEmpty()) {
ByteBuffer r = vec.get(0);
if(r.remaining() == 0) {
vec.remove(0);
} else {
break;
}
}
return total;
}
public synchronized long skip(long len) {
if(len <= 0) {
return 0;
}
long start = len;
while(!vec.isEmpty()) {
ByteBuffer r = vec.get(0);
int rlen = r.remaining();
if(rlen <= len) {
r.position(r.position()+rlen);
vec.remove(0);
len -= rlen;
} else {
r.position((int)(r.position()+len));
return start;
}
}
return start - len;
}
public final static class OutputStream extends java.io.OutputStream {
private VectoredByteBuffer vbb;
OutputStream(VectoredByteBuffer vbb) {
this.vbb = vbb;
}
@Override
public void write(byte[] b) {
vbb.write(b);
}
@Override
public void write(byte[] b, int off, int len) {
vbb.write(b, off, len);
}
@Override
public void write(int b) {
vbb.write(b);
}
public int write(ByteBuffer src) {
return vbb.write(src);
}
public long write(ByteBuffer[] srcs) {
return vbb.write(srcs);
}
public long write(ByteBuffer[] srcs, int offset, int length) {
return vbb.write(srcs, offset, length);
}
public void writeTo(OutputStream out) throws IOException {
vbb.writeTo(out);
}
public byte[] toByteArray() {
return vbb.toByteArray();
}
}
public final static class InputStream extends java.io.InputStream {
private VectoredByteBuffer vbb;
InputStream(VectoredByteBuffer vbb) {
this.vbb = vbb;
}
@Override
public int available() {
return vbb.available();
}
@Override
public int read(byte[] b) {
return vbb.read(b);
}
@Override
public int read(byte[] b, int off, int len) {
return vbb.read(b, off, len);
}
@Override
public int read() {
return vbb.read();
}
public int read(ByteBuffer dst) {
return vbb.read(dst);
}
public long read(ByteBuffer[] dsts, int offset, int length) {
return vbb.read(dsts, offset, length);
}
public long read(GatheringByteChannel to) throws IOException {
return vbb.read(to);
}
public long skip(long len) {
return vbb.skip(len);
}
}
public OutputStream outputStream() {
return new OutputStream(this);
}
public InputStream inputStream() {
return new InputStream(this);
}
}

View File

@ -24,10 +24,13 @@ public class AnyTemplate implements Template {
private AnyTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(target == null) {
if(target instanceof MessagePackObject) {
pk.pack((MessagePackObject)target);
} else if(target == null) {
pk.packNil();
} else {
new ClassTemplate(target.getClass()).pack(pk, target);
TemplateRegistry.lookup(target.getClass()).pack(pk, target);
//new ClassTemplate(target.getClass()).pack(pk, target);
}
}
@ -47,6 +50,7 @@ public class AnyTemplate implements Template {
static {
CustomMessage.register(MessagePackObject.class, instance);
TemplateRegistry.register(MessagePackObject.class, instance);
}
}

View File

@ -44,6 +44,7 @@ public class BigIntegerTemplate implements Template {
static {
CustomMessage.register(BigInteger.class, instance);
TemplateRegistry.register(BigInteger.class, instance);
}
}

View File

@ -0,0 +1,76 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import org.msgpack.*;
public class BooleanArrayTemplate implements Template {
private BooleanArrayTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof boolean[])) {
throw new MessageTypeException();
}
boolean[] array = (boolean[])target;
pk.packArray(array.length);
for(boolean a : array) {
pk.pack(a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
boolean[] array;
if(to != null && to instanceof boolean[] && ((boolean[])to).length == length) {
array = (boolean[])to;
} else {
array = new boolean[length];
}
for(int i=0; i < length; i++) {
array[i] = pac.unpackBoolean();
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
boolean[] array;
if(to != null && to instanceof boolean[] && ((boolean[])to).length == src.length) {
array = (boolean[])to;
} else {
array = new boolean[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = s.asBoolean();
}
return array;
}
static public BooleanArrayTemplate getInstance() {
return instance;
}
static final BooleanArrayTemplate instance = new BooleanArrayTemplate();
static {
TemplateRegistry.register(boolean[].class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class BooleanTemplate implements Template {
static {
CustomMessage.register(Boolean.class, instance);
TemplateRegistry.register(Boolean.class, instance);
TemplateRegistry.register(boolean.class, instance);
}
}

View File

@ -0,0 +1,47 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
public class BuiltInTemplateLoader {
public static void load() {
AnyTemplate.getInstance();
BigIntegerTemplate.getInstance();
BooleanArrayTemplate.getInstance();
BooleanTemplate.getInstance();
ByteArrayTemplate.getInstance();
ByteTemplate.getInstance();
DoubleArrayTemplate.getInstance();
DoubleTemplate.getInstance();
FloatArrayTemplate.getInstance();
FloatTemplate.getInstance();
IntArrayTemplate.getInstance();
IntegerTemplate.getInstance();
LongArrayTemplate.getInstance();
LongTemplate.getInstance();
ShortArrayTemplate.getInstance();
ShortTemplate.getInstance();
StringTemplate.getInstance();
CollectionTemplate.load();
ListTemplate.load();
MapTemplate.load();
NullableTemplate.load();
ObjectArrayTemplate.load();
}
}

View File

@ -43,6 +43,7 @@ public class ByteArrayTemplate implements Template {
static {
CustomMessage.register(byte[].class, instance);
TemplateRegistry.register(byte[].class, instance);
}
}

View File

@ -56,5 +56,9 @@ public class ByteBufferTemplate implements Template {
}
static final ByteBufferTemplate instance = new ByteBufferTemplate();
static {
TemplateRegistry.register(ByteBuffer.class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class ByteTemplate implements Template {
static {
CustomMessage.register(Byte.class, instance);
TemplateRegistry.register(Byte.class, instance);
TemplateRegistry.register(byte.class, instance);
}
}

View File

@ -18,6 +18,8 @@
package org.msgpack.template;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.annotation.Annotation;
import org.msgpack.*;
import org.msgpack.annotation.MessagePackDelegate;
import org.msgpack.annotation.MessagePackMessage;
@ -30,10 +32,6 @@ import java.math.BigInteger;
import java.nio.ByteBuffer;
public class ClassTemplate implements Template {
static {
Templates.load();
}
private Class<?> klass;
public ClassTemplate(Class<?> klass) {
@ -119,14 +117,14 @@ public class ClassTemplate implements Template {
// pk.packDouble((Double)o);
// return;
//}
if(o instanceof BigInteger) {
pk.packBigInteger((BigInteger)o);
return;
}
if (o instanceof ByteBuffer) { // FIXME
Templates.tByteBuffer().pack(pk, o);
return;
}
//if(o instanceof BigInteger) {
// pk.packBigInteger((BigInteger)o);
// return;
//}
//if (o instanceof ByteBuffer) {
// Templates.tByteBuffer().pack(pk, o);
// return;
//}
MessagePacker packer = CustomPacker.get(klass);
if(packer != null) {
@ -134,15 +132,15 @@ public class ClassTemplate implements Template {
return;
}
if (CustomMessage.isAnnotated(klass, MessagePackMessage.class)) {
if (isAnnotated(klass, MessagePackMessage.class)) {
Template tmpl = DynamicTemplate.create(klass);
CustomMessage.register(klass, tmpl);
tmpl.pack(pk, o);
return;
} else if (CustomMessage.isAnnotated(klass, MessagePackDelegate.class)) {
} else if (isAnnotated(klass, MessagePackDelegate.class)) {
// FIXME DelegatePacker
throw new UnsupportedOperationException("not supported yet. : " + klass.getName());
} else if (CustomMessage.isAnnotated(klass, MessagePackOrdinalEnum.class)) {
} else if (isAnnotated(klass, MessagePackOrdinalEnum.class)) {
Template tmpl = DynamicOrdinalEnumTemplate.create(klass);
CustomMessage.register(klass, tmpl);
tmpl.pack(pk, o);
@ -171,14 +169,14 @@ public class ClassTemplate implements Template {
return obj;
}
if (CustomMessage.isAnnotated(klass, MessagePackMessage.class)) {
if (isAnnotated(klass, MessagePackMessage.class)) {
Template tmpl = DynamicTemplate.create(klass);
CustomMessage.register(klass, tmpl);
return tmpl.unpack(pac, to);
} else if (CustomMessage.isAnnotated(klass, MessagePackDelegate.class)) {
} else if (isAnnotated(klass, MessagePackDelegate.class)) {
// TODO DelegateUnpacker
throw new UnsupportedOperationException("not supported yet. : " + klass.getName());
} else if (CustomMessage.isAnnotated(klass, MessagePackOrdinalEnum.class)) {
} else if (isAnnotated(klass, MessagePackOrdinalEnum.class)) {
Template tmpl = DynamicOrdinalEnumTemplate.create(klass);
CustomMessage.register(klass, tmpl);
return tmpl.unpack(pac, to);
@ -187,20 +185,20 @@ public class ClassTemplate implements Template {
// fallback
MessageConverter converter = null;
if (CustomMessage.isAnnotated(klass, MessagePackMessage.class)) {
if (isAnnotated(klass, MessagePackMessage.class)) {
Template tmpl = DynamicTemplate.create(klass);
CustomMessage.register(klass, tmpl);
return tmpl.convert(pac.unpackObject(), to);
} else if (CustomMessage.isAnnotated(klass, MessagePackDelegate.class)) {
} else if (isAnnotated(klass, MessagePackDelegate.class)) {
// TODO DelegateConverter
throw new UnsupportedOperationException("not supported yet. : " + klass.getName());
} else if (CustomMessage.isAnnotated(klass, MessagePackOrdinalEnum.class)) {
} else if (isAnnotated(klass, MessagePackOrdinalEnum.class)) {
Template tmpl = DynamicOrdinalEnumTemplate.create(klass);
CustomMessage.register(klass, tmpl);
return tmpl.convert(pac.unpackObject(), to);
}
throw new MessageTypeException();
throw new MessageTypeException("unknown type: "+klass);
} catch (IllegalAccessException e) {
throw new MessageTypeException(e.getMessage()); // FIXME
@ -228,14 +226,14 @@ public class ClassTemplate implements Template {
return obj;
}
if (CustomMessage.isAnnotated(klass, MessagePackMessage.class)) {
if (isAnnotated(klass, MessagePackMessage.class)) {
Template tmpl = DynamicTemplate.create(klass);
CustomMessage.register(klass, tmpl);
return tmpl.convert(from, to);
} else if (CustomMessage.isAnnotated(klass, MessagePackDelegate.class)) {
} else if (isAnnotated(klass, MessagePackDelegate.class)) {
// TODO DelegateConverter
throw new UnsupportedOperationException("not supported yet. : " + klass.getName());
} else if (CustomMessage.isAnnotated(klass, MessagePackOrdinalEnum.class)) {
} else if (isAnnotated(klass, MessagePackOrdinalEnum.class)) {
Template tmpl = DynamicOrdinalEnumTemplate.create(klass);
CustomMessage.register(klass, tmpl);
return tmpl.convert(from, to);
@ -249,5 +247,9 @@ public class ClassTemplate implements Template {
throw new MessageTypeException(e.getMessage()); // FIXME
}
}
private boolean isAnnotated(Class<?> ao, Class<? extends Annotation> with) {
return ao.getAnnotation(with) != null;
}
}

View File

@ -24,6 +24,8 @@ import java.io.IOException;
import org.msgpack.*;
public class CollectionTemplate implements Template {
public static void load() { }
private Template elementTemplate;
public CollectionTemplate(Template elementTemplate) {
@ -72,5 +74,10 @@ public class CollectionTemplate implements Template {
}
return list;
}
static {
TemplateRegistry.registerGeneric(Collection.class, new GenericTemplate1(CollectionTemplate.class));
TemplateRegistry.register(Collection.class, new CollectionTemplate(AnyTemplate.getInstance()));
}
}

View File

@ -0,0 +1,93 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import java.lang.reflect.Type;
import org.msgpack.*;
public class DefaultTemplate implements Template {
private Class<?> targetClass;
private Type lookupType;
private boolean messagePackable;
private boolean messageUnpackable;
private boolean messageConvertable;
public DefaultTemplate(Class<?> targetClass) {
this(targetClass, (Type)targetClass);
}
public DefaultTemplate(Class<?> targetClass, Type lookupType) {
this.targetClass = targetClass;
this.lookupType = lookupType;
this.messagePackable = MessagePackable.class.isAssignableFrom(targetClass);
this.messageUnpackable = MessageUnpackable.class.isAssignableFrom(targetClass);
this.messageConvertable = MessageConvertable.class.isAssignableFrom(targetClass);
}
public void pack(Packer pk, Object target) throws IOException {
if(messagePackable) {
((MessagePackable)target).messagePack(pk);
return;
}
Template tmpl = TemplateRegistry.tryLookup(lookupType);
if(tmpl == this || tmpl == null) {
throw new MessageTypeException();
}
tmpl.pack(pk, target);
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
if(messageUnpackable) {
if(to == null) {
try {
to = targetClass.newInstance();
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
((MessageUnpackable)to).messageUnpack(pac);
return to;
}
Template tmpl = TemplateRegistry.tryLookup(lookupType);
if(tmpl == this || tmpl == null) {
throw new MessageTypeException();
}
return tmpl.unpack(pac, to);
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
if(messageConvertable) {
if(to == null) {
try {
to = targetClass.newInstance();
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
((MessageConvertable)to).messageConvert(from);
return from;
}
Template tmpl = TemplateRegistry.tryLookup(lookupType);
if(tmpl == this || tmpl == null) {
throw new MessageTypeException();
}
return tmpl.convert(from, to);
}
}

View File

@ -0,0 +1,76 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import org.msgpack.*;
public class DoubleArrayTemplate implements Template {
private DoubleArrayTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof double[])) {
throw new MessageTypeException();
}
double[] array = (double[])target;
pk.packArray(array.length);
for(double a : array) {
pk.pack(a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
double[] array;
if(to != null && to instanceof double[] && ((double[])to).length == length) {
array = (double[])to;
} else {
array = new double[length];
}
for(int i=0; i < length; i++) {
array[i] = pac.unpackDouble();
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
double[] array;
if(to != null && to instanceof double[] && ((double[])to).length == src.length) {
array = (double[])to;
} else {
array = new double[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = s.asDouble();
}
return array;
}
static public DoubleArrayTemplate getInstance() {
return instance;
}
static final DoubleArrayTemplate instance = new DoubleArrayTemplate();
static {
TemplateRegistry.register(double[].class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class DoubleTemplate implements Template {
static {
CustomMessage.register(Double.class, instance);
TemplateRegistry.register(Double.class, instance);
TemplateRegistry.register(double.class, instance);
}
}

View File

@ -0,0 +1,96 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.util.List;
import java.util.ArrayList;
public class FieldList {
public static class Entry {
public Entry() {
this.name = null;
this.option = null;
}
public Entry(String name, FieldOption option) {
this.name = name;
this.option = option;
}
private String name;
private FieldOption option;
public String getName() {
return name;
}
public FieldOption getOption() {
return option;
}
boolean isAvailable() {
return this.name != null;
}
boolean isRequired() {
return this.option == FieldOption.REQUIRED;
}
boolean isOptional() {
return this.option == FieldOption.OPTIONAL;
}
boolean isNullable() {
return this.option == FieldOption.NULLABLE;
}
}
private ArrayList<Entry> list;
public FieldList() {
list = new ArrayList<Entry>();
}
public void add(final String name) {
add(name, FieldOption.REQUIRED);
}
public void add(final String name, final FieldOption option) {
list.add(new Entry(name, option));
}
public void put(int index, final String name) {
put(index, name, FieldOption.REQUIRED);
}
public void put(int index, final String name, final FieldOption option) {
if(list.size() < index) {
do {
list.add(new Entry());
} while(list.size() < index);
list.add(new Entry(name, option));
} else {
list.set(index, new Entry(name, option));
}
}
List<Entry> getList() {
return list;
}
}

View File

@ -0,0 +1,27 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
public enum FieldOption {
IGNORE,
REQUIRED,
OPTIONAL,
NULLABLE,
DEFAULT;
}

View File

@ -0,0 +1,76 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import org.msgpack.*;
public class FloatArrayTemplate implements Template {
private FloatArrayTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof float[])) {
throw new MessageTypeException();
}
float[] array = (float[])target;
pk.packArray(array.length);
for(float a : array) {
pk.pack(a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
float[] array;
if(to != null && to instanceof float[] && ((float[])to).length == length) {
array = (float[])to;
} else {
array = new float[length];
}
for(int i=0; i < length; i++) {
array[i] = pac.unpackFloat();
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
float[] array;
if(to != null && to instanceof float[] && ((float[])to).length == src.length) {
array = (float[])to;
} else {
array = new float[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = s.asFloat();
}
return array;
}
static public FloatArrayTemplate getInstance() {
return instance;
}
static final FloatArrayTemplate instance = new FloatArrayTemplate();
static {
TemplateRegistry.register(float[].class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class FloatTemplate implements Template {
static {
CustomMessage.register(Float.class, instance);
TemplateRegistry.register(Float.class, instance);
TemplateRegistry.register(float.class, instance);
}
}

View File

@ -0,0 +1,25 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import org.msgpack.Template;
public interface GenericTemplate {
public Template build(Template[] params);
}

View File

@ -0,0 +1,54 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.msgpack.Template;
public class GenericTemplate1 implements GenericTemplate {
Constructor<? extends Template> constructor;
public GenericTemplate1(Class<? extends Template> tmpl) {
try {
this.constructor = tmpl.getConstructor(new Class<?>[]{Template.class});
constructor.newInstance(new Object[]{AnyTemplate.getInstance()});
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
}
}
public Template build(Template[] params) {
try {
return constructor.newInstance(params);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
}
}
}

View File

@ -0,0 +1,54 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.msgpack.Template;
public class GenericTemplate2 implements GenericTemplate {
Constructor<? extends Template> constructor;
public GenericTemplate2(Class<? extends Template> tmpl) {
try {
this.constructor = tmpl.getConstructor(new Class<?>[]{Template.class, Template.class});
constructor.newInstance(new Object[]{AnyTemplate.getInstance(), AnyTemplate.getInstance()});
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
}
}
public Template build(Template[] params) {
try {
return constructor.newInstance(params);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InstantiationException e) {
throw new IllegalArgumentException(e);
}
}
}

View File

@ -0,0 +1,76 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import org.msgpack.*;
public class IntArrayTemplate implements Template {
private IntArrayTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof int[])) {
throw new MessageTypeException();
}
int[] array = (int[])target;
pk.packArray(array.length);
for(int a : array) {
pk.pack(a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
int[] array;
if(to != null && to instanceof int[] && ((int[])to).length == length) {
array = (int[])to;
} else {
array = new int[length];
}
for(int i=0; i < length; i++) {
array[i] = pac.unpackInt();
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
int[] array;
if(to != null && to instanceof int[] && ((int[])to).length == src.length) {
array = (int[])to;
} else {
array = new int[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = s.asInt();
}
return array;
}
static public IntArrayTemplate getInstance() {
return instance;
}
static final IntArrayTemplate instance = new IntArrayTemplate();
static {
TemplateRegistry.register(int[].class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class IntegerTemplate implements Template {
static {
CustomMessage.register(Integer.class, instance);
TemplateRegistry.register(Integer.class, instance);
TemplateRegistry.register(int.class, instance);
}
}

View File

@ -0,0 +1,523 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.Map;
import java.util.HashMap;
import org.msgpack.*;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JavassistTemplateBuilder extends TemplateBuilder {
private static JavassistTemplateBuilder instance;
public synchronized static JavassistTemplateBuilder getInstance() {
if(instance == null) {
instance = new JavassistTemplateBuilder();
}
return instance;
}
private JavassistTemplateBuilder() {
this.pool = ClassPool.getDefault();
}
private static Logger LOG = LoggerFactory
.getLogger(JavassistTemplateBuilder.class);
protected ClassPool pool;
private int seqId = 0;
CtClass makeCtClass(String className) {
return pool.makeClass(className);
}
CtClass getCtClass(String className) throws NotFoundException {
return pool.get(className);
}
int nextSeqId() {
return seqId++;
}
public static abstract class JavassistTemplate extends AbstractTemplate {
public Class targetClass;
public Template[] templates;
public JavassistTemplate(Class targetClass, Template[] templates) {
this.targetClass = targetClass;
this.templates = templates;
}
}
private static abstract class BuildContextBase {
protected JavassistTemplateBuilder director;
protected Class<?> origClass;
protected String origName;
protected String tmplName;
protected CtClass tmplCtClass;
protected abstract void setSuperClass() throws CannotCompileException, NotFoundException;
protected abstract void buildConstructor() throws CannotCompileException, NotFoundException;
protected void buildMethodInit() { }
protected abstract String buildPackMethodBody();
protected abstract String buildUnpackMethodBody();
protected abstract String buildConvertMethodBody();
protected abstract Template buildInstance(Class<?> c) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException;
public BuildContextBase(JavassistTemplateBuilder director) {
this.director = director;
}
protected Template build(Class<?> targetClass) {
try {
reset(targetClass);
buildClass();
buildConstructor();
buildMethodInit();
buildPackMethod();
buildUnpackMethod();
buildConvertMethod();
return buildInstance(createClass());
} catch (Exception e) {
if(this.stringBuilder != null) {
LOG.error("builder: "+this.stringBuilder.toString());
}
throw new MessageTypeException(e);
}
}
protected void reset(Class<?> targetClass) {
this.origClass = targetClass;
this.origName = this.origClass.getName();
this.tmplName = this.origName + "_$$_Template" + director.nextSeqId();
this.tmplCtClass = director.makeCtClass(this.tmplName);
}
protected void buildClass() throws CannotCompileException, NotFoundException {
setSuperClass();
this.tmplCtClass.addInterface(
director.getCtClass(Template.class.getName()));
}
protected void buildPackMethod() throws CannotCompileException, NotFoundException {
String mbody = buildPackMethodBody();
int mod = javassist.Modifier.PUBLIC;
CtClass returnType = CtClass.voidType;
String mname = "pack";
CtClass[] paramTypes = new CtClass[] {
director.getCtClass(Packer.class.getName()),
director.getCtClass(Object.class.getName())
};
CtClass[] exceptTypes = new CtClass[] {
director.getCtClass(IOException.class.getName())
};
CtMethod newCtMethod = CtNewMethod.make(
mod, returnType, mname,
paramTypes, exceptTypes, mbody,
this.tmplCtClass);
this.tmplCtClass.addMethod(newCtMethod);
}
protected void buildUnpackMethod() throws CannotCompileException, NotFoundException {
String mbody = buildUnpackMethodBody();
int mod = javassist.Modifier.PUBLIC;
CtClass returnType = director.getCtClass(Object.class.getName());
String mname = "unpack";
CtClass[] paramTypes = new CtClass[] {
director.getCtClass(Unpacker.class.getName()),
director.getCtClass(Object.class.getName())
};
CtClass[] exceptTypes = new CtClass[] {
director.getCtClass(MessageTypeException.class.getName())
};
CtMethod newCtMethod = CtNewMethod.make(
mod, returnType, mname,
paramTypes, exceptTypes, mbody,
this.tmplCtClass);
this.tmplCtClass.addMethod(newCtMethod);
}
protected void buildConvertMethod() throws CannotCompileException, NotFoundException {
String mbody = buildConvertMethodBody();
int mod = javassist.Modifier.PUBLIC;
CtClass returnType = director.getCtClass(Object.class.getName());
String mname = "convert";
CtClass[] paramTypes = new CtClass[] {
director.getCtClass(MessagePackObject.class.getName()),
director.getCtClass(Object.class.getName())
};
CtClass[] exceptTypes = new CtClass[] {
director.getCtClass(MessageTypeException.class.getName())
};
CtMethod newCtMethod = CtNewMethod.make(
mod, returnType, mname,
paramTypes, exceptTypes, mbody,
this.tmplCtClass);
this.tmplCtClass.addMethod(newCtMethod);
}
protected Class<?> createClass() throws CannotCompileException {
return (Class<?>)this.tmplCtClass.toClass(null, null);
}
protected StringBuilder stringBuilder = null;
protected void resetStringBuilder() {
this.stringBuilder = new StringBuilder();
}
protected void buildString(String str) {
this.stringBuilder.append(str);
}
protected void buildString(String format, Object... args) {
this.stringBuilder.append(String.format(format, args));
}
protected String getBuiltString() {
return this.stringBuilder.toString();
}
}
private static class BuildContext extends BuildContextBase {
protected FieldEntry[] entries;
protected Template[] templates;
protected int minimumArrayLength;
public BuildContext(JavassistTemplateBuilder director) {
super(director);
}
public Template buildTemplate(Class<?> targetClass, FieldEntry[] entries, Template[] templates) {
this.entries = entries;
this.templates = templates;
return build(targetClass);
}
protected void setSuperClass() throws CannotCompileException, NotFoundException {
this.tmplCtClass.setSuperclass(
director.getCtClass(JavassistTemplate.class.getName()));
}
protected void buildConstructor() throws CannotCompileException, NotFoundException {
// Constructor(Class targetClass, Template[] templates)
CtConstructor newCtCons = CtNewConstructor.make(
new CtClass[] {
director.getCtClass(Class.class.getName()),
director.getCtClass(Template.class.getName()+"[]")
},
new CtClass[0],
this.tmplCtClass);
this.tmplCtClass.addConstructor(newCtCons);
}
protected Template buildInstance(Class<?> c) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<?> cons = c.getConstructor(new Class[] {
Class.class,
Template[].class
});
Object tmpl = cons.newInstance(new Object[] {
this.origClass,
this.templates
});
return (Template)tmpl;
}
protected void buildMethodInit() {
this.minimumArrayLength = 0;
for(int i=0; i < entries.length; i++) {
FieldEntry e = entries[i];
if(e.isRequired() || e.isNullable()) {
this.minimumArrayLength = i+1;
}
}
}
protected String buildPackMethodBody() {
resetStringBuilder();
buildString("{");
buildString("%s _$$_t = (%s)$2;", this.origName, this.origName);
buildString("$1.packArray(%d);", entries.length);
for(int i=0; i < entries.length; i++) {
FieldEntry e = entries[i];
if(!e.isAvailable()) {
buildString("$1.packNil();");
continue;
}
Class<?> type = e.getType();
if(type.isPrimitive()) {
buildString("$1.%s(_$$_t.%s);", primitivePackName(type), e.getName());
} else {
buildString("if(_$$_t.%s == null) {", e.getName());
if(!e.isNullable() && !e.isOptional()) {
buildString("throw new %s();", MessageTypeException.class.getName());
} else {
buildString("$1.packNil();");
}
buildString("} else {");
buildString(" this.templates[%d].pack($1, _$$_t.%s);", i, e.getName());
buildString("}");
}
}
buildString("}");
return getBuiltString();
}
protected String buildUnpackMethodBody() {
resetStringBuilder();
buildString("{ ");
buildString("%s _$$_t;", this.origName);
buildString("if($2 == null) {");
buildString(" _$$_t = (%s)this.targetClass.newInstance();", this.origName);
buildString("} else {");
buildString(" _$$_t = (%s)$2;", this.origName);
buildString("}");
buildString("int length = $1.unpackArray();");
buildString("if(length < %d) {", this.minimumArrayLength);
buildString(" throw new %s();", MessageTypeException.class.getName());
buildString("}");
int i;
for(i=0; i < this.minimumArrayLength; i++) {
FieldEntry e = entries[i];
if(!e.isAvailable()) {
buildString("$1.unpackObject();");
continue;
}
buildString("if($1.tryUnpackNull()) {");
if(e.isRequired()) {
// Requred + nil => exception
buildString("throw new %s();", MessageTypeException.class.getName());
} else if(e.isOptional()) {
// Optional + nil => keep default value
} else { // Nullable
// Nullable + nil => set null
buildString("_$$_t.%s = null;", e.getName());
}
buildString("} else {");
Class<?> type = e.getType();
if(type.isPrimitive()) {
buildString("_$$_t.%s = $1.%s();", e.getName(), primitiveUnpackName(type));
} else {
buildString("_$$_t.%s = (%s)this.templates[%d].unpack($1, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
}
buildString("}");
}
for(; i < entries.length; i++) {
buildString("if(length <= %d) { return _$$_t; }", i);
FieldEntry e = entries[i];
if(!e.isAvailable()) {
buildString("$1.unpackObject();");
continue;
}
buildString("if($1.tryUnpackNull()) {");
buildString("} else {");
Class<?> type = e.getType();
if(type.isPrimitive()) {
buildString("_$$_t.%s = $1.%s();", e.getName(), primitiveUnpackName(type));
} else {
buildString("_$$_t.%s = (%s)this.templates[%d].unpack($1, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
}
buildString("}");
}
buildString("for(int i=%d; i < length; i++) {", i);
buildString(" $1.unpackObject();");
buildString("}");
buildString("return _$$_t;");
buildString("}");
return getBuiltString();
}
protected String buildConvertMethodBody() {
resetStringBuilder();
buildString("{ ");
buildString("%s _$$_t;", this.origName);
buildString("if($2 == null) {");
buildString(" _$$_t = (%s)this.targetClass.newInstance();", this.origName);
buildString("} else {");
buildString(" _$$_t = (%s)$2;", this.origName);
buildString("}");
buildString("%s[] array = $1.asArray();", MessagePackObject.class.getName());
buildString("int length = array.length;");
buildString("if(length < %d) {", this.minimumArrayLength);
buildString(" throw new %s();", MessageTypeException.class.getName());
buildString("}");
int i;
for(i=0; i < this.minimumArrayLength; i++) {
FieldEntry e = entries[i];
if(!e.isAvailable()) {
continue;
}
buildString("%s obj = array[%d];", MessagePackObject.class.getName(), i);
buildString("if(obj.isNil()) {");
if(e.isRequired()) {
// Requred + nil => exception
buildString("throw new %s();", MessageTypeException.class.getName());
} else if(e.isOptional()) {
// Optional + nil => keep default value
} else { // Nullable
// Nullable + nil => set null
buildString("_$$_t.%s = null;", e.getName());
}
buildString("} else {");
Class<?> type = e.getType();
if(type.isPrimitive()) {
buildString("_$$_t.%s = obj.%s();", e.getName(), primitiveConvertName(type));
} else {
buildString("_$$_t.%s = (%s)this.templates[%d].convert(obj, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
}
buildString("}");
}
for(; i < entries.length; i++) {
buildString("if(length <= %d) { return _$$_t; }", i);
FieldEntry e = entries[i];
if(!e.isAvailable()) {
continue;
}
buildString("%s obj = array[%d];", MessagePackObject.class.getName(), i);
buildString("if(obj.isNil()) {");
buildString("} else {");
Class<?> type = e.getType();
if(type.isPrimitive()) {
buildString("_$$_t.%s = $1.%s();", e.getName(), primitiveConvertName(type));
} else {
buildString("_$$_t.%s = (%s)this.templates[%d].convert(obj, _$$_t.%s);", e.getName(), e.getJavaTypeName(), i, e.getName());
}
buildString("}");
}
buildString("return _$$_t;");
buildString("}");
return getBuiltString();
}
protected String primitivePackName(Class<?> type) {
if(type == boolean.class) {
return "packBoolean";
} else if(type == byte.class) {
return "packByte";
} else if(type == short.class) {
return "packShort";
} else if(type == int.class) {
return "packInt";
} else if(type == long.class) {
return "packLong";
} else if(type == float.class) {
return "packFloat";
} else if(type == double.class) {
return "packDouble";
}
return null;
}
protected String primitiveUnpackName(Class<?> type) {
if(type == boolean.class) {
return "unpackBoolean";
} else if(type == byte.class) {
return "unpackByte";
} else if(type == short.class) {
return "unpackShort";
} else if(type == int.class) {
return "unpackInt";
} else if(type == long.class) {
return "unpackLong";
} else if(type == float.class) {
return "unpackFloat";
} else if(type == double.class) {
return "unpackDouble";
}
return null;
}
protected String primitiveConvertName(Class<?> type) {
if(type == boolean.class) {
return "asBoolean";
} else if(type == byte.class) {
return "asByte";
} else if(type == short.class) {
return "asShort";
} else if(type == int.class) {
return "asInt";
} else if(type == long.class) {
return "asLong";
} else if(type == float.class) {
return "asFloat";
} else if(type == double.class) {
return "asDouble";
}
return null;
}
}
public Template buildTemplate(Class<?> targetClass, FieldEntry[] entries) {
Template[] tmpls = new Template[entries.length];
for(int i=0; i < entries.length; i++) {
FieldEntry e = entries[i];
Template tmpl = TemplateRegistry.lookup(e.getGenericType(), true);
tmpls[i] = tmpl;
}
BuildContext bc = new BuildContext(this);
return bc.buildTemplate(targetClass, entries, tmpls);
}
static class JavassistOrdinalEnumTemplate extends ReflectionTemplateBuilder.ReflectionOrdinalEnumTemplate {
JavassistOrdinalEnumTemplate(Enum<?>[] entries) {
super(entries);
}
}
public Template buildOrdinalEnumTemplate(Class<?> targetClass, Enum<?>[] entries) {
return new JavassistOrdinalEnumTemplate(entries);
}
}

View File

@ -23,6 +23,8 @@ import java.io.IOException;
import org.msgpack.*;
public class ListTemplate implements Template {
static void load() { }
private Template elementTemplate;
public ListTemplate(Template elementTemplate) {
@ -75,5 +77,10 @@ public class ListTemplate implements Template {
}
return list;
}
static {
TemplateRegistry.registerGeneric(List.class, new GenericTemplate1(ListTemplate.class));
TemplateRegistry.register(List.class, new ListTemplate(AnyTemplate.getInstance()));
}
}

View File

@ -0,0 +1,76 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import org.msgpack.*;
public class LongArrayTemplate implements Template {
private LongArrayTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof long[])) {
throw new MessageTypeException();
}
long[] array = (long[])target;
pk.packArray(array.length);
for(long a : array) {
pk.pack(a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
long[] array;
if(to != null && to instanceof long[] && ((long[])to).length == length) {
array = (long[])to;
} else {
array = new long[length];
}
for(int i=0; i < length; i++) {
array[i] = pac.unpackLong();
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
long[] array;
if(to != null && to instanceof long[] && ((long[])to).length == src.length) {
array = (long[])to;
} else {
array = new long[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = s.asLong();
}
return array;
}
static public LongArrayTemplate getInstance() {
return instance;
}
static final LongArrayTemplate instance = new LongArrayTemplate();
static {
TemplateRegistry.register(long[].class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class LongTemplate implements Template {
static {
CustomMessage.register(Long.class, instance);
TemplateRegistry.register(Long.class, instance);
TemplateRegistry.register(long.class, instance);
}
}

View File

@ -23,6 +23,8 @@ import java.io.IOException;
import org.msgpack.*;
public class MapTemplate implements Template {
static void load() { }
private Template keyTemplate;
private Template valueTemplate;
@ -86,5 +88,10 @@ public class MapTemplate implements Template {
}
return map;
}
static {
TemplateRegistry.registerGeneric(Map.class, new GenericTemplate2(MapTemplate.class));
TemplateRegistry.register(Map.class, new MapTemplate(AnyTemplate.getInstance(), AnyTemplate.getInstance()));
}
}

View File

@ -21,6 +21,8 @@ import java.io.IOException;
import org.msgpack.*;
public class NullableTemplate implements Template {
static void load() { }
private Template elementTemplate;
public NullableTemplate(Template elementTemplate) {

View File

@ -0,0 +1,79 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
import org.msgpack.*;
public class ObjectArrayTemplate implements Template {
static void load() { }
private Template componentTemplate;
public ObjectArrayTemplate(Template componentTemplate) {
this.componentTemplate = componentTemplate;
}
public Template getcomponentTemplate() {
return componentTemplate;
}
@SuppressWarnings("unchecked")
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof Object[])) {
throw new MessageTypeException();
}
Object[] array = (Object[])target;
pk.packArray(array.length);
for(Object a : array) {
componentTemplate.pack(pk, a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
Object[] array;
if(to != null && to instanceof Object[] && ((Object[])to).length == length) {
array = (Object[])to;
} else {
array = new Object[length];
}
for(int i=0; i < length; i++) {
array[i] = componentTemplate.unpack(pac, null);
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
Object[] array;
if(to != null && to instanceof Object[] && ((Object[])to).length == src.length) {
array = (Object[])to;
} else {
array = new Object[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = componentTemplate.convert(s, array[i]);
}
return array;
}
}

View File

@ -0,0 +1,444 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.Map;
import java.util.HashMap;
import org.msgpack.*;
public class ReflectionTemplateBuilder extends TemplateBuilder {
private static ReflectionTemplateBuilder instance;
public synchronized static ReflectionTemplateBuilder getInstance() {
if(instance == null) {
instance = new ReflectionTemplateBuilder();
}
return instance;
}
private ReflectionTemplateBuilder() {
}
static abstract class ReflectionFieldEntry extends FieldEntry {
public ReflectionFieldEntry(FieldEntry e) {
super(e.getField(), e.getOption());
}
public abstract void pack(Object target, Packer pac) throws IOException;
public abstract void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException;
public abstract void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException;
public void setNull(Object target) throws IllegalAccessException {
getField().set(target, null);
}
}
static class ObjectFieldEntry extends ReflectionFieldEntry {
private Template template;
ObjectFieldEntry(FieldEntry e, Template template) {
super(e);
this.template = template;
}
public void pack(Object target, Packer pac) throws IOException {
template.pack(pac, target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
Field f = getField();
Class<Object> type = (Class<Object>)f.getType();
Object fieldReference = f.get(target);
Object valueReference = template.convert(obj, fieldReference);
if(valueReference != fieldReference) {
f.set(target, valueReference);
}
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
Field f = getField();
Class<Object> type = (Class<Object>)f.getType();
Object fieldReference = f.get(target);
Object valueReference = template.unpack(pac, fieldReference);
if(valueReference != fieldReference) {
f.set(target, valueReference);
}
}
}
static class BooleanFieldEntry extends ReflectionFieldEntry {
BooleanFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((boolean)(Boolean)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setBoolean(target, obj.asBoolean());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setBoolean(target, pac.unpackBoolean());
}
}
static class ByteFieldEntry extends ReflectionFieldEntry {
ByteFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((byte)(Byte)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setByte(target, obj.asByte());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setByte(target, pac.unpackByte());
}
}
static class ShortFieldEntry extends ReflectionFieldEntry {
ShortFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((short)(Short)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setShort(target, obj.asShort());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setShort(target, pac.unpackShort());
}
}
static class IntFieldEntry extends ReflectionFieldEntry {
IntFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((int)(Integer)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setInt(target, obj.asInt());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setInt(target, pac.unpackInt());
}
}
static class LongFieldEntry extends ReflectionFieldEntry {
LongFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((long)(Long)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setLong(target, obj.asLong());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setLong(target, pac.unpackLong());
}
}
static class FloatFieldEntry extends ReflectionFieldEntry {
FloatFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((float)(Float)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setFloat(target, obj.asFloat());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setFloat(target, pac.unpackFloat());
}
}
static class DoubleFieldEntry extends ReflectionFieldEntry {
DoubleFieldEntry(FieldEntry e) {
super(e);
}
public void pack(Object target, Packer pac) throws IOException {
pac.pack((double)(Double)target);
}
public void convert(Object target, MessagePackObject obj) throws MessageTypeException, IllegalAccessException {
getField().setDouble(target, obj.asDouble());
}
public void unpack(Object target, Unpacker pac) throws IOException, MessageTypeException, IllegalAccessException {
getField().setDouble(target, pac.unpackDouble());
}
}
static class ReflectionTemplate extends AbstractTemplate {
protected Class<?> targetClass;
protected ReflectionFieldEntry[] entries;
protected int minimumArrayLength;
ReflectionTemplate(Class<?> targetClass, ReflectionFieldEntry[] entries) {
this.targetClass = targetClass;
this.entries = entries;
this.minimumArrayLength = 0;
for(int i=0; i < entries.length; i++) {
ReflectionFieldEntry e = entries[i];
if(e.isRequired() || e.isNullable()) {
this.minimumArrayLength = i+1;
}
}
}
public void pack(Packer pk, Object target) throws IOException {
try {
pk.packArray(entries.length);
for(ReflectionFieldEntry e : entries) {
if(!e.isAvailable()) {
pk.packNil();
continue;
}
Object obj = e.getField().get(target);
if(obj == null) {
if(!e.isNullable() && !e.isOptional()) {
throw new MessageTypeException();
}
pk.packNil();
} else {
e.pack(obj, pk);
}
}
} catch (MessageTypeException e) {
throw e;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
try {
if(to == null) {
to = targetClass.newInstance();
}
int length = pac.unpackArray();
if(length < minimumArrayLength) {
throw new MessageTypeException();
}
int i;
for(i=0; i < minimumArrayLength; i++) {
ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
pac.unpackObject();
continue;
}
if(pac.tryUnpackNull()) {
if(e.isRequired()) {
// Requred + nil => exception
throw new MessageTypeException();
} else if(e.isOptional()) {
// Optional + nil => keep default value
} else { // Nullable
// Nullable + nil => set null
e.setNull(to);
}
} else {
e.unpack(to, pac);
}
}
int max = length < entries.length ? length : entries.length;
for(; i < max; i++) {
ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
pac.unpackObject();
continue;
}
if(pac.tryUnpackNull()) {
// this is Optional field becaue i >= minimumArrayLength
// Optional + nil => keep default value
} else {
e.unpack(to, pac);
}
}
// latter entries are all Optional + nil => keep default value
for(; i < length; i++) {
pac.unpackObject();
}
return to;
} catch (MessageTypeException e) {
throw e;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
try {
if(to == null) {
to = targetClass.newInstance();
}
MessagePackObject[] array = from.asArray();
int length = array.length;
if(length < minimumArrayLength) {
throw new MessageTypeException();
}
int i;
for(i=0; i < minimumArrayLength; i++) {
ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
continue;
}
MessagePackObject obj = array[i];
if(obj.isNil()) {
if(e.isRequired()) {
// Requred + nil => exception
throw new MessageTypeException();
} else if(e.isOptional()) {
// Optional + nil => keep default value
} else { // Nullable
// Nullable + nil => set null
e.setNull(to);
}
} else {
e.convert(to, obj);
}
}
int max = length < entries.length ? length : entries.length;
for(; i < max; i++) {
ReflectionFieldEntry e = entries[i];
if(!e.isAvailable()) {
continue;
}
MessagePackObject obj = array[i];
if(obj.isNil()) {
// this is Optional field becaue i >= minimumArrayLength
// Optional + nil => keep default value
} else {
e.convert(to, obj);
}
}
// latter entries are all Optional + nil => keep default value
return to;
} catch (MessageTypeException e) {
throw e;
} catch (Exception e) {
throw new MessageTypeException(e);
}
}
}
public Template buildTemplate(Class<?> targetClass, FieldEntry[] entries) {
for(FieldEntry e : entries) {
Field f = e.getField();
int mod = f.getModifiers();
if(!Modifier.isPublic(mod)) {
f.setAccessible(true);
}
}
ReflectionFieldEntry[] res = new ReflectionFieldEntry[entries.length];
for(int i=0; i < entries.length; i++) {
FieldEntry e = entries[i];
Class<?> type = e.getType();
if(type.equals(boolean.class)) {
res[i] = new BooleanFieldEntry(e);
} else if(type.equals(byte.class)) {
res[i] = new ByteFieldEntry(e);
} else if(type.equals(short.class)) {
res[i] = new ShortFieldEntry(e);
} else if(type.equals(int.class)) {
res[i] = new IntFieldEntry(e);
} else if(type.equals(long.class)) {
res[i] = new LongFieldEntry(e);
} else if(type.equals(float.class)) {
res[i] = new FloatFieldEntry(e);
} else if(type.equals(double.class)) {
res[i] = new DoubleFieldEntry(e);
} else {
Template tmpl = TemplateRegistry.lookup(e.getGenericType(), true);
res[i] = new ObjectFieldEntry(e, tmpl);
}
}
return new ReflectionTemplate(targetClass, res);
}
static class ReflectionOrdinalEnumTemplate extends AbstractTemplate {
protected Enum<?>[] entries;
protected Map<Enum<?>, Integer> reverse;
ReflectionOrdinalEnumTemplate(Enum<?>[] entries) {
this.entries = entries;
this.reverse = new HashMap<Enum<?>, Integer>();
for(int i=0; i < entries.length; i++) {
this.reverse.put(entries[i], i);
}
}
public void pack(Packer pk, Object target) throws IOException {
Integer ord = reverse.get(target);
if(ord == null) {
throw new MessageTypeException();
}
pk.pack((int)ord);
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int ord = pac.unpackInt();
if(entries.length <= ord) {
throw new MessageTypeException();
}
return entries[ord];
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
int ord = from.asInt();
if(entries.length <= ord) {
throw new MessageTypeException();
}
return entries[ord];
}
}
public Template buildOrdinalEnumTemplate(Class<?> targetClass, Enum<?>[] entries) {
return new ReflectionOrdinalEnumTemplate(entries);
}
}

View File

@ -0,0 +1,76 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import org.msgpack.*;
public class ShortArrayTemplate implements Template {
private ShortArrayTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
if(!(target instanceof short[])) {
throw new MessageTypeException();
}
short[] array = (short[])target;
pk.packArray(array.length);
for(short a : array) {
pk.pack(a);
}
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
int length = pac.unpackArray();
short[] array;
if(to != null && to instanceof short[] && ((short[])to).length == length) {
array = (short[])to;
} else {
array = new short[length];
}
for(int i=0; i < length; i++) {
array[i] = pac.unpackShort();
}
return array;
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
MessagePackObject[] src = from.asArray();
short[] array;
if(to != null && to instanceof short[] && ((short[])to).length == src.length) {
array = (short[])to;
} else {
array = new short[src.length];
}
for(int i=0; i < src.length; i++) {
MessagePackObject s = src[i];
array[i] = s.asShort();
}
return array;
}
static public ShortArrayTemplate getInstance() {
return instance;
}
static final ShortArrayTemplate instance = new ShortArrayTemplate();
static {
TemplateRegistry.register(short[].class, instance);
}
}

View File

@ -43,6 +43,8 @@ public class ShortTemplate implements Template {
static {
CustomMessage.register(Short.class, instance);
TemplateRegistry.register(Short.class, instance);
TemplateRegistry.register(short.class, instance);
}
}

View File

@ -43,6 +43,7 @@ public class StringTemplate implements Template {
static {
CustomMessage.register(String.class, instance);
TemplateRegistry.register(String.class, instance);
}
}

View File

@ -0,0 +1,307 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.io.IOException;
import java.lang.reflect.*;
import java.lang.annotation.*;
import java.util.List;
import java.util.ArrayList;
import java.util.EnumSet;
import org.msgpack.*;
import org.msgpack.annotation.*;
public abstract class TemplateBuilder {
public static class FieldEntry {
private Field field = null;
private FieldOption option = FieldOption.IGNORE;
public FieldEntry() {
}
public FieldEntry(Field field, FieldOption option) {
this.field = field;
this.option = option;
}
public Field getField() {
return field;
}
public String getName() {
return field.getName();
}
public Class<?> getType() {
return field.getType();
}
public String getJavaTypeName() {
Class<?> type = field.getType();
if(type.isArray()) {
return arrayTypeToString(type);
} else {
return type.getName();
}
}
public Type getGenericType() {
return field.getGenericType();
}
public FieldOption getOption() {
return option;
}
public boolean isAvailable() {
return option != FieldOption.IGNORE;
}
public boolean isRequired() {
return option == FieldOption.REQUIRED;
}
public boolean isOptional() {
return option == FieldOption.OPTIONAL;
}
public boolean isNullable() {
return option == FieldOption.NULLABLE;
}
public boolean isAnnotated(Class<? extends Annotation> with) {
return field.getAnnotation(with) != null;
}
static String arrayTypeToString(Class<?> type) {
int dim = 1;
Class<?> baseType = type.getComponentType();
while(baseType.isArray()) {
baseType = baseType.getComponentType();
dim += 1;
}
StringBuilder sb = new StringBuilder();
sb.append(baseType.getName());
for (int i = 0; i < dim; ++i) {
sb.append("[]");
}
return sb.toString();
}
}
// Override this method
public abstract Template buildTemplate(Class<?> targetClass, FieldEntry[] entries);
// Override this method
public abstract Template buildOrdinalEnumTemplate(Class<?> targetClass, Enum<?>[] entries);
public Template buildTemplate(Class<?> targetClass) {
return buildTemplate(targetClass, readFieldEntries(targetClass));
}
public Template buildTemplate(Class<?> targetClass, FieldOption implicitOption) {
return buildTemplate(targetClass, readFieldEntries(targetClass, implicitOption));
}
public Template buildTemplate(Class<?> targetClass, FieldList flist) throws NoSuchFieldException {
return buildTemplate(targetClass, convertFieldEntries(targetClass, flist));
}
public Template buildOrdinalEnumTemplate(Class<?> targetClass) {
Enum<?>[] entries = (Enum<?>[])targetClass.getEnumConstants();
return buildOrdinalEnumTemplate(targetClass, entries);
}
private static TemplateBuilder instance;
static {
// FIXME
instance = JavassistTemplateBuilder.getInstance();
}
public synchronized static void setTemplateBuilder(TemplateBuilder builder) {
instance = builder;
}
public static Template build(Class<?> targetClass) {
return instance.buildTemplate(targetClass);
}
public static Template build(Class<?> targetClass, FieldOption implicitOption) {
return instance.buildTemplate(targetClass, implicitOption);
}
public static Template build(Class<?> targetClass, FieldList flist) throws NoSuchFieldException {
return instance.buildTemplate(targetClass, flist);
}
public static Template buildOrdinalEnum(Class<?> targetClass) {
return instance.buildOrdinalEnumTemplate(targetClass);
}
protected FieldEntry[] convertFieldEntries(Class<?> targetClass, FieldList flist) throws NoSuchFieldException {
List<FieldList.Entry> src = flist.getList();
FieldEntry[] result = new FieldEntry[src.size()];
for(int i=0; i < src.size(); i++) {
FieldList.Entry s = src.get(i);
if(s.isAvailable()) {
result[i] = new FieldEntry(targetClass.getDeclaredField(s.getName()), s.getOption());
} else {
result[i] = new FieldEntry();
}
}
return result;
}
protected FieldEntry[] readFieldEntries(Class<?> targetClass) {
FieldOption implicitOption = readImplicitFieldOption(targetClass);
return readFieldEntries(targetClass, implicitOption);
}
protected FieldEntry[] readFieldEntries(Class<?> targetClass, FieldOption implicitOption) {
Field[] allFields = readAllFields(targetClass);
/* index:
* @Index(0) int a; // 0
* int b; // 1
* @Index(3) int c; // 3
* int e; // 4
* @Index(2) int d; // 2
* int e; // 5
*/
List<FieldEntry> indexed = new ArrayList<FieldEntry>();
int maxIndex = -1;
for(Field f : allFields) {
FieldOption opt = readFieldOption(f, implicitOption);
if(opt == FieldOption.IGNORE) {
// skip
continue;
}
int index = readFieldIndex(f, maxIndex);
if(indexed.size() > index && indexed.get(index) != null) {
throw new RuntimeException("duplicated index: "+index); // FIXME exception
}
if(index < 0) {
throw new RuntimeException("invalid index: "+index); // FIXME exception
}
while(indexed.size() <= index) {
indexed.add(null);
}
indexed.set(index, new FieldEntry(f, opt));
if(maxIndex < index) {
maxIndex = index;
}
}
FieldEntry[] result = new FieldEntry[maxIndex+1];
for(int i=0; i < indexed.size(); i++) {
FieldEntry e = indexed.get(i);
if(e == null) {
result[i] = new FieldEntry();
} else {
result[i] = new FieldEntry(e.getField(), e.getOption());
}
}
return result;
}
private Field[] readAllFields(Class<?> targetClass) {
// order: [fields of super class, ..., fields of this class]
List<Field[]> succ = new ArrayList<Field[]>();
int total = 0;
for(Class<?> c = targetClass; c != Object.class; c = c.getSuperclass()) {
Field[] fields = c.getDeclaredFields();
total += fields.length;
succ.add(fields);
}
Field[] result = new Field[total];
int off = 0;
for(int i=succ.size()-1; i >= 0; i--) {
Field[] fields = succ.get(i);
System.arraycopy(fields, 0, result, off, fields.length);
off += fields.length;
}
return result;
}
private FieldOption readImplicitFieldOption(Class<?> targetClass) {
MessagePackMessage a = targetClass.getAnnotation(MessagePackMessage.class);
if(a == null) {
return FieldOption.DEFAULT;
}
return a.value();
}
private FieldOption readFieldOption(Field field, FieldOption implicitOption) {
int mod = field.getModifiers();
if(Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
return FieldOption.IGNORE;
}
if(isAnnotated(field, Ignore.class)) {
return FieldOption.IGNORE;
} else if(isAnnotated(field, Required.class)) {
return FieldOption.REQUIRED;
} else if(isAnnotated(field, Optional.class)) {
return FieldOption.OPTIONAL;
} else if(isAnnotated(field, Nullable.class)) {
if(field.getDeclaringClass().isPrimitive()) {
return FieldOption.REQUIRED;
} else {
return FieldOption.NULLABLE;
}
}
if(implicitOption != FieldOption.DEFAULT) {
return implicitOption;
}
// default mode:
// transient : Ignore
// public : Required
// others : Ignore
if(Modifier.isTransient(mod)) {
return FieldOption.IGNORE;
} else if(Modifier.isPublic(mod)) {
return FieldOption.REQUIRED;
} else {
return FieldOption.IGNORE;
}
}
private int readFieldIndex(Field field, int maxIndex) {
Index a = field.getAnnotation(Index.class);
if(a == null) {
return maxIndex + 1;
} else {
return a.value();
}
}
protected boolean isAnnotated(AccessibleObject ao, Class<? extends Annotation> with) {
return ao.getAnnotation(with) != null;
}
}

View File

@ -0,0 +1,212 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.template;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Type;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.annotation.Annotation;
import org.msgpack.annotation.MessagePackMessage;
import org.msgpack.annotation.MessagePackDelegate;
import org.msgpack.annotation.MessagePackOrdinalEnum;
import org.msgpack.Template;
import org.msgpack.Templates;
public class TemplateRegistry {
private static Map<Type, Template> map;
private static Map<Type, GenericTemplate> genericMap;
static {
map = new HashMap<Type, Template>();
genericMap = new HashMap<Type, GenericTemplate>();
BuiltInTemplateLoader.load();
}
public static void register(Class<?> target) { // auto-detect
if(target.isEnum()) {
register(target, TemplateBuilder.buildOrdinalEnum(target));
} else {
register(target, TemplateBuilder.build(target));
}
}
public static void register(Class<?> target, FieldOption implicitOption) {
register(target, TemplateBuilder.build(target, implicitOption));
}
public static void register(Class<?> target, FieldList flist) throws NoSuchFieldException {
register(target, TemplateBuilder.build(target, flist));
}
public static synchronized void register(Type rawType, Template tmpl) {
if(rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType)rawType).getRawType();
}
map.put(rawType, tmpl);
}
public static synchronized void registerGeneric(Type rawType, GenericTemplate gtmpl) {
if(rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType)rawType).getRawType();
}
genericMap.put(rawType, gtmpl);
}
public static synchronized Template lookup(Type targetType) {
return lookupImpl(targetType, false, true);
}
public static synchronized Template lookup(Type targetType, boolean forceBuild) {
return lookupImpl(targetType, forceBuild, true);
}
public static synchronized Template tryLookup(Type targetType) {
return lookupImpl(targetType, false, false);
}
public static synchronized Template tryLookup(Type targetType, boolean forceBuild) {
return lookupImpl(targetType, forceBuild, false);
}
private static synchronized Template lookupImpl(Type targetType, boolean forceBuild, boolean fallbackDefault) {
Template tmpl;
Class<?> target;
// TODO
//if((Type)target instanceof GenericArrayType) {
// return lookupArrayImpl((GenericArrayType)(Type)target);
//}
if(targetType instanceof ParameterizedType) {
tmpl = lookupGenericImpl((ParameterizedType)targetType);
if(tmpl != null) {
return tmpl;
}
target = (Class<?>)((ParameterizedType)targetType).getRawType();
} else {
target = (Class<?>)targetType;
}
tmpl = map.get(target);
if(tmpl != null) {
return tmpl;
}
if(isAnnotated(target, MessagePackMessage.class)) {
tmpl = TemplateBuilder.build(target);
register(target, tmpl);
return tmpl;
} else if(isAnnotated(target, MessagePackDelegate.class)) {
// TODO DelegateTemplate
throw new UnsupportedOperationException("not supported yet. : " + target.getName());
} else if(isAnnotated(target, MessagePackOrdinalEnum.class)) {
tmpl = TemplateBuilder.buildOrdinalEnum(target);
register(target, tmpl);
return tmpl;
}
for(Class<?> i : target.getInterfaces()) {
tmpl = map.get(i);
if(tmpl != null) {
map.put(target, tmpl);
return tmpl;
}
}
Class<?> c = target.getSuperclass();
if(c != null) {
for(; c != Object.class; c = c.getSuperclass()) {
tmpl = map.get(c);
if(tmpl != null) {
map.put(target, tmpl);
return tmpl;
}
}
if(forceBuild) {
tmpl = TemplateBuilder.build(target);
register(target, tmpl);
return tmpl;
}
}
if(fallbackDefault) {
tmpl = new DefaultTemplate((Class<?>)target);
register(target, tmpl);
return tmpl;
} else {
return null;
}
}
public static synchronized Template lookupGeneric(Type targetType) {
if(targetType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)targetType;
Template tmpl = lookupGenericImpl(parameterizedType);
if(tmpl != null) {
return tmpl;
}
return new DefaultTemplate((Class<?>)parameterizedType.getRawType(), parameterizedType);
} else {
throw new IllegalArgumentException("actual types of the generic type are erased: "+targetType);
}
}
private static synchronized Template lookupGenericImpl(ParameterizedType type) {
Type rawType = type.getRawType();
GenericTemplate gtmpl = genericMap.get(rawType);
if(gtmpl == null) {
return null;
}
Type[] types = type.getActualTypeArguments();
Template[] tmpls = new Template[types.length];
for(int i=0; i < types.length; i++) {
tmpls[i] = lookup(types[i]);
}
return gtmpl.build(tmpls);
}
public static synchronized Template lookupArray(Type targetType) {
if(targetType instanceof GenericArrayType) {
GenericArrayType arrayType = (GenericArrayType)targetType;
return lookupArrayImpl(arrayType);
} else {
throw new IllegalArgumentException("actual type of the array type is erased: "+targetType);
}
}
private static synchronized Template lookupArrayImpl(GenericArrayType arrayType) {
Template tmpl = map.get(arrayType);
if(tmpl != null) {
// TODO primitive types are included?
return tmpl;
}
Type component = arrayType.getGenericComponentType();
Template componentTemplate = lookup(component);
return new ObjectArrayTemplate(componentTemplate);
}
private static boolean isAnnotated(Class<?> ao, Class<? extends Annotation> with) {
return ao.getAnnotation(with) != null;
}
}

View File

@ -0,0 +1,69 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.type;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import org.msgpack.*;
public final class Raw {
private byte[] bytes;
private String string;
public Raw(byte[] bytes) {
this.bytes = bytes;
this.string = null;
}
public Raw(String string) {
this.bytes = null;
this.string = string;
}
public String toString() {
if(string == null) {
try {
string = new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return string;
}
public byte[] toByteArray() {
if(bytes == null) {
try {
bytes = string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return bytes;
}
public ByteBuffer toByteBuffer() {
return ByteBuffer.wrap(toByteArray());
}
static {
RawTemplate.load();
}
}

View File

@ -0,0 +1,51 @@
//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack.type;
import java.io.IOException;
import org.msgpack.*;
import org.msgpack.template.TemplateRegistry;
public class RawTemplate implements Template {
static void load() { }
private RawTemplate() { }
public void pack(Packer pk, Object target) throws IOException {
pk.packByteArray(((Raw)target).toByteArray());
}
public Object unpack(Unpacker pac, Object to) throws IOException, MessageTypeException {
return new Raw(pac.unpackByteArray());
}
public Object convert(MessagePackObject from, Object to) throws MessageTypeException {
return new Raw(from.asByteArray());
}
static public RawTemplate getInstance() {
return instance;
}
static final RawTemplate instance = new RawTemplate();
static {
TemplateRegistry.register(Raw.class, instance);
}
}

View File

@ -333,6 +333,8 @@ public class DynamicCodeGenBase implements Constants {
return Templates.tString();
} else if (c.equals(BigInteger.class)) {
return Templates.tBigInteger();
} else if (c.equals(byte[].class)) {
return Templates.tByteArray();
} else if (c.equals(ByteBuffer.class)) {
return Templates.tByteBuffer();
} else if (CustomConverter.isRegistered(c)) {// FIXME

View File

@ -0,0 +1,45 @@
package org.msgpack.buffer;
import org.msgpack.*;
import org.msgpack.object.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.net.*;
import junit.framework.*;
import org.junit.Test;
public class VectoredByteBufferTest extends TestCase {
public VectoredByteBufferTest() {
}
@Test
public void testIO() throws Exception {
VectoredByteBuffer v = new VectoredByteBuffer();
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] ref = new byte[40];
byte[] copy = new byte[3];
ref[0] = 10;
ref[1] = 20;
ref[2] = 30;
copy[0] = 40;
copy[1] = 50;
copy[2] = 60;
byte[][] src = new byte[][] {
copy, ref, ref, copy, ref, copy, copy, ref
};
for(byte[] s : src) {
bo.write(s);
v.write(s);
}
ByteArrayOutputStream check = new ByteArrayOutputStream();
v.writeTo(check);
assertEquals(bo.size(), check.size());
assertTrue(Arrays.equals(bo.toByteArray(), check.toByteArray()));
}
}

View File

@ -0,0 +1,218 @@
package org.msgpack.template;
import java.util.*;
import java.io.*;
import java.math.*;
import org.msgpack.*;
import org.msgpack.annotation.*;
import org.junit.Test;
import junit.framework.TestCase;
public class TestTemplateBuilder extends TestCase {
public static class PrimitiveTypeFieldsClass {
public byte f0;
public short f1;
public int f2;
public long f3;
public float f4;
public double f5;
public boolean f6;
public PrimitiveTypeFieldsClass() {
}
}
public static class GeneralReferenceTypeFieldsClass {
public Byte f0;
public Short f1;
public Integer f2;
public Long f3;
public Float f4;
public Double f5;
public Boolean f6;
public BigInteger f7;
public String f8;
public byte[] f9;
public GeneralReferenceTypeFieldsClass() {
}
}
public static class SampleListTypes {
public List<Integer> f0;
public List<Integer> f1;
public List<String> f2;
public List<List<String>> f3;
public List<SampleListNestedType> f4;
public SampleListTypes() {
}
}
@MessagePackMessage
public static class SampleListNestedType {
public byte[] f0;
public String f1;
public SampleListNestedType() {
}
}
public static class SampleMapTypes {
public Map<Integer, Integer> f0;
public Map<Integer, Integer> f1;
public Map<String, Integer> f2;
public SampleMapTypes() {
}
}
static void buildAndRegisterTemplate(Class<?> targetClass) {
MessagePack.register(targetClass,
TemplateBuilder.build(targetClass));
}
static {
buildAndRegisterTemplate(PrimitiveTypeFieldsClass.class);
buildAndRegisterTemplate(GeneralReferenceTypeFieldsClass.class);
buildAndRegisterTemplate(SampleListNestedType.class);
buildAndRegisterTemplate(SampleListTypes.class);
buildAndRegisterTemplate(SampleMapTypes.class);
}
@Test
public void testPrimitiveTypeFieldsClass00() throws Exception {
PrimitiveTypeFieldsClass src = new PrimitiveTypeFieldsClass();
src.f0 = (byte) 0;
src.f1 = 1;
src.f2 = 2;
src.f3 = 3;
src.f4 = 4;
src.f5 = 5;
src.f6 = false;
byte[] raw = MessagePack.pack(src);
PrimitiveTypeFieldsClass dstu =
MessagePack.unpack(raw, PrimitiveTypeFieldsClass.class);
assertEquals(src.f0, dstu.f0);
assertEquals(src.f1, dstu.f1);
assertEquals(src.f2, dstu.f2);
assertEquals(src.f3, dstu.f3);
assertEquals(src.f4, dstu.f4);
assertEquals(src.f5, dstu.f5);
assertEquals(src.f6, dstu.f6);
MessagePackObject o = MessagePack.unpack(raw);
PrimitiveTypeFieldsClass dsto =
o.convert(PrimitiveTypeFieldsClass.class);
assertEquals(src.f0, dsto.f0);
assertEquals(src.f1, dsto.f1);
assertEquals(src.f2, dsto.f2);
assertEquals(src.f3, dsto.f3);
assertEquals(src.f4, dsto.f4);
assertEquals(src.f5, dsto.f5);
assertEquals(src.f6, dsto.f6);
}
public void testGeneralReferenceTypeFieldsClass() throws Exception {
GeneralReferenceTypeFieldsClass src = new GeneralReferenceTypeFieldsClass();
src.f0 = 0;
src.f1 = 1;
src.f2 = 2;
src.f3 = (long) 3;
src.f4 = (float) 4;
src.f5 = (double) 5;
src.f6 = false;
src.f7 = new BigInteger("7");
src.f8 = "8";
src.f9 = new byte[] { 0x01, 0x02 };
byte[] raw = MessagePack.pack(src);
GeneralReferenceTypeFieldsClass dstu =
MessagePack.unpack(raw, GeneralReferenceTypeFieldsClass.class);
assertEquals(src.f0, dstu.f0);
assertEquals(src.f1, dstu.f1);
assertEquals(src.f2, dstu.f2);
assertEquals(src.f3, dstu.f3);
assertEquals(src.f4, dstu.f4);
assertEquals(src.f5, dstu.f5);
assertEquals(src.f6, dstu.f6);
assertEquals(src.f7, dstu.f7);
assertEquals(src.f8, dstu.f8);
assertEquals(src.f9[0], dstu.f9[0]);
assertEquals(src.f9[1], dstu.f9[1]);
MessagePackObject o = MessagePack.unpack(raw);
GeneralReferenceTypeFieldsClass dsto =
o.convert(GeneralReferenceTypeFieldsClass.class);
assertEquals(src.f0, dsto.f0);
assertEquals(src.f1, dsto.f1);
assertEquals(src.f2, dsto.f2);
assertEquals(src.f3, dsto.f3);
assertEquals(src.f4, dsto.f4);
assertEquals(src.f5, dsto.f5);
assertEquals(src.f6, dsto.f6);
assertEquals(src.f7, dsto.f7);
assertEquals(src.f8, dsto.f8);
assertEquals(src.f9[0], dsto.f9[0]);
assertEquals(src.f9[1], dsto.f9[1]);
}
@Test
public void testListTypes() throws Exception {
SampleListTypes src = new SampleListTypes();
src.f0 = new ArrayList<Integer>();
src.f1 = new ArrayList<Integer>();
src.f1.add(1);
src.f1.add(2);
src.f1.add(3);
src.f2 = new ArrayList<String>();
src.f2.add("e1");
src.f2.add("e2");
src.f2.add("e3");
src.f3 = new ArrayList<List<String>>();
src.f3.add(src.f2);
src.f4 = new ArrayList<SampleListNestedType>();
SampleListNestedType slnt = new SampleListNestedType();
slnt.f0 = new byte[] { 0x01, 0x02 };
slnt.f1 = "muga";
src.f4.add(slnt);
byte[] raw = MessagePack.pack(src);
SampleListTypes dstu =
MessagePack.unpack(raw, SampleListTypes.class);
assertEquals(src.f0.size(), dstu.f0.size());
assertEquals(src.f1.size(), dstu.f1.size());
for (int i = 0; i < src.f1.size(); ++i) {
assertEquals(src.f1.get(i), dstu.f1.get(i));
}
assertEquals(src.f2.size(), dstu.f2.size());
for (int i = 0; i < src.f2.size(); ++i) {
assertEquals(src.f2.get(i), dstu.f2.get(i));
}
assertEquals(src.f3.size(), dstu.f3.size());
for (int i = 0; i < src.f3.size(); ++i) {
List<String> srclist = src.f3.get(i);
List<String> dstlist = dstu.f3.get(i);
assertEquals(srclist.size(), dstlist.size());
for (int j = 0; j < srclist.size(); ++j) {
assertEquals(srclist.get(j), dstlist.get(j));
}
}
assertEquals(src.f4.size(), dstu.f4.size());
for (int i = 0; i < src.f4.size(); ++i) {
SampleListNestedType s = src.f4.get(i);
SampleListNestedType d = dstu.f4.get(i);
assertEquals(s.f0[0], d.f0[0]);
assertEquals(s.f0[1], d.f0[1]);
assertEquals(s.f1, d.f1);
}
}
}

View File

@ -18,8 +18,9 @@
#ifndef MSGPACK_SYSDEP_H__
#define MSGPACK_SYSDEP_H__
#ifdef _MSC_VER
#include <stdlib.h>
#include <stddef.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
@ -28,8 +29,9 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#elif defined(_MSC_VER) // && _MSC_VER >= 1600
#include <stdint.h>
#else
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#endif
@ -76,7 +78,7 @@ typedef unsigned int _msgpack_atomic_counter_t;
#define _msgpack_be16(x) ntohs(x)
#define _msgpack_be32(x) ntohl(x)
#if defined(_byteswap_uint64)
#if defined(_byteswap_uint64) || _MSC_VER >= 1400
# define _msgpack_be64(x) (_byteswap_uint64(x))
#elif defined(bswap_64)
# define _msgpack_be64(x) bswap_64(x)

View File

@ -8,6 +8,7 @@ cp pack.h ext/
cp rbinit.c ext/
cp unpack.c ext/
cp unpack.h ext/
cp compat.h ext/
cp version.rb ext/
cp ../msgpack/pack_define.h msgpack/
cp ../msgpack/pack_template.h msgpack/

View File

@ -227,8 +227,9 @@ class MessagePackTestPackUnpack < Test::Unit::TestCase
assert(fe.length > 0)
off += fe.length
pac.feed fe
pac.each {|obj|
#pac.feed fe
#pac.each {|obj|
pac.feed_each(fe) {|obj|
assert(!parsed)
assert_equal(obj, str)
parsed = true
@ -245,8 +246,8 @@ class MessagePackTestPackUnpack < Test::Unit::TestCase
pac = MessagePack::Unpacker.new
parsed = 0
raw.split(//).each do |b|
pac.feed(b)
pac.each {|o|
#pac.feed(b)
pac.feed_each(b) {|o|
GC.start
assert_equal(obj, o)
parsed += 1

View File

@ -24,7 +24,7 @@ static ID s_sysread;
static ID s_readpartial;
struct unpack_buffer {
size_t size;
size_t used;
size_t free;
char* ptr;
};
@ -37,6 +37,7 @@ typedef struct {
VALUE stream;
VALUE streambuf;
ID stream_append_method;
size_t buffer_free_size;
} unpack_user;
@ -241,6 +242,13 @@ static VALUE eUnpackError;
#define MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE (8*1024)
#endif
/*
#ifndef MSGPACK_BUFFER_FREE_SIZE
#define MSGPACK_BUFFER_FREE_SIZE (1024*1024)
#endif
*/
#define MSGPACK_BUFFER_FREE_SIZE 0
static void MessagePack_Unpacker_free(void* data)
{
if(data) {
@ -273,7 +281,7 @@ static VALUE MessagePack_Unpacker_alloc(VALUE klass)
mp->user.finished = 0;
mp->user.offset = 0;
mp->user.buffer.size = 0;
mp->user.buffer.used = 0;
mp->user.buffer.free = 0;
mp->user.buffer.ptr = NULL;
@ -326,6 +334,7 @@ static VALUE MessagePack_Unpacker_initialize(int argc, VALUE *argv, VALUE self)
mp->user.stream = stream;
mp->user.streambuf = rb_str_buf_new(MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE);
mp->user.stream_append_method = append_method_of(stream);
mp->user.buffer_free_size = MSGPACK_BUFFER_FREE_SIZE;
return self;
}
@ -366,22 +375,27 @@ static void reserve_buffer(msgpack_unpack_t* mp, size_t require)
{
struct unpack_buffer* buffer = &mp->user.buffer;
if(buffer->size == 0) {
size_t nsize = MSGPACK_UNPACKER_BUFFER_INIT_SIZE;
if(buffer->used == 0) {
if(require <= buffer->free) {
/* enough free space */
return;
}
/* no used buffer: realloc only */
size_t nsize = buffer->free == 0 ?
MSGPACK_UNPACKER_BUFFER_INIT_SIZE : buffer->free*2;
while(nsize < require) {
nsize *= 2;
}
char* tmp = ALLOC_N(char, nsize);
buffer->ptr = tmp;
char* tmp = REALLOC_N(buffer->ptr, char, nsize);
buffer->free = nsize;
buffer->size = 0;
buffer->ptr = tmp;
return;
}
if(buffer->size <= mp->user.offset) {
if(buffer->used <= mp->user.offset) {
/* clear buffer and rewind offset */
buffer->free += buffer->size;
buffer->size = 0;
buffer->free += buffer->used;
buffer->used = 0;
mp->user.offset = 0;
}
@ -390,41 +404,91 @@ static void reserve_buffer(msgpack_unpack_t* mp, size_t require)
return;
}
size_t nsize = (buffer->size + buffer->free) * 2;
size_t nsize = (buffer->used + buffer->free) * 2;
if(mp->user.offset <= buffer->size / 2) {
if(mp->user.offset <= buffer->used / 2) {
/* parsed less than half: realloc only */
while(nsize < buffer->size + require) {
while(nsize < buffer->used + require) {
nsize *= 2;
}
char* tmp = REALLOC_N(buffer->ptr, char, nsize);
buffer->free = nsize - buffer->size;
buffer->free = nsize - buffer->used;
buffer->ptr = tmp;
} else {
/* parsed more than half: realloc and move */
size_t not_parsed = buffer->size - mp->user.offset;
size_t not_parsed = buffer->used - mp->user.offset;
while(nsize < not_parsed + require) {
nsize *= 2;
}
char* tmp = REALLOC_N(buffer->ptr, char, nsize);
memcpy(tmp, tmp + mp->user.offset, not_parsed);
buffer->free = nsize - buffer->size;
buffer->size = not_parsed;
buffer->free = nsize - not_parsed;
buffer->used = not_parsed;
buffer->ptr = tmp;
mp->user.offset = 0;
}
}
static inline void feed_buffer(msgpack_unpack_t* mp, const char* ptr, size_t len)
static inline void try_free_buffer(msgpack_unpack_t* mp, size_t require)
{
if(mp->user.buffer_free_size == 0) {
return;
}
struct unpack_buffer* buffer = &mp->user.buffer;
size_t csize = buffer->used + buffer->free;
if(csize <= mp->user.buffer_free_size) {
return;
}
if(mp->user.offset <= buffer->used / 2) {
/* parsed less than half: do nothing */
} else if(mp->user.offset < buffer->used) {
/* parsed more than half but not all: realloc and move */
size_t nsize = MSGPACK_UNPACKER_BUFFER_INIT_SIZE;
size_t not_parsed = buffer->used - mp->user.offset;
while(nsize < not_parsed + require) {
nsize *= 2;
}
if(nsize >= csize) {
return;
}
char* tmp;
if(mp->user.offset == 0) {
tmp = ALLOC_N(char, nsize);
memcpy(tmp, buffer->ptr + mp->user.offset, not_parsed);
free(buffer->ptr);
} else {
tmp = REALLOC_N(buffer->ptr, char, nsize);
}
buffer->free = nsize - not_parsed;
buffer->used = not_parsed;
buffer->ptr = tmp;
mp->user.offset = 0;
} else {
/* all parsed: free all */
free(buffer->ptr);
buffer->free = 0;
buffer->used = 0;
buffer->ptr = NULL;
mp->user.offset = 0;
}
}
static void feed_buffer(msgpack_unpack_t* mp, const char* ptr, size_t len)
{
struct unpack_buffer* buffer = &mp->user.buffer;
if(buffer->free < len) {
reserve_buffer(mp, len);
}
memcpy(buffer->ptr + buffer->size, ptr, len);
buffer->size += len;
memcpy(buffer->ptr + buffer->used, ptr, len);
buffer->used += len;
buffer->free -= len;
}
@ -498,7 +562,7 @@ static VALUE MessagePack_Unpacker_each(VALUE self)
#endif
while(1) {
if(mp->user.buffer.size <= mp->user.offset) {
if(mp->user.buffer.used <= mp->user.offset) {
do_fill:
{
VALUE len = MessagePack_Unpacker_fill(self);
@ -509,7 +573,7 @@ static VALUE MessagePack_Unpacker_each(VALUE self)
}
ret = template_execute_wrap_each(mp,
mp->user.buffer.ptr, mp->user.buffer.size,
mp->user.buffer.ptr, mp->user.buffer.used,
&mp->user.offset);
if(ret < 0) {
@ -525,9 +589,131 @@ static VALUE MessagePack_Unpacker_each(VALUE self)
}
}
try_free_buffer(mp, 0);
return Qnil;
}
static VALUE feed_each_impl(VALUE args)
{
VALUE self = ((VALUE*)args)[0];
VALUE data = ((VALUE*)args)[1];
size_t* pconsumed = (size_t*)((VALUE*)args)[2];
UNPACKER(self, mp);
int ret;
const char* ptr = RSTRING_PTR(data);
size_t len = RSTRING_LEN(data);
if(mp->user.buffer.used > 0) {
while(1) {
ret = template_execute_wrap_each(mp,
mp->user.buffer.ptr, mp->user.buffer.used,
&mp->user.offset);
if(ret < 0) {
rb_raise(eUnpackError, "parse error.");
} else if(ret > 0) {
VALUE data = template_data(mp);
template_init(mp);
rb_yield(data);
} else {
break;
}
}
}
if(len <= 0) {
return Qnil;
}
if(mp->user.buffer.used <= mp->user.offset) {
// wrap & execute & feed
while(1) {
ret = template_execute_wrap_each(mp,
ptr, len, pconsumed);
if(ret < 0) {
rb_raise(eUnpackError, "parse error.");
} else if(ret > 0) {
VALUE data = template_data(mp);
template_init(mp);
rb_yield(data);
} else {
break;
}
}
} else {
// feed & execute
feed_buffer(mp, ptr, len);
*pconsumed = len;
while(1) {
ret = template_execute_wrap_each(mp,
mp->user.buffer.ptr, mp->user.buffer.used,
&mp->user.offset);
if(ret < 0) {
rb_raise(eUnpackError, "parse error.");
} else if(ret > 0) {
VALUE data = template_data(mp);
template_init(mp);
rb_yield(data);
} else {
break;
}
}
}
return Qnil;
}
static VALUE feed_each_ensure(VALUE args) {
VALUE self = ((VALUE*)args)[0];
VALUE data = ((VALUE*)args)[1];
size_t* pconsumed = (size_t*)((VALUE*)args)[2];
const char* dptr = RSTRING_PTR(data) + *pconsumed;
size_t dlen = RSTRING_LEN(data) - *pconsumed;
if(dlen > 0) {
UNPACKER(self, mp);
try_free_buffer(mp, dlen);
feed_buffer(mp, dptr, dlen);
}
return Qnil;
}
/**
* Document-method: MessagePack::Unpacker#feed_each
*
* call-seq:
* unpacker.feed_each(data) {|object| }
*
* Same as feed(data) + each {|object| }, but tries to avoid copying of the buffer.
*/
static VALUE MessagePack_Unpacker_feed_each(VALUE self, VALUE data)
{
size_t consumed = 0;
StringValue(data);
VALUE args[3];
args[0] = self;
args[1] = data;
args[2] = (VALUE)&consumed;
return rb_ensure(feed_each_impl, (VALUE)args,
feed_each_ensure, (VALUE)args);
}
static inline VALUE MessagePack_unpack_impl(VALUE self, VALUE data, unsigned long dlen)
{
@ -620,7 +806,7 @@ static VALUE MessagePack_Unpacker_execute_impl(VALUE self, VALUE data,
*
* This method doesn't use the internal buffer.
*
* Call *reset()* method before calling this method again.
* Call *reset* method before calling this method again.
*
* UnpackError is throw when parse error is occured.
*/
@ -642,7 +828,7 @@ static VALUE MessagePack_Unpacker_execute_limit(VALUE self, VALUE data,
*
* This method doesn't use the internal buffer.
*
* Call *reset()* method before calling this method again.
* Call *reset* method before calling this method again.
*
* This returns offset that was parsed to.
* Use *finished?* method to check an object is deserialized and call *data*
@ -705,6 +891,7 @@ static VALUE MessagePack_Unpacker_reset(VALUE self)
UNPACKER(self, mp);
template_init(mp);
mp->user.finished = 0;
try_free_buffer(mp, 0);
return self;
}
@ -726,6 +913,7 @@ void Init_msgpack_unpack(VALUE mMessagePack)
rb_define_method(cUnpacker, "each", MessagePack_Unpacker_each, 0);
rb_define_method(cUnpacker, "stream", MessagePack_Unpacker_stream_get, 0);
rb_define_method(cUnpacker, "stream=", MessagePack_Unpacker_stream_set, 1);
rb_define_method(cUnpacker, "feed_each", MessagePack_Unpacker_feed_each, 1);
/* Unbuffered API */
rb_define_method(cUnpacker, "execute", MessagePack_Unpacker_execute, 2);

View File

@ -1,3 +1,3 @@
module MessagePack
VERSION = "0.4.3"
VERSION = "0.4.4"
end