From f0e3d9b032501d7d01b888d896d6e067e4896e75 Mon Sep 17 00:00:00 2001 From: kamhung <22250530@qq.com> Date: Wed, 9 Dec 2015 11:15:38 +0800 Subject: [PATCH] --- .../src/org/redkale/convert/AnyEncoder.java | 40 ++ .../src/org/redkale/convert/ArrayDecoder.java | 79 +++ .../src/org/redkale/convert/ArrayEncoder.java | 75 +++ .../redkale/convert/CollectionDecoder.java | 69 +++ .../redkale/convert/CollectionEncoder.java | 65 ++ .../src/org/redkale/convert/Convert.java | 26 + .../org/redkale/convert/ConvertColumn.java | 44 ++ .../redkale/convert/ConvertColumnEntry.java | 67 ++ .../org/redkale/convert/ConvertColumns.java | 24 + .../org/redkale/convert/ConvertEntity.java | 25 + .../org/redkale/convert/ConvertException.java | 28 + .../src/org/redkale/convert/ConvertType.java | 28 + .../src/org/redkale/convert/DeMember.java | 64 ++ .../src/org/redkale/convert/Decodeable.java | 27 + .../src/org/redkale/convert/EnMember.java | 76 +++ .../src/org/redkale/convert/Encodeable.java | 27 + .../src/org/redkale/convert/Factory.java | 386 ++++++++++++ .../src/org/redkale/convert/HashedMap.java | 70 +++ .../src/org/redkale/convert/MapDecoder.java | 78 +++ .../src/org/redkale/convert/MapEncoder.java | 62 ++ .../org/redkale/convert/ObjectDecoder.java | 157 +++++ .../org/redkale/convert/ObjectEncoder.java | 234 +++++++ .../src/org/redkale/convert/Reader.java | 112 ++++ .../src/org/redkale/convert/SimpledCoder.java | 42 ++ .../src/org/redkale/convert/Writer.java | 120 ++++ .../convert/bson/BsonByteBufferWriter.java | 134 ++++ .../org/redkale/convert/bson/BsonConvert.java | 155 +++++ .../org/redkale/convert/bson/BsonFactory.java | 62 ++ .../org/redkale/convert/bson/BsonReader.java | 323 ++++++++++ .../convert/bson/BsonSimpledCoder.java | 17 + .../org/redkale/convert/bson/BsonWriter.java | 297 +++++++++ .../convert/ext/BigIntegerSimpledCoder.java | 38 ++ .../convert/ext/BoolArraySimpledCoder.java | 68 +++ .../redkale/convert/ext/BoolSimpledCoder.java | 32 + .../convert/ext/ByteArraySimpledCoder.java | 68 +++ .../redkale/convert/ext/ByteSimpledCoder.java | 32 + .../convert/ext/CharArraySimpledCoder.java | 68 +++ .../redkale/convert/ext/CharSimpledCoder.java | 33 + .../convert/ext/DLongSimpledCoder.java | 40 ++ .../redkale/convert/ext/DateSimpledCoder.java | 33 + .../convert/ext/DoubleArraySimpledCoder.java | 68 +++ .../convert/ext/DoubleSimpledCoder.java | 32 + .../redkale/convert/ext/EnumSimpledCoder.java | 44 ++ .../convert/ext/FloatArraySimpledCoder.java | 68 +++ .../convert/ext/FloatSimpledCoder.java | 32 + .../convert/ext/InetAddressSimpledCoder.java | 70 +++ .../convert/ext/IntArraySimpledCoder.java | 68 +++ .../redkale/convert/ext/IntSimpledCoder.java | 32 + .../convert/ext/LongArraySimpledCoder.java | 68 +++ .../redkale/convert/ext/LongSimpledCoder.java | 33 + .../convert/ext/NumberSimpledCoder.java | 32 + .../convert/ext/PatternSimpledCoder.java | 38 ++ .../convert/ext/ShortArraySimpledCoder.java | 68 +++ .../convert/ext/ShortSimpledCoder.java | 32 + .../convert/ext/StringArraySimpledCoder.java | 68 +++ .../convert/ext/StringSimpledCoder.java | 32 + .../redkale/convert/ext/TypeSimpledCoder.java | 42 ++ .../json/InetAddressJsonSimpledCoder.java | 68 +++ .../convert/json/JsonByteBufferWriter.java | 348 +++++++++++ .../org/redkale/convert/json/JsonConvert.java | 137 +++++ .../org/redkale/convert/json/JsonFactory.java | 60 ++ .../org/redkale/convert/json/JsonReader.java | 577 ++++++++++++++++++ .../convert/json/JsonSimpledCoder.java | 17 + .../org/redkale/convert/json/JsonWriter.java | 268 ++++++++ .../org/redkale/net/client/HttpClient.java | 89 +++ .../org/redkale/net/client/HttpFactory.java | 85 +++ .../redkale/net/client/WebSocketClient.java | 154 +++++ .../src/org/redkale/util/Attribute.java | 300 +++++++++ .../src/org/redkale/util/ByteArray.java | 161 +++++ .../redkale/util/ConstructorProperties.java | 24 + .../src/org/redkale/util/Creator.java | 210 +++++++ .../src/org/redkale/util/DLong.java | 81 +++ .../org/redkale/util/DebugMethodVisitor.java | 143 +++++ .../src/org/redkale/util/ObjectPool.java | 100 +++ .../src/org/redkale/util/Sheet.java | 87 +++ .../src/org/redkale/util/TypeToken.java | 26 + .../src/org/redkale/util/Utility.java | 470 ++++++++++++++ 77 files changed, 7657 insertions(+) create mode 100644 android-jdk6-redkale/src/org/redkale/convert/AnyEncoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ArrayDecoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ArrayEncoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/CollectionDecoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/CollectionEncoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/Convert.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ConvertColumn.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ConvertColumnEntry.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ConvertColumns.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ConvertEntity.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ConvertException.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ConvertType.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/DeMember.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/Decodeable.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/EnMember.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/Encodeable.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/Factory.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/HashedMap.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/MapDecoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/MapEncoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ObjectDecoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ObjectEncoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/Reader.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/SimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/Writer.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/bson/BsonByteBufferWriter.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/bson/BsonConvert.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/bson/BsonFactory.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/bson/BsonReader.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/bson/BsonSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/bson/BsonWriter.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/BigIntegerSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/BoolArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/BoolSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/ByteArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/ByteSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/CharArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/CharSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/DLongSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/DateSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/DoubleArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/DoubleSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/EnumSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/FloatArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/FloatSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/InetAddressSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/IntArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/IntSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/LongArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/LongSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/NumberSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/PatternSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/ShortArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/ShortSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/StringArraySimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/StringSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/ext/TypeSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/InetAddressJsonSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/JsonByteBufferWriter.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/JsonConvert.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/JsonFactory.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/JsonReader.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/JsonSimpledCoder.java create mode 100644 android-jdk6-redkale/src/org/redkale/convert/json/JsonWriter.java create mode 100644 android-jdk6-redkale/src/org/redkale/net/client/HttpClient.java create mode 100644 android-jdk6-redkale/src/org/redkale/net/client/HttpFactory.java create mode 100644 android-jdk6-redkale/src/org/redkale/net/client/WebSocketClient.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/Attribute.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/ByteArray.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/ConstructorProperties.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/Creator.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/DLong.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/DebugMethodVisitor.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/ObjectPool.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/Sheet.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/TypeToken.java create mode 100644 android-jdk6-redkale/src/org/redkale/util/Utility.java diff --git a/android-jdk6-redkale/src/org/redkale/convert/AnyEncoder.java b/android-jdk6-redkale/src/org/redkale/convert/AnyEncoder.java new file mode 100644 index 000000000..72685f9a8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/AnyEncoder.java @@ -0,0 +1,40 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.Type; + +/** + * 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入Writer,JSON则不写入。 + * + * @author zhangjx + * @param + */ +public final class AnyEncoder implements Encodeable { + + final Factory factory; + + AnyEncoder(Factory factory) { + this.factory = factory; + } + + @Override + @SuppressWarnings("unchecked") + public void convertTo(final Writer out, final T value) { + if (value == null) { + out.writeNull(); + } else { + out.wirteClassName(factory.getEntity(value.getClass())); + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + } + + @Override + public Type getType() { + return Object.class; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ArrayDecoder.java b/android-jdk6-redkale/src/org/redkale/convert/ArrayDecoder.java new file mode 100644 index 000000000..4259402d4 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ArrayDecoder.java @@ -0,0 +1,79 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.*; +import java.util.*; + +/** + * 对象数组的序列化,不包含int[]、long[]这样的primitive class数组. + * 数组长度不能超过 32767。 在BSON中数组长度设定的是short,对于大于32767长度的数组传输会影响性能,所以没有采用int存储。 + * 支持一定程度的泛型。 + * + * @author zhangjx + * @param + */ +@SuppressWarnings("unchecked") +public final class ArrayDecoder implements Decodeable { + + private final Type type; + + private final Type componentType; + + private final Class componentClass; + + private final Decodeable decoder; + + public ArrayDecoder(final Factory factory, final Type type) { + this.type = type; + if (type instanceof GenericArrayType) { + Type t = ((GenericArrayType) type).getGenericComponentType(); + this.componentType = t instanceof TypeVariable ? Object.class : t; + } else if ((type instanceof Class) && ((Class) type).isArray()) { + this.componentType = ((Class) type).getComponentType(); + } else { + throw new ConvertException("(" + type + ") is not a array type"); + } + if (this.componentType instanceof ParameterizedType) { + this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType(); + } else { + this.componentClass = (Class) this.componentType; + } + factory.register(type, this); + this.decoder = factory.loadDecoder(this.componentType); + } + + @Override + public T[] convertFrom(Reader in) { + final int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) return null; + final Decodeable localdecoder = this.decoder; + final List result = new ArrayList(); + if (len == Reader.SIGN_NOLENGTH) { + while (in.hasNext()) { + result.add(localdecoder.convertFrom(in)); + } + } else { + for (int i = 0; i < len; i++) { + result.add(localdecoder.convertFrom(in)); + } + } + in.readArrayE(); + T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size()); + return result.toArray(rs); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}"; + } + + @Override + public Type getType() { + return type; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ArrayEncoder.java b/android-jdk6-redkale/src/org/redkale/convert/ArrayEncoder.java new file mode 100644 index 000000000..31421784c --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ArrayEncoder.java @@ -0,0 +1,75 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.*; + +/** + * 对象数组的反序列化,不包含int[]、long[]这样的primitive class数组. + * 数组长度不能超过 32767。 在BSON中数组长度设定的是short,对于大于32767长度的数组传输会影响性能,所以没有采用int存储。 + * 支持一定程度的泛型。 + * + * @author zhangjx + * @param + */ +@SuppressWarnings("unchecked") +public final class ArrayEncoder implements Encodeable { + + private final Type type; + + private final Type componentType; + + private final Encodeable anyEncoder; + + private final Encodeable encoder; + + public ArrayEncoder(final Factory factory, final Type type) { + this.type = type; + if (type instanceof GenericArrayType) { + Type t = ((GenericArrayType) type).getGenericComponentType(); + this.componentType = t instanceof TypeVariable ? Object.class : t; + } else if ((type instanceof Class) && ((Class) type).isArray()) { + this.componentType = ((Class) type).getComponentType(); + } else { + throw new ConvertException("(" + type + ") is not a array type"); + } + factory.register(type, this); + this.encoder = factory.loadEncoder(this.componentType); + this.anyEncoder = factory.getAnyEncoder(); + } + + @Override + public void convertTo(Writer out, T[] value) { + if (value == null) { + out.writeNull(); + return; + } + if (value.length == 0) { + out.writeArrayB(0); + out.writeArrayE(); + return; + } + out.writeArrayB(value.length); + final Type comp = this.componentType; + boolean first = true; + for (Object v : value) { + if (!first) out.writeArrayMark(); + ((v != null && v.getClass() == comp) ? encoder : anyEncoder).convertTo(out, v); + if (first) first = false; + } + out.writeArrayE(); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.encoder + "}"; + } + + @Override + public Type getType() { + return type; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/CollectionDecoder.java b/android-jdk6-redkale/src/org/redkale/convert/CollectionDecoder.java new file mode 100644 index 000000000..95d7613e7 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/CollectionDecoder.java @@ -0,0 +1,69 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import org.redkale.util.Creator; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collection; + +/** + * 对象集合的反序列化. + * 集合大小不能超过 32767。 在BSON中集合大小设定的是short,对于大于32767长度的集合传输会影响性能,所以没有采用int存储。 + * 支持一定程度的泛型。 + * + * @author zhangjx + * @param + */ +@SuppressWarnings("unchecked") +public final class CollectionDecoder implements Decodeable> { + + private final Type type; + + private final Type componentType; + + protected Creator> creator; + + private final Decodeable decoder; + + public CollectionDecoder(final Factory factory, final Type type) { + this.type = type; + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.componentType = pt.getActualTypeArguments()[0]; + this.creator = factory.loadCreator((Class) pt.getRawType()); + factory.register(type, this); + this.decoder = factory.loadDecoder(this.componentType); + } else { + throw new ConvertException("collectiondecoder not support the type (" + type + ")"); + } + } + + @Override + public Collection convertFrom(Reader in) { + final int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) return null; + final Decodeable localdecoder = this.decoder; + final Collection result = this.creator.create(); + if (len == Reader.SIGN_NOLENGTH) { + while (in.hasNext()) { + result.add(localdecoder.convertFrom(in)); + } + } else { + for (int i = 0; i < len; i++) { + result.add(localdecoder.convertFrom(in)); + } + } + in.readArrayE(); + return result; + } + + @Override + public Type getType() { + return type; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/CollectionEncoder.java b/android-jdk6-redkale/src/org/redkale/convert/CollectionEncoder.java new file mode 100644 index 000000000..fe6206d17 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/CollectionEncoder.java @@ -0,0 +1,65 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.*; +import java.util.Collection; + +/** + * 对象集合的序列化. + * 集合大小不能超过 32767。 在BSON中集合大小设定的是short,对于大于32767长度的集合传输会影响性能,所以没有采用int存储。 + * 支持一定程度的泛型。 + * + * @author zhangjx + * @param + */ +@SuppressWarnings("unchecked") +public final class CollectionEncoder implements Encodeable> { + + private final Type type; + + private final Encodeable encoder; + + public CollectionEncoder(final Factory factory, final Type type) { + this.type = type; + if (type instanceof ParameterizedType) { + Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; + if (t instanceof TypeVariable) { + this.encoder = factory.getAnyEncoder(); + } else { + this.encoder = factory.loadEncoder(t); + } + } else { + this.encoder = factory.getAnyEncoder(); + } + } + + @Override + public void convertTo(Writer out, Collection value) { + if (value == null) { + out.writeNull(); + return; + } + if (value.isEmpty()) { + out.writeArrayB(0); + out.writeArrayE(); + return; + } + out.writeArrayB(value.size()); + boolean first = true; + for (Object v : value) { + if (!first) out.writeArrayMark(); + encoder.convertTo(out, v); + if (first) first = false; + } + out.writeArrayE(); + } + + @Override + public Type getType() { + return type; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/Convert.java b/android-jdk6-redkale/src/org/redkale/convert/Convert.java new file mode 100644 index 000000000..5e93b5f37 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/Convert.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +/** + * 序列化操作类 + * + * @author zhangjx + * @param + * @param + */ +public abstract class Convert { + + protected final Factory factory; + + protected Convert(Factory factory) { + this.factory = factory; + } + + public Factory getFactory() { + return this.factory; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ConvertColumn.java b/android-jdk6-redkale/src/org/redkale/convert/ConvertColumn.java new file mode 100644 index 000000000..974b0db73 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ConvertColumn.java @@ -0,0 +1,44 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * 依附在setter、getter方法、字段进行简单的配置 + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +@Repeatable(ConvertColumns.class) +public @interface ConvertColumn { + + /** + * 给字段取个别名, 只对JSON有效 + * + * @return + */ + String name() default ""; + + /** + * 解析/序列化时是否屏蔽该字段 + * + * @return + */ + boolean ignore() default false; + + /** + * 解析/序列化定制化的TYPE + * + * @return + */ + ConvertType type() default ConvertType.ALL; +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ConvertColumnEntry.java b/android-jdk6-redkale/src/org/redkale/convert/ConvertColumnEntry.java new file mode 100644 index 000000000..273139d26 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ConvertColumnEntry.java @@ -0,0 +1,67 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +/** + * ConvertColumn 对应的实体类 + * + * @author zhangjx + */ +public final class ConvertColumnEntry { + + private String name = ""; + + private boolean ignore; + + private ConvertType convertType; + + public ConvertColumnEntry() { + } + + public ConvertColumnEntry(ConvertColumn column) { + if (column == null) return; + this.name = column.name(); + this.ignore = column.ignore(); + this.convertType = column.type(); + } + + public ConvertColumnEntry(String name, boolean ignore) { + this.name = name; + this.ignore = ignore; + this.convertType = ConvertType.ALL; + } + + public ConvertColumnEntry(String name, boolean ignore, ConvertType convertType) { + this.name = name; + this.ignore = ignore; + this.convertType = convertType; + } + + public String name() { + return name == null ? "" : name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean ignore() { + return ignore; + } + + public void setIgnore(boolean ignore) { + this.ignore = ignore; + } + + public ConvertType type() { + return convertType == null ? ConvertType.ALL : convertType; + } + + public void setConvertType(ConvertType convertType) { + this.convertType = convertType; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ConvertColumns.java b/android-jdk6-redkale/src/org/redkale/convert/ConvertColumns.java new file mode 100644 index 000000000..9e4fbb4eb --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ConvertColumns.java @@ -0,0 +1,24 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * ConvertColumn 的多用类 + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface ConvertColumns { + + ConvertColumn[] value(); +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ConvertEntity.java b/android-jdk6-redkale/src/org/redkale/convert/ConvertEntity.java new file mode 100644 index 000000000..6449df6cd --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ConvertEntity.java @@ -0,0 +1,25 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 用于类名的别名, 类似javax.persistence.Table + * 该值必须是全局唯一 + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface ConvertEntity { + + String value(); +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ConvertException.java b/android-jdk6-redkale/src/org/redkale/convert/ConvertException.java new file mode 100644 index 000000000..4fdc3f6ce --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ConvertException.java @@ -0,0 +1,28 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +/** + * + * @author zhangjx + */ +public class ConvertException extends RuntimeException { + + public ConvertException() { + super(); + } + + public ConvertException(String s) { + super(s); + } + + public ConvertException(String message, Throwable cause) { + super(message, cause); + } + + public ConvertException(Throwable cause) { + super(cause); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ConvertType.java b/android-jdk6-redkale/src/org/redkale/convert/ConvertType.java new file mode 100644 index 000000000..e079007d6 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ConvertType.java @@ -0,0 +1,28 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +/** + * + * @author zhangjx + */ +public enum ConvertType { + + JSON(1), + BSON(2), + ALL(127); + + private final int value; + + private ConvertType(int v) { + this.value = v; + } + + public boolean contains(ConvertType type) { + if (type == null) return false; + return this.value >= type.value && (this.value & type.value) > 0; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/DeMember.java b/android-jdk6-redkale/src/org/redkale/convert/DeMember.java new file mode 100644 index 000000000..75de5e173 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/DeMember.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import org.redkale.util.Attribute; + +/** + * + * @author zhangjx + * @param + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class DeMember implements Comparable> { + + protected final Attribute attribute; + + protected Decodeable decoder; + + public DeMember(final Attribute attribute) { + this.attribute = attribute; + } + + public DeMember(Attribute attribute, Decodeable decoder) { + this(attribute); + this.decoder = decoder; + } + + public final void read(R in, T obj) { + this.attribute.set(obj, decoder.convertFrom(in)); + } + + public Attribute getAttribute() { + return this.attribute; + } + + @Override + public final int compareTo(DeMember o) { + if (o == null) return 1; + return this.attribute.field().compareTo(o.attribute.field()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof DeMember)) return false; + DeMember other = (DeMember) obj; + return compareTo(other) == 0; + } + + @Override + public int hashCode() { + return this.attribute.field().hashCode(); + } + + @Override + public String toString() { + return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + decoder + '}'; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/Decodeable.java b/android-jdk6-redkale/src/org/redkale/convert/Decodeable.java new file mode 100644 index 000000000..a3c02cec1 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/Decodeable.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.Type; + +/** + * + * @author zhangjx + * @param + * @param + */ +public interface Decodeable { + + public T convertFrom(final R in); + + /** + * 泛型映射接口 + * + * @return + */ + public Type getType(); + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/EnMember.java b/android-jdk6-redkale/src/org/redkale/convert/EnMember.java new file mode 100644 index 000000000..5d2c24b57 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/EnMember.java @@ -0,0 +1,76 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import org.redkale.util.Attribute; + +/** + * + * @author zhangjx + * @param + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class EnMember implements Comparable> { + + private final Attribute attribute; + + final Encodeable encoder; + + private final boolean istring; + + //private final boolean isnumber; + private final boolean isbool; + + public EnMember(Attribute attribute, Encodeable encoder) { + this.attribute = attribute; + this.encoder = encoder; + Class t = attribute.type(); + this.istring = CharSequence.class.isAssignableFrom(t); + this.isbool = t == Boolean.class || t == boolean.class; + //this.isnumber = Number.class.isAssignableFrom(t) || (!this.isbool && t.isPrimitive()); + } + + public boolean write(final W out, final boolean comma, final T obj) { + F value = attribute.get(obj); + if (value == null) return comma; + if (out.isTiny()) { + if (istring) { + if (((CharSequence) value).length() == 0) return comma; + } else if (isbool) { + if (!((Boolean) value)) return comma; + } + } + out.writeField(comma, attribute); + encoder.convertTo(out, value); + return true; + } + + @Override + public final int compareTo(EnMember o) { + if (o == null) return 1; + return this.attribute.field().compareTo(o.attribute.field()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof EnMember)) return false; + EnMember other = (EnMember) obj; + return compareTo(other) == 0; + } + + @Override + public int hashCode() { + return this.attribute.field().hashCode(); + } + + @Override + public String toString() { + return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + encoder + '}'; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/Encodeable.java b/android-jdk6-redkale/src/org/redkale/convert/Encodeable.java new file mode 100644 index 000000000..9d5f1eb29 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/Encodeable.java @@ -0,0 +1,27 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.Type; + +/** + * + * @author zhangjx + * @param + * @param + */ +public interface Encodeable { + + public void convertTo(final W out, T value); + + /** + * 泛型映射接口 + * + * @return + */ + public Type getType(); + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/Factory.java b/android-jdk6-redkale/src/org/redkale/convert/Factory.java new file mode 100644 index 000000000..1e29ec078 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/Factory.java @@ -0,0 +1,386 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.Map; +import java.lang.reflect.*; +import java.math.BigInteger; +import java.net.*; +import static org.redkale.convert.ext.InetAddressSimpledCoder.*; +import org.redkale.util.Creator.Creators; +import java.util.*; +import java.util.concurrent.*; +import java.util.regex.*; +import org.redkale.convert.ext.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + * @param + * @param + */ +@SuppressWarnings("unchecked") +public abstract class Factory { + + private final Factory parent; + + protected Convert convert; + + protected boolean tiny; + + private final Encodeable anyEncoder = new AnyEncoder(this); + + //----------------------------------------------------------------------------------- + private final HashedMap creators = new HashedMap(); + + private final Map entitys = new ConcurrentHashMap(); + + private final HashedMap> decoders = new HashedMap(); + + private final HashedMap> encoders = new HashedMap(); + + private final HashMap columnEntrys = new HashMap(); + + private final Set skipIgnores = new HashSet(); + + private boolean skipAllIgnore = false; + + protected Factory(Factory parent, boolean tiny) { + this.tiny = tiny; + this.parent = parent; + if (parent == null) { + //--------------------------------------------------------- + this.register(boolean.class, BoolSimpledCoder.instance); + this.register(Boolean.class, BoolSimpledCoder.instance); + + this.register(byte.class, ByteSimpledCoder.instance); + this.register(Byte.class, ByteSimpledCoder.instance); + + this.register(short.class, ShortSimpledCoder.instance); + this.register(Short.class, ShortSimpledCoder.instance); + + this.register(char.class, CharSimpledCoder.instance); + this.register(Character.class, CharSimpledCoder.instance); + + this.register(int.class, IntSimpledCoder.instance); + this.register(Integer.class, IntSimpledCoder.instance); + + this.register(long.class, LongSimpledCoder.instance); + this.register(Long.class, LongSimpledCoder.instance); + + this.register(float.class, FloatSimpledCoder.instance); + this.register(Float.class, FloatSimpledCoder.instance); + + this.register(double.class, DoubleSimpledCoder.instance); + this.register(Double.class, DoubleSimpledCoder.instance); + + this.register(Number.class, NumberSimpledCoder.instance); + this.register(String.class, StringSimpledCoder.instance); + this.register(java.util.Date.class, DateSimpledCoder.instance); + this.register(BigInteger.class, BigIntegerSimpledCoder.instance); + this.register(InetAddress.class, InetAddressSimpledCoder.instance); + this.register(DLong.class, DLongSimpledCoder.instance); + this.register(Class.class, TypeSimpledCoder.instance); + this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance); + this.register(Pattern.class, PatternSimpledCoder.instance); + //--------------------------------------------------------- + this.register(boolean[].class, BoolArraySimpledCoder.instance); + this.register(byte[].class, ByteArraySimpledCoder.instance); + this.register(short[].class, ShortArraySimpledCoder.instance); + this.register(char[].class, CharArraySimpledCoder.instance); + this.register(int[].class, IntArraySimpledCoder.instance); + this.register(long[].class, LongArraySimpledCoder.instance); + this.register(float[].class, FloatArraySimpledCoder.instance); + this.register(double[].class, DoubleArraySimpledCoder.instance); + this.register(String[].class, StringArraySimpledCoder.instance); + //--------------------------------------------------------- + } + } + + public Factory parent() { + return this.parent; + } + + public abstract ConvertType getConvertType(); + + public abstract boolean isReversible(); + + public abstract Factory createChild(); + + public abstract Factory createChild(boolean tiny); + + public Convert getConvert() { + return convert; + } + + public void setTiny(boolean tiny) { + this.tiny = tiny; + } + + public ConvertColumnEntry findRef(AccessibleObject field) { + if (field == null) return null; + ConvertColumnEntry en = this.columnEntrys.get(field); + if (en != null) return en; + final ConvertType ct = this.getConvertType(); + for (ConvertColumn ref : field.getAnnotationsByType(ConvertColumn.class)) { + if (ref.type().contains(ct)) { + ConvertColumnEntry entry = new ConvertColumnEntry(ref); + if (skipAllIgnore) { + entry.setIgnore(false); + return entry; + } + if (skipIgnores.isEmpty()) return entry; + if (skipIgnores.contains(((Member) field).getDeclaringClass())) entry.setIgnore(false); + return entry; + } + } + return null; + } + + final String getEntity(Class clazz) { + ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class); + if (ce != null && findEntity(ce.value()) == null) entitys.put(ce.value(), clazz); + return ce == null ? clazz.getName() : ce.value(); + } + + private Class findEntity(String name) { + Class clazz = entitys.get(name); + return parent == null ? clazz : parent.findEntity(name); + } + + final Class getEntity(String name) { + Class clazz = findEntity(name); + try { + return clazz == null ? Class.forName(name) : clazz; + } catch (Exception ex) { + throw new ConvertException("convert entity is " + name, ex); + } + } + + /** + * 使所有类的所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false + *

+ * @param skipIgnore + */ + public final void registerSkipAllIgnore(final boolean skipIgnore) { + this.skipAllIgnore = skipIgnore; + } + + /** + * 使该类所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false + *

+ * @param type + */ + public final void registerSkipIgnore(final Class type) { + skipIgnores.add(type); + } + + public final void register(final Class type, boolean ignore, String... columns) { + for (String column : columns) { + register(type, column, new ConvertColumnEntry(column, ignore)); + } + } + + public final boolean register(final Class type, String column, ConvertColumnEntry entry) { + if (type == null || column == null || entry == null) return false; + try { + final Field field = type.getDeclaredField(column); + String get = "get"; + if (field.getType() == boolean.class || field.getType() == Boolean.class) get = "is"; + char[] cols = column.toCharArray(); + cols[0] = Character.toUpperCase(cols[0]); + String col2 = new String(cols); + try { + register(type.getMethod(get + col2), entry); + } catch (Exception ex) { + } + try { + register(type.getMethod("set" + col2, field.getType()), entry); + } catch (Exception ex) { + } + return register(field, entry); + } catch (Exception e) { + return false; + } + } + + public final boolean register(final AccessibleObject field, final ConvertColumnEntry entry) { + if (field == null || entry == null) return false; + this.columnEntrys.put(field, entry); + return true; + } + + public final void register(final Class clazz, final Creator creator) { + creators.put(clazz, creator); + } + + public final Creator findCreator(Class type) { + Creator creator = creators.get(type); + if (creator != null) return creator; + return this.parent == null ? null : this.parent.findCreator(type); + } + + public final Creator loadCreator(Class type) { + Creator result = findCreator(type); + if (result == null) { + result = Creators.create(type); + creators.put(type, result); + } + return result; + } + + //---------------------------------------------------------------------- + public final Encodeable getAnyEncoder() { + return (Encodeable) anyEncoder; + } + + public final void register(final Type clazz, final SimpledCoder coder) { + decoders.put(clazz, coder); + encoders.put(clazz, coder); + } + + public final void register(final Type clazz, final Decodeable decoder) { + decoders.put(clazz, decoder); + } + + public final void register(final Type clazz, final Encodeable printer) { + encoders.put(clazz, printer); + } + + public final Decodeable findDecoder(final Type type) { + Decodeable rs = (Decodeable) decoders.get(type); + if (rs != null) return rs; + return this.parent == null ? null : this.parent.findDecoder(type); + } + + public final Encodeable findEncoder(final Type type) { + Encodeable rs = (Encodeable) encoders.get(type); + if (rs != null) return rs; + return this.parent == null ? null : this.parent.findEncoder(type); + } + + public final Decodeable loadDecoder(final Type type) { + Decodeable decoder = findDecoder(type); + if (decoder != null) return decoder; + if (type instanceof GenericArrayType) return new ArrayDecoder(this, type); + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + decoder = findDecoder(clazz); + if (decoder != null) return decoder; + return createDecoder(type, clazz); + } + + public final Decodeable createDecoder(final Type type) { + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + return createDecoder(type, clazz); + } + + private Decodeable createDecoder(final Type type, final Class clazz) { + Decodeable decoder = null; + ObjectDecoder od = null; + if (clazz.isEnum()) { + decoder = new EnumSimpledCoder(clazz); + } else if (clazz.isArray()) { + decoder = new ArrayDecoder(this, type); + } else if (Collection.class.isAssignableFrom(clazz)) { + decoder = new CollectionDecoder(this, type); + } else if (Map.class.isAssignableFrom(clazz)) { + decoder = new MapDecoder(this, type); + } else if (clazz == Object.class) { + od = new ObjectDecoder(type); + decoder = od; + } else if (!clazz.getName().startsWith("java.")) { + od = new ObjectDecoder(type); + decoder = od; + } + if (decoder == null) throw new ConvertException("not support the type (" + type + ")"); + register(type, decoder); + if (od != null) od.init(this); + return decoder; + } + + public final Encodeable loadEncoder(final Type type) { + Encodeable encoder = findEncoder(type); + if (encoder != null) return encoder; + if (type instanceof GenericArrayType) return new ArrayEncoder(this, type); + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + Type t = Object.class; + if (tv.getBounds().length == 1) { + t = tv.getBounds()[0]; + } + if (!(t instanceof Class)) t = Object.class; + clazz = (Class) t; + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + encoder = findEncoder(clazz); + if (encoder != null) return encoder; + return createEncoder(type, clazz); + } + + public final Encodeable createEncoder(final Type type) { + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + return createEncoder(type, clazz); + } + + private Encodeable createEncoder(final Type type, final Class clazz) { + Encodeable encoder = null; + ObjectEncoder oe = null; + if (clazz.isEnum()) { + encoder = new EnumSimpledCoder(clazz); + } else if (clazz.isArray()) { + encoder = new ArrayEncoder(this, type); + } else if (Collection.class.isAssignableFrom(clazz)) { + encoder = new CollectionEncoder(this, type); + } else if (Map.class.isAssignableFrom(clazz)) { + encoder = new MapEncoder(this, type); + } else if (clazz == Object.class) { + return (Encodeable) this.anyEncoder; + } else if (!clazz.getName().startsWith("java.")) { + oe = new ObjectEncoder(type); + encoder = oe; + } + if (encoder == null) throw new ConvertException("not support the type (" + type + ")"); + register(type, encoder); + if (oe != null) oe.init(this); + return encoder; + + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/HashedMap.java b/android-jdk6-redkale/src/org/redkale/convert/HashedMap.java new file mode 100644 index 000000000..f30dd9385 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/HashedMap.java @@ -0,0 +1,70 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.*; + +/** + * 只增不减的伪Map类 + * + * @author zhangjx + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class HashedMap { + + protected final transient Entry[] table; + + public HashedMap() { + this(128); + } + + public HashedMap(int initCapacity) { + this.table = new Entry[Math.max(initCapacity, 16)]; + } + + public final V get(final K key) { + final K k = key; + final Entry[] data = this.table; + Entry entry = data[k.hashCode() & (data.length - 1)]; + while (entry != null) { + if (k == entry.key) return entry.value; + entry = entry.next; + } + return null; + } + + public final V put(K key, V value) { + final K k = key; + final Entry[] data = this.table; + final int index = k.hashCode() & (data.length - 1); + Entry entry = data[index]; + while (entry != null) { + if (k == entry.key) { + entry.value = value; + return entry.value; + } + entry = entry.next; + } + data[index] = new Entry(key, value, data[index]); + return null; + } + + protected static final class Entry { + + protected V value; + + protected final K key; + + protected final Entry next; + + protected Entry(K key, V value, Entry next) { + this.key = key; + this.value = value; + this.next = next; + } + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/MapDecoder.java b/android-jdk6-redkale/src/org/redkale/convert/MapDecoder.java new file mode 100644 index 000000000..8dc6bd6e6 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/MapDecoder.java @@ -0,0 +1,78 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import org.redkale.util.Creator; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; + +/** + * + * @author zhangjx + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class MapDecoder implements Decodeable> { + + private final Type type; + + private final Type keyType; + + private final Type valueType; + + protected Creator> creator; + + private final Decodeable keyDecoder; + + private final Decodeable valueDecoder; + + public MapDecoder(final Factory factory, final Type type) { + this.type = type; + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.keyType = pt.getActualTypeArguments()[0]; + this.valueType = pt.getActualTypeArguments()[1]; + this.creator = factory.loadCreator((Class) pt.getRawType()); + factory.register(type, this); + this.keyDecoder = factory.loadDecoder(this.keyType); + this.valueDecoder = factory.loadDecoder(this.valueType); + } else { + throw new ConvertException("mapdecoder not support the type (" + type + ")"); + } + } + + @Override + public Map convertFrom(Reader in) { + final int len = in.readMapB(); + if (len == Reader.SIGN_NULL) return null; + final Map result = this.creator.create(); + if (len == Reader.SIGN_NOLENGTH) { + while (in.hasNext()) { + K key = keyDecoder.convertFrom(in); + in.skipBlank(); + V value = valueDecoder.convertFrom(in); + result.put(key, value); + } + } else { + for (int i = 0; i < len; i++) { + K key = keyDecoder.convertFrom(in); + in.skipBlank(); + V value = valueDecoder.convertFrom(in); + result.put(key, value); + } + } + in.readMapE(); + return result; + } + + @Override + public Type getType() { + return this.type; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/MapEncoder.java b/android-jdk6-redkale/src/org/redkale/convert/MapEncoder.java new file mode 100644 index 000000000..c8ba007e4 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/MapEncoder.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; + +/** + * + * @author zhangjx + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class MapEncoder implements Encodeable> { + + private final Type type; + + private final Encodeable keyencoder; + + private final Encodeable valencoder; + + public MapEncoder(final Factory factory, final Type type) { + this.type = type; + if (type instanceof ParameterizedType) { + final Type[] pt = ((ParameterizedType) type).getActualTypeArguments(); + this.keyencoder = factory.loadEncoder(pt[0]); + this.valencoder = factory.loadEncoder(pt[1]); + } else { + this.keyencoder = factory.getAnyEncoder(); + this.valencoder = factory.getAnyEncoder(); + } + } + + @Override + public void convertTo(Writer out, Map value) { + final Map values = value; + if (values == null) { + out.writeNull(); + return; + } + out.writeMapB(values.size()); + boolean first = true; + for (Map.Entry en : values.entrySet()) { + if (!first) out.writeArrayMark(); + this.keyencoder.convertTo(out, en.getKey()); + out.writeMapMark(); + this.valencoder.convertTo(out, en.getValue()); + if (first) first = false; + } + out.writeMapE(); + } + + @Override + public Type getType() { + return type; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ObjectDecoder.java b/android-jdk6-redkale/src/org/redkale/convert/ObjectDecoder.java new file mode 100644 index 000000000..ebe16a2e0 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ObjectDecoder.java @@ -0,0 +1,157 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import static org.redkale.convert.ObjectEncoder.TYPEZERO; +import org.redkale.util.Creator; +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author zhangjx + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class ObjectDecoder implements Decodeable { + + protected final Type type; + + protected final Class typeClass; + + protected Creator creator; + + protected DeMember[] members; + + protected Factory factory; + + private boolean inited = false; + + private final Object lock = new Object(); + + protected ObjectDecoder(Type type) { + this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type; + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.typeClass = (Class) pt.getRawType(); + } else { + this.typeClass = (Class) type; + } + this.members = new DeMember[0]; + } + + public void init(final Factory factory) { + this.factory = factory; + try { + if (type == Object.class) return; + + Class clazz = null; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (!(type instanceof Class)) { + throw new ConvertException("[" + type + "] is no a class"); + } else { + clazz = (Class) type; + } + final Type[] virGenericTypes = this.typeClass.getTypeParameters(); + final Type[] realGenericTypes = (type instanceof ParameterizedType) ? ((ParameterizedType) type).getActualTypeArguments() : TYPEZERO; + this.creator = factory.loadCreator(clazz); + final Set list = new HashSet(); + try { + ConvertColumnEntry ref; + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + ref = factory.findRef(field); + if (ref != null && ref.ignore()) continue; + Type t = ObjectEncoder.makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); + list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t))); + } + final boolean reversible = factory.isReversible(); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getName().length() < 4) continue; + if (!method.getName().startsWith("set")) continue; + if (method.getParameterTypes().length != 1) continue; + if (method.getReturnType() != void.class) continue; + if (reversible) { + boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; + try { + clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); + } catch (Exception e) { + continue; + } + } + ref = factory.findRef(method); + if (ref != null && ref.ignore()) continue; + Type t = ObjectEncoder.makeGenericType(method.getGenericParameterTypes()[0], virGenericTypes, realGenericTypes); + list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t))); + } + this.members = list.toArray(new DeMember[list.size()]); + Arrays.sort(this.members); + } catch (Exception ex) { + throw new ConvertException(ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + /** + * 对象格式: [0x1][short字段个数][字段名][字段值]...[0x2] + * + * @param in + * @return + */ + @Override + public final T convertFrom(final R in) { + final String clazz = in.readClassName(); + if (clazz != null && !clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntity(clazz)).convertFrom(in); + if (in.readObjectB() == Reader.SIGN_NULL) return null; + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + final T result = this.creator.create(); + final AtomicInteger index = new AtomicInteger(); + while (in.hasNext()) { + DeMember member = in.readField(index, members); + in.skipBlank(); + if (member == null) { + in.skipValue(); //跳过该属性的值 + } else { + member.read(in, result); + } + index.incrementAndGet(); + } + in.readObjectE(); + return result; + } + + @Override + public final Type getType() { + return this.type; + } + + @Override + public String toString() { + return "ObjectDecoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ObjectEncoder.java b/android-jdk6-redkale/src/org/redkale/convert/ObjectEncoder.java new file mode 100644 index 000000000..897fb8051 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ObjectEncoder.java @@ -0,0 +1,234 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import org.redkale.util.Attribute; +import org.redkale.util.Attribute.Attributes; +import java.lang.reflect.*; +import java.util.*; + +/** + * + * @author zhangjx + * @param + * @param + */ +@SuppressWarnings("unchecked") +public final class ObjectEncoder implements Encodeable { + + static final Type[] TYPEZERO = new Type[0]; + + protected final Type type; + + protected final Class typeClass; + + protected EnMember[] members; + + protected Factory factory; + + private boolean inited = false; + + private final Object lock = new Object(); + + protected ObjectEncoder(Type type) { + this.type = type; + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.typeClass = (Class) pt.getRawType(); + } else { + this.typeClass = (Class) type; + } + this.members = new EnMember[0]; + } + + static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) { + if (type instanceof Class) { + return type; + } else if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + Type[] paramTypes = pt.getActualTypeArguments(); + final Type[] newTypes = new Type[paramTypes.length]; + int count = 0; + for (int i = 0; i < newTypes.length; i++) { + newTypes[i] = makeGenericType(paramTypes[i], virGenericTypes, realGenericTypes); + if (paramTypes[i] == newTypes[i]) count++; + } + if (count == paramTypes.length) return pt; + return new ParameterizedType() { + + @Override + public Type[] getActualTypeArguments() { + return newTypes; + } + + @Override + public Type getRawType() { + return pt.getRawType(); + } + + @Override + public Type getOwnerType() { + return pt.getOwnerType(); + } + + }; + } + if (realGenericTypes == null) return type; + if (type instanceof WildcardType) { + final WildcardType wt = (WildcardType) type; + for (Type f : wt.getUpperBounds()) { + for (int i = 0; i < virGenericTypes.length; i++) { + if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i]; + } + } + } else if (type instanceof TypeVariable) { + for (int i = 0; i < virGenericTypes.length; i++) { + if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i]; + } + } + return type; + } + + private static String readGetSetFieldName(Method method) { + if (method == null) return null; + String fname = method.getName(); + if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; + fname = fname.substring(fname.startsWith("is") ? 2 : 3); + if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { + fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); + } else if (fname.length() == 1) { + fname = "" + Character.toLowerCase(fname.charAt(0)); + } + return fname; + } + + static Attribute createAttribute(final Factory factory, Class clazz, final Field field, final Method getter, final Method setter) { + String fieldalias = null; + if (field != null) { // public field + ConvertColumnEntry ref = factory.findRef(field); + fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name(); + } else if (getter != null) { + ConvertColumnEntry ref = factory.findRef(getter); + String mfieldname = readGetSetFieldName(getter); + if (ref == null) { + try { + ref = factory.findRef(clazz.getDeclaredField(mfieldname)); + } catch (Exception e) { + } + } + fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); + } else { // setter != null + ConvertColumnEntry ref = factory.findRef(setter); + String mfieldname = readGetSetFieldName(setter); + if (ref == null) { + try { + ref = factory.findRef(clazz.getDeclaredField(mfieldname)); + } catch (Exception e) { + } + } + fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); + } + return Attributes.create(clazz, fieldalias, field, getter, setter); + } + + public void init(final Factory factory) { + this.factory = factory; + try { + if (type == Object.class) return; + //if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class"); + final Class clazz = this.typeClass; + final Set list = new HashSet(); + final Type[] virGenericTypes = this.typeClass.getTypeParameters(); + final Type[] realGenericTypes = (type instanceof ParameterizedType) ? ((ParameterizedType) type).getActualTypeArguments() : null; + if (realGenericTypes != null) { + // println(type + "," + Arrays.toString(virGenericTypes) + ", " + Arrays.toString(realGenericTypes)); + } + try { + ConvertColumnEntry ref; + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + ref = factory.findRef(field); + if (ref != null && ref.ignore()) continue; + Type t = makeGenericType(field.getGenericType(), virGenericTypes, realGenericTypes); + list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t))); + } + final boolean reversible = factory.isReversible(); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getName().length() < 3) continue; + if (method.getName().equals("getClass")) continue; + if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; + if (method.getParameterTypes().length != 0) continue; + if (method.getReturnType() == void.class) continue; + if (reversible) { + boolean is = method.getName().startsWith("is"); + try { + clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); + } catch (Exception e) { + continue; + } + } + ref = factory.findRef(method); + if (ref != null && ref.ignore()) continue; + Type t = makeGenericType(method.getGenericReturnType(), virGenericTypes, realGenericTypes); + list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t))); + } + this.members = list.toArray(new EnMember[list.size()]); + Arrays.sort(this.members); + + } catch (Exception ex) { + throw new ConvertException(ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public final void convertTo(W out, T value) { + if (value == null) { + out.wirteClassName(null); + out.writeNull(); + return; + } + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + if (value != null && value.getClass() != this.typeClass) { + final Class clz = value.getClass(); + out.wirteClassName(factory.getEntity(clz)); + factory.loadEncoder(clz).convertTo(out, value); + return; + } + out.writeObjectB(members.length, value); + boolean comma = false; + for (EnMember member : members) { + comma = member.write(out, comma, value); + } + out.writeObjectE(value); + } + + @Override + public final Type getType() { + return this.type; + } + + @Override + public String toString() { + return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/Reader.java b/android-jdk6-redkale/src/org/redkale/convert/Reader.java new file mode 100644 index 000000000..743474ac4 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/Reader.java @@ -0,0 +1,112 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author zhangjx + */ +public interface Reader { + + public static final short SIGN_NULL = -1; + + public static final short SIGN_NOLENGTH = -2; + + /** + * 是否还存在下个元素或字段 + * + * @return + */ + public boolean hasNext(); + + /** + * 跳过值(不包含值前面的字段) + */ + public void skipValue(); + + /** + * /跳过字段与值之间的多余内容, json就是跳过:符, map跳过: + */ + public void skipBlank(); + + /** + * 读取对象的开头 返回字段数 + * + * @return + */ + public int readObjectB(); + + /** + * 读取对象的尾端 + * + */ + public void readObjectE(); + + /** + * 读取数组的开头并返回数组的长度 + * + * @return + */ + public int readArrayB(); + + /** + * 读取数组的尾端 + * + */ + public void readArrayE(); + + /** + * 读取map的开头并返回map的size + * + * @return + */ + public int readMapB(); + + /** + * 读取数组的尾端 + * + */ + public void readMapE(); + + /** + * 根据字段读取字段对应的DeMember + * + * @param index + * @param members + * @return + */ + public DeMember readField(final AtomicInteger index, final DeMember[] members); + + public boolean readBoolean(); + + public byte readByte(); + + public char readChar(); + + public short readShort(); + + public int readInt(); + + public long readLong(); + + public float readFloat(); + + public double readDouble(); + + /** + * 读取无转义字符长度不超过255的字符串, 例如枚举值、字段名、类名字符串等 + * + * @return + */ + public String readSmallString(); + + public String readClassName(); + + public String readString(); + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/SimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/SimpledCoder.java new file mode 100644 index 000000000..fef1ec2cc --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/SimpledCoder.java @@ -0,0 +1,42 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * + * @author zhangjx + * @param + * @param + * @param + */ +public abstract class SimpledCoder implements Decodeable, Encodeable { + + private Type type; + + @Override + public abstract void convertTo(final W out, final T value); + + @Override + public abstract T convertFrom(final R in); + + @Override + @SuppressWarnings("unchecked") + public Class getType() { + if (type == null) { + Type[] ts = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments(); + type = ts[ts.length - 1]; + } + return (Class) type; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/Writer.java b/android-jdk6-redkale/src/org/redkale/convert/Writer.java new file mode 100644 index 000000000..4da8710b8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/Writer.java @@ -0,0 +1,120 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +import org.redkale.util.Attribute; + +/** + * + * @author zhangjx + */ +public interface Writer { + + /** + * 当tiny=true时, 字符串为空、boolean为false的字段值都会被跳过, 不会输出。 + *

+ * @return + */ + public boolean isTiny(); + + /** + * 输出null值 + */ + public void writeNull(); + + /** + * + * @param clazz + */ + public void wirteClassName(String clazz); + + /** + * 输出一个对象前的操作 + * + * @param fieldCount 字段个数 + * + * @param obj + */ + public void writeObjectB(int fieldCount, Object obj); + + /** + * 输出一个对象后的操作 + * + * @param obj + */ + public void writeObjectE(Object obj); + + /** + * 输出一个数组前的操作 + * + * @param size 数组长度 + */ + public void writeArrayB(int size); + + /** + * 输出数组元素间的间隔符 + * + */ + public void writeArrayMark(); + + /** + * 输出一个数组后的操作 + * + */ + public void writeArrayE(); + + /** + * 输出一个Map前的操作 + * + * @param size map大小 + */ + public void writeMapB(int size); + + /** + * 输出一个Map中key与value间的间隔符 + * + */ + public void writeMapMark(); + + /** + * 输出一个Map后的操作 + * + */ + public void writeMapE(); + + /** + * 输出一个字段 + * + * @param comma 是否非第一个字段 + * @param attribute + */ + public void writeField(boolean comma, Attribute attribute); + + public void writeBoolean(boolean value); + + public void writeByte(byte value); + + public void writeChar(char value); + + public void writeShort(short value); + + public void writeInt(int value); + + public void writeLong(long value); + + public void writeFloat(float value); + + public void writeDouble(double value); + + /** + * 写入无转义字符长度不超过255的字符串, 例如枚举值、字段名、类名字符串等 * + * + * @param value + */ + public void writeSmallString(String value); + + public void writeString(String value); +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/bson/BsonByteBufferWriter.java b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonByteBufferWriter.java new file mode 100644 index 000000000..ba724bbc1 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonByteBufferWriter.java @@ -0,0 +1,134 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.bson; + +import java.nio.*; +import java.util.function.*; + +/** + * + * @author zhangjx + */ +public final class BsonByteBufferWriter extends BsonWriter { + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int index; + + protected BsonByteBufferWriter(Supplier supplier) { + super((byte[]) null); + this.supplier = supplier; + } + + @Override + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) buf.flip(); + } + return this.buffers; + } + + @Override + public byte[] toArray() { + if (buffers == null) return new byte[0]; + int pos = 0; + byte[] bytes = new byte[this.count]; + for (ByteBuffer buf : toBuffers()) { + int r = buf.remaining(); + buf.get(bytes, pos, r); + buf.flip(); + pos += r; + } + return bytes; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + @Override + public BsonByteBufferWriter setTiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + protected int expand(final int byteLength) { + if (this.buffers == null) { + this.index = 0; + this.buffers = new ByteBuffer[]{supplier.get()}; + } + ByteBuffer buffer = this.buffers[index]; + if (!buffer.hasRemaining()) { + buffer.flip(); + buffer = supplier.get(); + ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; + System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length); + bufs[this.buffers.length] = buffer; + this.buffers = bufs; + this.index++; + } + int len = buffer.remaining(); + int size = 0; + while (len < byteLength) { + buffer = supplier.get(); + ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; + System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length); + bufs[this.buffers.length] = buffer; + this.buffers = bufs; + len += buffer.remaining(); + size++; + } + return size; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { + if (expand(len) == 0) { + this.buffers[index].put(chs, start, len); + } else { + ByteBuffer buffer = this.buffers[index]; + final int end = start + len; + int remain = len; //还剩多少没有写 + while (remain > 0) { + final int br = buffer.remaining(); + if (remain > br) { //一个buffer写不完 + buffer.put(chs, end - remain, br); + buffer = nextByteBuffer(); + remain -= br; + } else { + buffer.put(chs, end - remain, remain); + remain = 0; + } + } + } + this.count += len; + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + @Override + public void writeTo(final byte ch) { + expand(1); + this.buffers[index].put(ch); + count++; + } + + @Override + protected boolean recycle() { + this.index = 0; + this.buffers = null; + return false; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/bson/BsonConvert.java b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonConvert.java new file mode 100644 index 000000000..38618f675 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonConvert.java @@ -0,0 +1,155 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.bson; + +import java.lang.reflect.*; +import java.nio.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * BSON协议格式: + * 1). 基本数据类型: 直接转换成byte[] + * 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 + * 3). String: length(4 bytes) + byte[](utf8); + * 4). 数组: length(4 bytes) + byte[]... + * 5). Object: + * 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值) + * 2. 空字符串(SmallString) + * 3. SIGN_OBJECTB 标记位,值固定为0xBB (short) + * 4. 循环字段值: + * 4.1 SIGN_HASNEXT 标记位,值固定为1 (byte) + * 4.2 字段类型; 1-9为基本类型&字符串; 101-109为基本类型&字符串的数组; 127为Object + * 4.3 字段名 (SmallString) + * 4.4 字段的值Object + * 5. SIGN_NONEXT 标记位,值固定为0 (byte) + * 6. SIGN_OBJECTE 标记位,值固定为0xEE (short) + * + * @author zhangjx + */ +public final class BsonConvert extends Convert { + + private static final ObjectPool readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16)); + + private static final ObjectPool writerPool = BsonWriter.createPool(Integer.getInteger("convert.bson.pool.size", 16)); + + private final boolean tiny; + + protected BsonConvert(Factory factory, boolean tiny) { + super(factory); + this.tiny = tiny; + } + + public BsonByteBufferWriter pollBsonWriter(final Supplier supplier) { + return new BsonByteBufferWriter(supplier).setTiny(tiny); + } + + public BsonWriter pollBsonWriter() { + return writerPool.get().setTiny(tiny); + } + + public void offerBsonWriter(BsonWriter out) { + if (out != null) writerPool.offer(out); + } + + public BsonReader pollBsonReader() { + return readerPool.get(); + } + + public void offerBsonReader(BsonReader in) { + if (in != null) readerPool.offer(in); + } + + public T convertFrom(final Type type, final byte[] bytes) { + if (bytes == null) return null; + return convertFrom(type, bytes, 0, bytes.length); + } + + public T convertFrom(final Type type, final byte[] bytes, int start, int len) { + if (type == null) return null; + final BsonReader in = readerPool.get(); + in.setBytes(bytes, start, len); + @SuppressWarnings("unchecked") + T rs = (T) factory.loadDecoder(type).convertFrom(in); + readerPool.offer(in); + return rs; + } + + public T convertFrom(final BsonReader in, final Type type) { + if (type == null) return null; + @SuppressWarnings("unchecked") + T rs = (T) factory.loadDecoder(type).convertFrom(in); + return rs; + } + + public byte[] convertTo(final Type type, Object value) { + if (type == null) return null; + final BsonWriter out = writerPool.get().setTiny(tiny); + factory.loadEncoder(type).convertTo(out, value); + byte[] result = out.toArray(); + writerPool.offer(out); + return result; + } + + public void convertTo(final BsonWriter out, final Type type, Object value) { + if (type == null) return; + factory.loadEncoder(type).convertTo(out, value); + } + + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, Object value) { + if (supplier == null || type == null) return null; + BsonByteBufferWriter out = new BsonByteBufferWriter(supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(type).convertTo(out, value); + } + return out.toBuffers(); + } + + public ByteBuffer[] convertTo(final Supplier supplier, Object value) { + if (supplier == null) return null; + BsonByteBufferWriter out = new BsonByteBufferWriter(supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + return out.toBuffers(); + } + + public void convertTo(final BsonWriter out, Object value) { + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + } + + public byte[] convertTo(Object value) { + if (value == null) { + final BsonWriter out = writerPool.get().setTiny(tiny); + out.writeNull(); + byte[] result = out.toArray(); + writerPool.offer(out); + return result; + } + return convertTo(value.getClass(), value); + } + + public BsonWriter convertToWriter(final Type type, Object value) { + if (type == null) return null; + final BsonWriter out = writerPool.get().setTiny(tiny); + factory.loadEncoder(type).convertTo(out, value); + return out; + } + + public BsonWriter convertToWriter(Object value) { + if (value == null) return null; + return convertToWriter(value.getClass(), value); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/bson/BsonFactory.java b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonFactory.java new file mode 100644 index 000000000..7b2dba377 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonFactory.java @@ -0,0 +1,62 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.bson; + +import java.io.Serializable; +import org.redkale.convert.*; + +/** + * + * @author zhangjx + */ +public final class BsonFactory extends Factory { + + private static final BsonFactory instance = new BsonFactory(null, Boolean.getBoolean("convert.bson.tiny")); + + static final Decodeable objectDecoder = instance.loadDecoder(Object.class); + + static final Encodeable objectEncoder = instance.loadEncoder(Object.class); + + static { + instance.register(Serializable.class, objectDecoder); + instance.register(Serializable.class, objectEncoder); + } + + private BsonFactory(BsonFactory parent, boolean tiny) { + super(parent, tiny); + } + + public static BsonFactory root() { + return instance; + } + + @Override + public final BsonConvert getConvert() { + if (convert == null) convert = new BsonConvert(this, tiny); + return (BsonConvert) convert; + } + + @Override + public BsonFactory createChild() { + return new BsonFactory(this, this.tiny); + } + + @Override + public BsonFactory createChild(boolean tiny) { + return new BsonFactory(this, tiny); + } + + @Override + public ConvertType getConvertType() { + return ConvertType.BSON; + } + + @Override + public boolean isReversible() { + return true; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/bson/BsonReader.java b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonReader.java new file mode 100644 index 000000000..5596e7677 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonReader.java @@ -0,0 +1,323 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.bson; + +import java.util.concurrent.atomic.*; +import java.util.function.*; +import org.redkale.convert.*; +import static org.redkale.convert.Reader.SIGN_NULL; +import org.redkale.convert.ext.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public final class BsonReader implements Reader { + + public static final short SIGN_OBJECTB = (short) 0xBB; + + public static final short SIGN_OBJECTE = (short) 0xEE; + + public static final byte SIGN_HASNEXT = 1; + + public static final byte SIGN_NONEXT = 0; + + public static final byte VERBOSE_NO = 1; + + public static final byte VERBOSE_YES = 2; + + private int position = -1; + + private byte typeval; //字段的类型值 对应 BsonWriter.writeField + + private byte[] content; + + public BsonReader() { + } + + public static ObjectPool createPool(int max) { + return new ObjectPool(max, new Creator() { + + @Override + public BsonReader create(Object... params) { + return new BsonReader(); + } + }, null, new Predicate() { + + @Override + public boolean test(BsonReader t) { + return t.recycle(); + } + }); + } + + public BsonReader(byte[] bytes) { + setBytes(bytes, 0, bytes.length); + } + + public BsonReader(byte[] bytes, int start, int len) { + setBytes(bytes, start, len); + } + + public final void setBytes(byte[] bytes) { + if (bytes == null) { + this.position = 0; + } else { + setBytes(bytes, 0, bytes.length); + } + } + + public final void setBytes(byte[] bytes, int start, int len) { + if (bytes == null) { + this.position = 0; + } else { + this.content = bytes; + this.position = start - 1; + //this.limit = start + len - 1; + } + } + + protected boolean recycle() { + this.position = -1; + this.typeval = 0; + //this.limit = -1; + this.content = null; + return true; + } + + public void close() { + this.recycle(); + } + + /** + * 跳过属性的值 + */ + @Override + public final void skipValue() { + if (typeval == 0) return; + final byte val = this.typeval; + this.typeval = 0; + switch (val) { + case 1: readBoolean(); + break; + case 2: readByte(); + break; + case 3: readShort(); + break; + case 4: readChar(); + break; + case 5: readInt(); + break; + case 6: readLong(); + break; + case 7: readFloat(); + break; + case 8: readDouble(); + break; + case 9: readString(); + break; + case 101: + BoolArraySimpledCoder.instance.convertFrom(this); + break; + case 102: + ByteArraySimpledCoder.instance.convertFrom(this); + break; + case 103: + ShortArraySimpledCoder.instance.convertFrom(this); + break; + case 104: + CharArraySimpledCoder.instance.convertFrom(this); + break; + case 105: + IntArraySimpledCoder.instance.convertFrom(this); + break; + case 106: + LongArraySimpledCoder.instance.convertFrom(this); + break; + case 107: + FloatArraySimpledCoder.instance.convertFrom(this); + break; + case 108: + DoubleArraySimpledCoder.instance.convertFrom(this); + break; + case 109: + StringArraySimpledCoder.instance.convertFrom(this); + break; + case 127: + BsonFactory.objectDecoder.convertFrom(this); + break; + } + } + + /** + * 判断下一个非空白字节是否为{ + * + */ + @Override + public int readObjectB() { + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + if (bt != SIGN_OBJECTB) { + throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB) + + " (position = " + position + ") but '" + this.content[this.position] + "'"); + } + return bt; + } + + @Override + public void readObjectE() { + if (readShort() != SIGN_OBJECTE) { + throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE) + + " (position = " + position + ") but '" + this.content[this.position] + "'"); + } + } + + @Override + public int readMapB() { + return readArrayB(); + } + + @Override + public void readMapE() { + } + + /** + * 判断下一个非空白字节是否为[ + * + * @return + */ + @Override + public int readArrayB() { + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); + } + + @Override + public void readArrayE() { + } + + /** + * 判断下一个非空白字节是否: + */ + @Override + public void skipBlank() { + } + + /** + * 判断对象是否存在下一个属性或者数组是否存在下一个元素 + * + * @return + */ + @Override + public boolean hasNext() { + byte b = readByte(); + if (b == SIGN_HASNEXT) return true; + if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT) + + " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")"); + return false; + } + + @Override + public DeMember readField(final AtomicInteger index, final DeMember[] members) { + final String exceptedfield = readSmallString(); + this.typeval = readByte(); + final int len = members.length; + int v = index.get(); + if (v >= len) { + v = 0; + index.set(0); + } + for (int k = v; k < len; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + index.set(k); + return members[k]; + } + } + for (int k = 0; k < v; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + index.set(k); + return members[k]; + } + } + return null; + } + + //------------------------------------------------------------ + @Override + public boolean readBoolean() { + return content[++this.position] == 1; + } + + @Override + public byte readByte() { + return content[++this.position]; + } + + @Override + public char readChar() { + return (char) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position])); + } + + @Override + public short readShort() { + return (short) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position])); + } + + @Override + public int readInt() { + return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16) + | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); + } + + @Override + public long readLong() { + return ((((long) content[++this.position] & 0xff) << 56) + | (((long) content[++this.position] & 0xff) << 48) + | (((long) content[++this.position] & 0xff) << 40) + | (((long) content[++this.position] & 0xff) << 32) + | (((long) content[++this.position] & 0xff) << 24) + | (((long) content[++this.position] & 0xff) << 16) + | (((long) content[++this.position] & 0xff) << 8) + | (((long) content[++this.position] & 0xff))); + } + + @Override + public float readFloat() { + return Float.intBitsToFloat(readInt()); + } + + @Override + public double readDouble() { + return Double.longBitsToDouble(readLong()); + } + + @Override + public String readClassName() { + return readSmallString(); + } + + @Override + public String readSmallString() { + int len = 0xff & readByte(); + if (len == 0) return ""; + String value = new String(content, ++this.position, len); + this.position += len - 1; + return value; + } + + @Override + public String readString() { + int len = readInt(); + if (len == SIGN_NULL) return null; + if (len == 0) return ""; + String value = new String(Utility.decodeUTF8(content, ++this.position, len)); + this.position += len - 1; + return value; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/bson/BsonSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonSimpledCoder.java new file mode 100644 index 000000000..2a4e5950f --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonSimpledCoder.java @@ -0,0 +1,17 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.bson; + +import org.redkale.convert.SimpledCoder; + +/** + * + * @author zhangjx + * @param + */ +public abstract class BsonSimpledCoder extends SimpledCoder { + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/bson/BsonWriter.java b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonWriter.java new file mode 100644 index 000000000..c10e2f204 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/bson/BsonWriter.java @@ -0,0 +1,297 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.bson; + +import java.nio.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public class BsonWriter implements Writer { + + private static final int defaultSize = Integer.getInteger("convert.bson.writer.buffer.defsize", 1024); + + private byte[] content; + + protected int count; + + protected boolean tiny; + + public static ObjectPool createPool(int max) { + return new ObjectPool(max, new Creator() { + + @Override + public BsonWriter create(Object... params) { + return new BsonWriter(); + } + }, null, new Predicate() { + + @Override + public boolean test(BsonWriter t) { + return t.recycle(); + } + }); + } + + public byte[] toArray() { + if (count == content.length) return content; + byte[] newdata = new byte[count]; + System.arraycopy(content, 0, newdata, 0, count); + return newdata; + } + + public ByteBuffer[] toBuffers() { + return new ByteBuffer[]{ByteBuffer.wrap(content, 0, count)}; + } + + protected BsonWriter(byte[] bs) { + this.content = bs; + } + + public BsonWriter() { + this(defaultSize); + } + + public BsonWriter(int size) { + this.content = new byte[size > 128 ? size : 128]; + } + + @Override + public final boolean isTiny() { + return tiny; + } + + public BsonWriter setTiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + /** + * 扩充指定长度的缓冲区 + * + * @param len + * @return + */ + protected int expand(int len) { + int newcount = count + len; + if (newcount <= content.length) return 0; + byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; + System.arraycopy(content, 0, newdata, 0, count); + this.content = newdata; + return 0; + } + + public void writeTo(final byte ch) { + expand(1); + content[count++] = ch; + } + + public final void writeTo(final byte... chs) { + writeTo(chs, 0, chs.length); + } + + public void writeTo(final byte[] chs, final int start, final int len) { + expand(len); + System.arraycopy(chs, start, content, count, len); + count += len; + } + + protected boolean recycle() { + this.count = 0; + if (this.content.length > defaultSize) { + this.content = new byte[defaultSize]; + } + return true; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + //------------------------------------------------------------------------ + public final int count() { + return this.count; + } + + @Override + public final void writeBoolean(boolean value) { + writeTo(value ? (byte) 1 : (byte) 0); + } + + @Override + public final void writeByte(byte value) { + writeTo(value); + } + + @Override + public final void writeChar(final char value) { + writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF)); + } + + @Override + public final void writeShort(short value) { + writeTo((byte) (value >> 8), (byte) value); + } + + @Override + public final void writeInt(int value) { + writeTo((byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); + } + + @Override + public final void writeLong(long value) { + writeTo((byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32), + (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); + } + + @Override + public final void writeFloat(float value) { + writeInt(Float.floatToIntBits(value)); + } + + @Override + public final void writeDouble(double value) { + writeLong(Double.doubleToLongBits(value)); + } + + @Override + public final void wirteClassName(String clazz) { + writeSmallString(clazz == null ? "" : clazz); + } + + @Override + public final void writeObjectB(int fieldCount, Object obj) { + writeSmallString(""); + writeShort(BsonReader.SIGN_OBJECTB); + } + + @Override + public final void writeObjectE(Object obj) { + writeByte(BsonReader.SIGN_NONEXT); + writeShort(BsonReader.SIGN_OBJECTE); + } + + @Override + public final void writeField(boolean comma, Attribute attribute) { + writeByte(BsonReader.SIGN_HASNEXT); + writeSmallString(attribute.field()); + byte typeval = 127; //字段的类型值 + final Class type = attribute.type(); + if (type == boolean.class || type == Boolean.class) { + typeval = 1; + } else if (type == byte.class || type == Byte.class) { + typeval = 2; + } else if (type == short.class || type == Short.class) { + typeval = 3; + } else if (type == char.class || type == Character.class) { + typeval = 4; + } else if (type == int.class || type == Integer.class) { + typeval = 5; + } else if (type == long.class || type == Long.class) { + typeval = 6; + } else if (type == float.class || type == Float.class) { + typeval = 7; + } else if (type == double.class || type == Double.class) { + typeval = 8; + } else if (type == String.class) { + typeval = 9; + } else if (type == boolean[].class || type == Boolean[].class) { + typeval = 101; + } else if (type == byte[].class || type == Byte[].class) { + typeval = 102; + } else if (type == short[].class || type == Short[].class) { + typeval = 103; + } else if (type == char[].class || type == Character[].class) { + typeval = 104; + } else if (type == int[].class || type == Integer[].class) { + typeval = 105; + } else if (type == long[].class || type == Long[].class) { + typeval = 106; + } else if (type == float[].class || type == Float[].class) { + typeval = 107; + } else if (type == double[].class || type == Double[].class) { + typeval = 108; + } else if (type == String[].class) { + typeval = 109; + } + writeByte(typeval); + } + + /** + * 对于类的字段名、枚举值这些长度一般不超过255且不会出现双字节字符的字符串采用writeSmallString处理, readSmallString用于读取 + * + * @param value + */ + @Override + public final void writeSmallString(String value) { + if (value.isEmpty()) { + writeTo((byte) 0); + return; + } + char[] chars = Utility.charArray(value); + if (chars.length > 255) throw new ConvertException("'" + value + "' has very long length"); + byte[] bytes = new byte[chars.length + 1]; + bytes[0] = (byte) chars.length; + for (int i = 0; i < chars.length; i++) { + if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' has double-word"); + bytes[i + 1] = (byte) chars[i]; + } + writeTo(bytes); + } + + @Override + public final void writeString(String value) { + if (value == null) { + writeInt(Reader.SIGN_NULL); + return; + } else if (value.isEmpty()) { + writeInt(0); + return; + } + byte[] bytes = Utility.encodeUTF8(value); + writeInt(bytes.length); + writeTo(bytes); + } + + @Override + public final void writeNull() { + writeShort(Reader.SIGN_NULL); + } + + @Override + public final void writeArrayB(int size) { + writeInt(size); + } + + @Override + public final void writeArrayMark() { + } + + @Override + public final void writeArrayE() { + } + + @Override + public void writeMapB(int size) { + writeArrayB(size); + } + + @Override + public final void writeMapMark() { + } + + @Override + public final void writeMapE() { + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/BigIntegerSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/BigIntegerSimpledCoder.java new file mode 100644 index 000000000..8a6dd5284 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/BigIntegerSimpledCoder.java @@ -0,0 +1,38 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import org.redkale.convert.Reader; +import java.math.BigInteger; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class BigIntegerSimpledCoder extends SimpledCoder { + + public static final BigIntegerSimpledCoder instance = new BigIntegerSimpledCoder(); + + @Override + public void convertTo(W out, BigInteger value) { + if (value == null) { + out.writeNull(); + return; + } + ByteArraySimpledCoder.instance.convertTo(out, value.toByteArray()); + } + + @Override + public BigInteger convertFrom(R in) { + byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); + return bytes == null ? null : new BigInteger(bytes); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/BoolArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/BoolArraySimpledCoder.java new file mode 100644 index 000000000..bf9f2e2c2 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/BoolArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class BoolArraySimpledCoder extends SimpledCoder { + + public static final BoolArraySimpledCoder instance = new BoolArraySimpledCoder(); + + @Override + public void convertTo(W out, boolean[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (boolean v : values) { + if (flag) out.writeArrayMark(); + out.writeBoolean(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public boolean[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + boolean[] data = new boolean[8]; + while (in.hasNext()) { + if (size >= data.length) { + boolean[] newdata = new boolean[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readBoolean(); + } + in.readArrayE(); + boolean[] newdata = new boolean[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + boolean[] values = new boolean[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readBoolean(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/BoolSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/BoolSimpledCoder.java new file mode 100644 index 000000000..e25feca7d --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/BoolSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class BoolSimpledCoder extends SimpledCoder { + + public static final BoolSimpledCoder instance = new BoolSimpledCoder(); + + @Override + public void convertTo(W out, Boolean value) { + out.writeBoolean(value); + } + + @Override + public Boolean convertFrom(R in) { + return in.readBoolean(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/ByteArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/ByteArraySimpledCoder.java new file mode 100644 index 000000000..d642e726c --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/ByteArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class ByteArraySimpledCoder extends SimpledCoder { + + public static final ByteArraySimpledCoder instance = new ByteArraySimpledCoder(); + + @Override + public void convertTo(W out, byte[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (byte v : values) { + if (flag) out.writeArrayMark(); + out.writeByte(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public byte[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + byte[] data = new byte[8]; + while (in.hasNext()) { + if (size >= data.length) { + byte[] newdata = new byte[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readByte(); + } + in.readArrayE(); + byte[] newdata = new byte[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + byte[] values = new byte[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readByte(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/ByteSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/ByteSimpledCoder.java new file mode 100644 index 000000000..74861c7a8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/ByteSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class ByteSimpledCoder extends SimpledCoder { + + public static final ByteSimpledCoder instance = new ByteSimpledCoder(); + + @Override + public void convertTo(W out, Byte value) { + out.writeByte(value); + } + + @Override + public Byte convertFrom(R in) { + return in.readByte(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/CharArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/CharArraySimpledCoder.java new file mode 100644 index 000000000..efac0785f --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/CharArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class CharArraySimpledCoder extends SimpledCoder { + + public static final CharArraySimpledCoder instance = new CharArraySimpledCoder(); + + @Override + public void convertTo(W out, char[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (char v : values) { + if (flag) out.writeArrayMark(); + out.writeChar(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public char[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + char[] data = new char[8]; + while (in.hasNext()) { + if (size >= data.length) { + char[] newdata = new char[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readChar(); + } + in.readArrayE(); + char[] newdata = new char[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + char[] values = new char[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readChar(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/CharSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/CharSimpledCoder.java new file mode 100644 index 000000000..8e3803945 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/CharSimpledCoder.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class CharSimpledCoder extends SimpledCoder { + + public static final CharSimpledCoder instance = new CharSimpledCoder(); + + @Override + public void convertTo(W out, Character value) { + out.writeChar(value); + } + + @Override + public Character convertFrom(R in) { + return in.readChar(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/DLongSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/DLongSimpledCoder.java new file mode 100644 index 000000000..9df4bb726 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/DLongSimpledCoder.java @@ -0,0 +1,40 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.Writer; +import org.redkale.convert.SimpledCoder; +import org.redkale.util.DLong; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class DLongSimpledCoder extends SimpledCoder { + + public static final DLongSimpledCoder instance = new DLongSimpledCoder(); + + @Override + public void convertTo(final W out, final DLong value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.getFirst() + "_" + value.getSecond()); + } + } + + @Override + public DLong convertFrom(R in) { + String str = in.readString(); + if (str == null) return null; + int pos = str.indexOf('_'); + return new DLong(Long.parseLong(str.substring(0, pos)), Long.parseLong(str.substring(pos + 1))); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/DateSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/DateSimpledCoder.java new file mode 100644 index 000000000..d884167e4 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/DateSimpledCoder.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import java.util.Date; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class DateSimpledCoder extends SimpledCoder { + + public static final DateSimpledCoder instance = new DateSimpledCoder(); + + @Override + public void convertTo(W out, Date value) { + out.writeLong(value.getTime()); + } + + @Override + public Date convertFrom(R in) { + return new Date(in.readLong()); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/DoubleArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/DoubleArraySimpledCoder.java new file mode 100644 index 000000000..9005ab25d --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/DoubleArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class DoubleArraySimpledCoder extends SimpledCoder { + + public static final DoubleArraySimpledCoder instance = new DoubleArraySimpledCoder(); + + @Override + public void convertTo(W out, double[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (double v : values) { + if (flag) out.writeArrayMark(); + out.writeDouble(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public double[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + double[] data = new double[8]; + while (in.hasNext()) { + if (size >= data.length) { + double[] newdata = new double[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readDouble(); + } + in.readArrayE(); + double[] newdata = new double[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + double[] values = new double[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readDouble(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/DoubleSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/DoubleSimpledCoder.java new file mode 100644 index 000000000..613877115 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/DoubleSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class DoubleSimpledCoder extends SimpledCoder { + + public static final DoubleSimpledCoder instance = new DoubleSimpledCoder(); + + @Override + public void convertTo(W out, Double value) { + out.writeDouble(value); + } + + @Override + public Double convertFrom(R in) { + return in.readDouble(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/EnumSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/EnumSimpledCoder.java new file mode 100644 index 000000000..aa6b0ee10 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/EnumSimpledCoder.java @@ -0,0 +1,44 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + * @param + */ +public final class EnumSimpledCoder extends SimpledCoder { + + private final Class type; + + public EnumSimpledCoder(Class type) { + this.type = type; + } + + @Override + public void convertTo(final W out, final E value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + @SuppressWarnings("unchecked") + public E convertFrom(final R in) { + String value = in.readSmallString(); + if (value == null) return null; + return (E) Enum.valueOf(type, value); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/FloatArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/FloatArraySimpledCoder.java new file mode 100644 index 000000000..84eaf45f8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/FloatArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class FloatArraySimpledCoder extends SimpledCoder { + + public static final FloatArraySimpledCoder instance = new FloatArraySimpledCoder(); + + @Override + public void convertTo(W out, float[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (float v : values) { + if (flag) out.writeArrayMark(); + out.writeFloat(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public float[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + float[] data = new float[8]; + while (in.hasNext()) { + if (size >= data.length) { + float[] newdata = new float[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readFloat(); + } + in.readArrayE(); + float[] newdata = new float[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + float[] values = new float[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readFloat(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/FloatSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/FloatSimpledCoder.java new file mode 100644 index 000000000..265eddbeb --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/FloatSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class FloatSimpledCoder extends SimpledCoder { + + public static final FloatSimpledCoder instance = new FloatSimpledCoder(); + + @Override + public void convertTo(W out, Float value) { + out.writeFloat(value); + } + + @Override + public Float convertFrom(R in) { + return in.readFloat(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/InetAddressSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/InetAddressSimpledCoder.java new file mode 100644 index 000000000..f2eee328a --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/InetAddressSimpledCoder.java @@ -0,0 +1,70 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import org.redkale.convert.Reader; +import java.net.*; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class InetAddressSimpledCoder extends SimpledCoder { + + public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder(); + + @Override + public void convertTo(W out, InetAddress value) { + if (value == null) { + out.writeNull(); + return; + } + ByteArraySimpledCoder.instance.convertTo(out, value.getAddress()); + } + + @Override + public InetAddress convertFrom(R in) { + byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); + if (bytes == null) return null; + try { + return InetAddress.getByAddress(bytes); + } catch (Exception ex) { + return null; + } + } + + public final static class InetSocketAddressSimpledCoder extends SimpledCoder { + + public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder(); + + @Override + public void convertTo(W out, InetSocketAddress value) { + if (value == null) { + out.writeNull(); + return; + } + ByteArraySimpledCoder.instance.convertTo(out, value.getAddress().getAddress()); + out.writeInt(value.getPort()); + } + + @Override + public InetSocketAddress convertFrom(R in) { + byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); + if (bytes == null) return null; + int port = in.readInt(); + try { + return new InetSocketAddress(InetAddress.getByAddress(bytes), port); + } catch (Exception ex) { + return null; + } + } + + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/IntArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/IntArraySimpledCoder.java new file mode 100644 index 000000000..ca9b60000 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/IntArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class IntArraySimpledCoder extends SimpledCoder { + + public static final IntArraySimpledCoder instance = new IntArraySimpledCoder(); + + @Override + public void convertTo(W out, int[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (int v : values) { + if (flag) out.writeArrayMark(); + out.writeInt(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public int[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + int[] data = new int[8]; + while (in.hasNext()) { + if (size >= data.length) { + int[] newdata = new int[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readInt(); + } + in.readArrayE(); + int[] newdata = new int[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + int[] values = new int[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readInt(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/IntSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/IntSimpledCoder.java new file mode 100644 index 000000000..13815f424 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/IntSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class IntSimpledCoder extends SimpledCoder { + + public static final IntSimpledCoder instance = new IntSimpledCoder(); + + @Override + public void convertTo(W out, Integer value) { + out.writeInt(value); + } + + @Override + public Integer convertFrom(R in) { + return in.readInt(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/LongArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/LongArraySimpledCoder.java new file mode 100644 index 000000000..b9f21a145 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/LongArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class LongArraySimpledCoder extends SimpledCoder { + + public static final LongArraySimpledCoder instance = new LongArraySimpledCoder(); + + @Override + public void convertTo(W out, long[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (long v : values) { + if (flag) out.writeArrayMark(); + out.writeLong(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public long[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + long[] data = new long[8]; + while (in.hasNext()) { + if (size >= data.length) { + long[] newdata = new long[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readLong(); + } + in.readArrayE(); + long[] newdata = new long[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + long[] values = new long[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readLong(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/LongSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/LongSimpledCoder.java new file mode 100644 index 000000000..0c578ceea --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/LongSimpledCoder.java @@ -0,0 +1,33 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class LongSimpledCoder extends SimpledCoder { + + public static final LongSimpledCoder instance = new LongSimpledCoder(); + + @Override + public void convertTo(W out, Long value) { + out.writeLong(value); + } + + @Override + public Long convertFrom(R in) { + return in.readLong(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/NumberSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/NumberSimpledCoder.java new file mode 100644 index 000000000..28c809fa8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/NumberSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class NumberSimpledCoder extends SimpledCoder { + + public static final NumberSimpledCoder instance = new NumberSimpledCoder(); + + @Override + public void convertTo(W out, Number value) { + out.writeLong(value == null ? 0L : value.longValue()); + } + + @Override + public Number convertFrom(R in) { + return in.readLong(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/PatternSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/PatternSimpledCoder.java new file mode 100644 index 000000000..fd652a3ac --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/PatternSimpledCoder.java @@ -0,0 +1,38 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import java.util.regex.*; +import org.redkale.convert.*; + +/** + * + * @author zhangjx + * @param + * @param + */ +public class PatternSimpledCoder extends SimpledCoder { + + public static final PatternSimpledCoder instance = new PatternSimpledCoder(); + + @Override + public void convertTo(W out, Pattern value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.flags() + "," + value.pattern()); + } + } + + @Override + public Pattern convertFrom(R in) { + String value = in.readString(); + if (value == null) return null; + int pos = value.indexOf(','); + return Pattern.compile(value.substring(pos + 1), Integer.parseInt(value.substring(0, pos))); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/ShortArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/ShortArraySimpledCoder.java new file mode 100644 index 000000000..af726f8bc --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/ShortArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class ShortArraySimpledCoder extends SimpledCoder { + + public static final ShortArraySimpledCoder instance = new ShortArraySimpledCoder(); + + @Override + public void convertTo(W out, short[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (short v : values) { + if (flag) out.writeArrayMark(); + out.writeShort(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public short[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + short[] data = new short[8]; + while (in.hasNext()) { + if (size >= data.length) { + short[] newdata = new short[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readShort(); + } + in.readArrayE(); + short[] newdata = new short[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + short[] values = new short[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readShort(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/ShortSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/ShortSimpledCoder.java new file mode 100644 index 000000000..1b6f08221 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/ShortSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class ShortSimpledCoder extends SimpledCoder { + + public static final ShortSimpledCoder instance = new ShortSimpledCoder(); + + @Override + public void convertTo(W out, Short value) { + out.writeShort(value); + } + + @Override + public Short convertFrom(R in) { + return in.readShort(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/StringArraySimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/StringArraySimpledCoder.java new file mode 100644 index 000000000..c07cbc979 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/StringArraySimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class StringArraySimpledCoder extends SimpledCoder { + + public static final StringArraySimpledCoder instance = new StringArraySimpledCoder(); + + @Override + public void convertTo(W out, String[] values) { + if (values == null) { + out.writeNull(); + return; + } + out.writeArrayB(values.length); + boolean flag = false; + for (String v : values) { + if (flag) out.writeArrayMark(); + out.writeString(v); + flag = true; + } + out.writeArrayE(); + } + + @Override + public String[] convertFrom(R in) { + int len = in.readArrayB(); + if (len == Reader.SIGN_NULL) { + return null; + } else if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + String[] data = new String[8]; + while (in.hasNext()) { + if (size >= data.length) { + String[] newdata = new String[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readString(); + } + in.readArrayE(); + String[] newdata = new String[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + String[] values = new String[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readString(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/StringSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/StringSimpledCoder.java new file mode 100644 index 000000000..189e557ec --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/StringSimpledCoder.java @@ -0,0 +1,32 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class StringSimpledCoder extends SimpledCoder { + + public static final StringSimpledCoder instance = new StringSimpledCoder(); + + @Override + public void convertTo(W out, String value) { + out.writeString(value); + } + + @Override + public String convertFrom(R in) { + return in.readString(); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/ext/TypeSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/ext/TypeSimpledCoder.java new file mode 100644 index 000000000..f1a93b4e4 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/ext/TypeSimpledCoder.java @@ -0,0 +1,42 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.Writer; +import org.redkale.convert.SimpledCoder; + +/** + * + * @author zhangjx + * @param + * @param + */ +public class TypeSimpledCoder extends SimpledCoder { + + public static final TypeSimpledCoder instance = new TypeSimpledCoder(); + + @Override + public void convertTo(final W out, final Class value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.getName()); + } + } + + @Override + public Class convertFrom(R in) { + String str = in.readSmallString(); + if (str == null) return null; + try { + return Class.forName(str); + } catch (Exception e) { + return null; + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/InetAddressJsonSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/json/InetAddressJsonSimpledCoder.java new file mode 100644 index 000000000..2720284fd --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/InetAddressJsonSimpledCoder.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import java.net.*; +import org.redkale.convert.*; +import org.redkale.convert.ext.*; + +/** + * + * @author zhangjx + * @param + * @param + */ +public final class InetAddressJsonSimpledCoder extends SimpledCoder { + + public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder(); + + @Override + public void convertTo(JsonWriter out, InetAddress value) { + if (value == null) { + out.writeNull(); + return; + } + StringSimpledCoder.instance.convertTo(out, value.getHostAddress()); + } + + @Override + public InetAddress convertFrom(JsonReader in) { + String str = StringSimpledCoder.instance.convertFrom(in); + if (str == null) return null; + try { + return InetAddress.getByName(str); + } catch (Exception ex) { + return null; + } + } + + public final static class InetSocketAddressJsonSimpledCoder extends SimpledCoder { + + public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder(); + + @Override + public void convertTo(JsonWriter out, InetSocketAddress value) { + if (value == null) { + out.writeNull(); + return; + } + StringSimpledCoder.instance.convertTo(out, value.getHostString() + ":" + value.getPort()); + } + + @Override + public InetSocketAddress convertFrom(JsonReader in) { + String str = StringSimpledCoder.instance.convertFrom(in); + if (str == null) return null; + try { + int pos = str.indexOf(':'); + return new InetSocketAddress(str.substring(0, pos), Integer.parseInt(str.substring(pos + 1))); + } catch (Exception ex) { + return null; + } + } + + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/JsonByteBufferWriter.java b/android-jdk6-redkale/src/org/redkale/convert/json/JsonByteBufferWriter.java new file mode 100644 index 000000000..20835b1a9 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/JsonByteBufferWriter.java @@ -0,0 +1,348 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import java.nio.*; +import java.nio.charset.*; +import java.util.*; +import java.util.function.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public final class JsonByteBufferWriter extends JsonWriter { + + private static final Charset UTF8 = Charset.forName("UTF-8"); + + private final Charset charset; + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int index; + + protected JsonByteBufferWriter(Supplier supplier) { + this(null, supplier); + } + + protected JsonByteBufferWriter(Charset charset, Supplier supplier) { + this.charset = UTF8.equals(charset) ? null : charset; + this.supplier = supplier; + } + + @Override + public JsonByteBufferWriter setTiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + protected boolean recycle() { + this.index = 0; + this.buffers = null; + return false; + } + + @Override + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) buf.flip(); + } + return this.buffers; + } + + @Override + public int count() { + if (this.buffers == null) return 0; + int len = 0; + for (ByteBuffer buffer : buffers) { + len += buffer.remaining(); + } + return len; + } + + private int expand(final int byteLength) { + if (this.buffers == null) { + this.index = 0; + this.buffers = new ByteBuffer[]{supplier.get()}; + } + ByteBuffer buffer = this.buffers[index]; + if (!buffer.hasRemaining()) { + buffer.flip(); + buffer = supplier.get(); + ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; + System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length); + bufs[this.buffers.length] = buffer; + this.buffers = bufs; + this.index++; + } + int len = buffer.remaining(); + int size = 0; + while (len < byteLength) { + buffer = supplier.get(); + ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1]; + System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length); + bufs[this.buffers.length] = buffer; + this.buffers = bufs; + len += buffer.remaining(); + size++; + } + return size; + } + + @Override + public void writeTo(final char ch) { + if (ch > Byte.MAX_VALUE) throw new RuntimeException("writeTo char(int.value = " + (int) ch + ") must be less 127"); + expand(1); + this.buffers[index].put((byte) ch); + } + + @Override + public void writeTo(final char[] chs, final int start, final int len) { + writeTo(-1, false, chs, start, len); + } + + private void writeTo(int expandsize, final boolean quote, final char[] chs, final int start, final int len) { + int byteLength = quote ? 2 : 0; + ByteBuffer bb = null; + if (charset == null) { + byteLength += encodeUTF8Length(chs, start, len); + } else { + bb = charset.encode(CharBuffer.wrap(chs, start, len)); + byteLength += bb.remaining(); + } + if (expandsize < 0) expandsize = expand(byteLength); + if (expandsize == 0) { // 只需要一个buffer + final ByteBuffer buffer = this.buffers[index]; + if (quote) buffer.put((byte) '"'); + + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + char c = chs[i]; + if (c < 0x80) { + buffer.put((byte) c); + } else if (c < 0x800) { + buffer.put((byte) (0xc0 | (c >> 6))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else { + buffer.put((byte) (0xe0 | ((c >> 12)))); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + } + } else { + buffer.put(bb); + } + + if (quote) buffer.put((byte) '"'); + return; + } + ByteBuffer buffer = this.buffers[index]; + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + buffer = putChar(buffer, chs[i]); + } + } else { + while (bb.hasRemaining()) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(bb.get()); + } + } + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + } + + private ByteBuffer putChar(ByteBuffer buffer, char c) { + if (c < 0x80) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) c); + } else if (c < 0x800) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xc0 | (c >> 6))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xe0 | ((c >> 12)))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + return buffer; + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + private static int encodeUTF8Length(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chars = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chars[i]; + size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3)); + } + return size; + } + + private static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chars = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chars[i]; + switch (c) { + case '\n': size += 2; + break; + case '\r': size += 2; + break; + case '\t': size += 2; + break; + case '\\': size += 2; + break; + case '"': size += 2; + break; + default: + size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3)); + break; + } + } + return size; + } + + /** + * 注意: 该String值不能为null且不会进行转义, 只用于不含需要转义字符的字符串,例如enum、double、BigInteger转换的String + * + * @param quote + * @param value + */ + @Override + public void writeTo(final boolean quote, final String value) { + char[] chs = Utility.charArray(value); + writeTo(-1, quote, chs, 0, chs.length); + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + final char[] chs = Utility.charArray(value); + int len = 0; + for (char ch : chs) { + switch (ch) { + case '\n': len += 2; + break; + case '\r': len += 2; + break; + case '\t': len += 2; + break; + case '\\': len += 2; + break; + case '"': len += 2; + break; + default: len++; + break; + } + } + if (len == chs.length) { + writeTo(-1, true, chs, 0, len); + return; + } + int expandsize = -1; + if (this.charset == null) { //UTF-8 + final int byteLength = 2 + encodeEscapeUTF8Length(chs, 0, chs.length); + expandsize = expand(byteLength); + if (expandsize == 0) { // 只需要一个buffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put((byte) '"'); + for (char c : chs) { + switch (c) { + case '\n': buffer.put((byte) '\\').put((byte) 'n'); + break; + case '\r': buffer.put((byte) '\\').put((byte) 'r'); + break; + case '\t': buffer.put((byte) '\\').put((byte) 't'); + break; + case '\\': buffer.put((byte) '\\').put((byte) '\\'); + break; + case '"': buffer.put((byte) '\\').put((byte) '"'); + break; + default: + if (c < 0x80) { + buffer.put((byte) c); + } else if (c < 0x800) { + buffer.put((byte) (0xc0 | (c >> 6))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else { + buffer.put((byte) (0xe0 | ((c >> 12)))); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + break; + } + } + buffer.put((byte) '"'); + return; + } + } + StringBuilder sb = new StringBuilder(len); + for (char ch : chs) { + switch (ch) { + case '\n': sb.append("\\n"); + break; + case '\r': sb.append("\\r"); + break; + case '\t': sb.append("\\t"); + break; + case '\\': sb.append("\\\\"); + break; + case '"': sb.append("\\\""); + break; + default: sb.append(ch); + break; + } + } + char[] cs = Utility.charArray(sb); + writeTo(expandsize, true, cs, 0, sb.length()); + } + + @Override + public void writeField(boolean comma, Attribute attribute) { + if (comma) writeTo(','); + writeTo(true, attribute.field()); + writeTo(':'); + } + + @Override + public void writeSmallString(String value) { + writeTo(false, value); + } + + @Override + public String toString() { + return Objects.toString(this); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/JsonConvert.java b/android-jdk6-redkale/src/org/redkale/convert/json/JsonConvert.java new file mode 100644 index 000000000..d4d1786c8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/JsonConvert.java @@ -0,0 +1,137 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import java.lang.reflect.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public final class JsonConvert extends Convert { + + public static final Type TYPE_MAP_STRING_STRING = new TypeToken>() { + }.getType(); + + private static final ObjectPool readerPool = JsonReader.createPool(Integer.getInteger("convert.json.pool.size", 16)); + + private static final ObjectPool writerPool = JsonWriter.createPool(Integer.getInteger("convert.json.pool.size", 16)); + + private final boolean tiny; + + protected JsonConvert(JsonFactory factory, boolean tiny) { + super(factory); + this.tiny = tiny; + } + + public JsonByteBufferWriter pollJsonWriter(final Supplier supplier) { + return new JsonByteBufferWriter(supplier).setTiny(tiny); + } + + public JsonByteBufferWriter pollJsonWriter(final Charset charset, final Supplier supplier) { + return new JsonByteBufferWriter(charset, supplier).setTiny(tiny); + } + + public JsonWriter pollJsonWriter() { + return writerPool.get().setTiny(tiny); + } + + public void offerJsonWriter(JsonWriter out) { + if (out != null) writerPool.offer(out); + } + + @Override + public JsonFactory getFactory() { + return (JsonFactory) factory; + } + + public T convertFrom(final Type type, final String text) { + if (text == null) return null; + return convertFrom(type, Utility.charArray(text)); + } + + public T convertFrom(final Type type, final char[] text) { + if (text == null) return null; + return convertFrom(type, text, 0, text.length); + } + + public T convertFrom(final Type type, final char[] text, int start, int len) { + if (text == null || type == null) return null; + final JsonReader in = readerPool.get(); + in.setText(text, start, len); + T rs = (T) factory.loadDecoder(type).convertFrom(in); + readerPool.offer(in); + return rs; + } + + public String convertTo(final Type type, Object value) { + if (type == null) return null; + if (value == null) return "null"; + final JsonWriter out = writerPool.get().setTiny(tiny); + factory.loadEncoder(type).convertTo(out, value); + String result = out.toString(); + writerPool.offer(out); + return result; + } + + public String convertTo(Object value) { + if (value == null) return "null"; + return convertTo(value.getClass(), value); + } + + public void convertTo(final JsonWriter out, final Type type, Object value) { + if (type == null) return; + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(type).convertTo(out, value); + } + } + + public void convertTo(final JsonWriter out, Object value) { + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + } + + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, Object value) { + return convertTo(null, supplier, type, value); + } + + public ByteBuffer[] convertTo(final Charset charset, final Supplier supplier, final Type type, Object value) { + if (supplier == null || type == null) return null; + JsonByteBufferWriter out = new JsonByteBufferWriter(charset, supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(type).convertTo(out, value); + } + return out.toBuffers(); + } + + public ByteBuffer[] convertTo(final Supplier supplier, Object value) { + return convertTo(null, supplier, value); + } + + public ByteBuffer[] convertTo(final Charset charset, final Supplier supplier, Object value) { + if (supplier == null) return null; + JsonByteBufferWriter out = new JsonByteBufferWriter(charset, supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + return out.toBuffers(); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/JsonFactory.java b/android-jdk6-redkale/src/org/redkale/convert/json/JsonFactory.java new file mode 100644 index 000000000..435ab3496 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/JsonFactory.java @@ -0,0 +1,60 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import org.redkale.convert.ConvertType; +import org.redkale.convert.Factory; +import java.io.Serializable; +import java.net.*; + +/** + * + * @author zhangjx + */ +public final class JsonFactory extends Factory { + + private static final JsonFactory instance = new JsonFactory(null, Boolean.getBoolean("convert.json.tiny")); + + static { + instance.register(InetAddress.class, InetAddressJsonSimpledCoder.instance); + instance.register(InetSocketAddress.class, InetAddressJsonSimpledCoder.InetSocketAddressJsonSimpledCoder.instance); + instance.register(Serializable.class, instance.loadEncoder(Object.class)); + } + + private JsonFactory(JsonFactory parent, boolean tiny) { + super(parent, tiny); + } + + public static JsonFactory root() { + return instance; + } + + @Override + public final JsonConvert getConvert() { + if (convert == null) convert = new JsonConvert(this, tiny); + return (JsonConvert) convert; + } + + @Override + public JsonFactory createChild() { + return new JsonFactory(this, this.tiny); + } + + @Override + public JsonFactory createChild(boolean tiny) { + return new JsonFactory(this, tiny); + } + + @Override + public ConvertType getConvertType() { + return ConvertType.JSON; + } + + @Override + public boolean isReversible() { + return false; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/JsonReader.java b/android-jdk6-redkale/src/org/redkale/convert/json/JsonReader.java new file mode 100644 index 000000000..4a61d6c85 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/JsonReader.java @@ -0,0 +1,577 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import java.util.concurrent.atomic.*; +import java.util.function.*; +import org.redkale.convert.*; +import static org.redkale.convert.Reader.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public final class JsonReader implements Reader { + + private int position = -1; + + private char[] text; + + private int limit; + + public static ObjectPool createPool(int max) { + return new ObjectPool(max, new Creator() { //为了兼容 JDK 6 + + @Override + public JsonReader create(Object... params) { + return new JsonReader(); + } + }, null, new Predicate() { + + @Override + public boolean test(JsonReader t) { + return t.recycle(); + } + }); + } + + public JsonReader() { + } + + public JsonReader(String json) { + setText(Utility.charArray(json)); + } + + public JsonReader(char[] text) { + setText(text, 0, text.length); + } + + public JsonReader(char[] text, int start, int len) { + setText(text, start, len); + } + + public final void setText(String text) { + JsonReader.this.setText(Utility.charArray(text)); + } + + public final void setText(char[] text) { + setText(text, 0, text.length); + } + + public final void setText(char[] text, int start, int len) { + this.text = text; + this.position = start - 1; + this.limit = start + len - 1; + } + + protected boolean recycle() { + this.position = -1; + this.limit = -1; + this.text = null; + return true; + } + + public void close() { + this.recycle(); + } + + /** + * 找到指定的属性值 例如: {id : 1, data : { name : 'a', items : [1,2,3]}} seek('data.items') 直接跳转到 [1,2,3]; + * + * @param key + */ + public final void seek(String key) { + if (key == null || key.length() < 1) return; + final String[] keys = key.split("\\."); + nextGoodChar(); //读掉 { [ + for (String key1 : keys) { + while (this.hasNext()) { + String field = this.readSmallString(); + skipBlank(); + if (key1.equals(field)) break; + skipValue(); + } + } + + } + + /** + * 跳过属性的值 + */ + @Override + public final void skipValue() { + final char ch = nextGoodChar(); + if (ch == '"' || ch == '\'') { + backChar(ch); + readString(); + } else if (ch == '{') { + while (hasNext()) { + this.readSmallString(); //读掉field + this.skipBlank(); + this.skipValue(); + } + } else if (ch == '[') { + while (hasNext()) { + this.skipValue(); + } + } else { + char c; + for (;;) { + c = nextChar(); + if (c <= ' ') return; + if (c == '}' || c == ']' || c == ',' || c == ':') { + backChar(c); + return; + } + } + } + } + + /** + * 读取下一个字符, 不跳过空白字符 + * + * @return + */ + protected char nextChar() { + return this.text[++this.position]; + } + + /** + * 跳过空白字符, 返回一个非空白字符 + * + * @return + */ + protected char nextGoodChar() { + char c = nextChar(); + if (c > ' ') return c; + for (;;) { + c = nextChar(); + if (c > ' ') return c; + } + } + + /** + * 回退最后读取的字符 + * + * @param ch + */ + protected void backChar(char ch) { + this.position--; + } + + /** + * 判断下一个非空白字符是否为{ + * + */ + @Override + public int readObjectB() { + char ch = this.text[++this.position]; + if (ch == '{') return SIGN_NOLENGTH; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == '{') return SIGN_NOLENGTH; + } + if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return SIGN_NULL; + if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return SIGN_NULL; + throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + + @Override + public void readObjectE() { + } + + /** + * 判断下一个非空白字符是否为{ + * + */ + @Override + public int readMapB() { + return readArrayB(); + } + + @Override + public void readMapE() { + } + + /** + * 判断下一个非空白字符是否为[ + * + * @return + */ + @Override + public int readArrayB() { + char ch = this.text[++this.position]; + if (ch == '[') return SIGN_NOLENGTH; + if (ch == '{') return SIGN_NOLENGTH; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == '[') return SIGN_NOLENGTH; + if (ch == '{') return SIGN_NOLENGTH; + } + if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return SIGN_NULL; + if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return SIGN_NULL; + throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + + @Override + public void readArrayE() { + } + + /** + * 判断下一个非空白字符是否: + */ + @Override + public void skipBlank() { + char ch = this.text[++this.position]; + if (ch == ':') return; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == ':') return; + } + throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")"); + } + + /** + * 判断对象是否存在下一个属性或者数组是否存在下一个元素 + * + * @return + */ + @Override + public boolean hasNext() { + char ch = this.text[++this.position]; + if (ch == ',') return true; + if (ch == '}' || ch == ']') return false; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == ',') return true; + if (ch == '}' || ch == ']') return false; + } + this.position--; + return true; + } + + @Override + public String readClassName() { + return null; + } + + @Override + public String readSmallString() { + final int eof = this.limit; + if (this.position == eof) return null; + final char[] text0 = this.text; + int currpos = this.position; + char ch = text0[++currpos]; + if (ch <= ' ') { + for (;;) { + ch = text0[++currpos]; + if (ch > ' ') break; + } + } + if (ch == '"' || ch == '\'') { + final char quote = ch; + final int start = currpos + 1; + for (;;) { + ch = text0[++currpos]; + if (ch == '\\') { + this.position = currpos - 1; + return readEscapeValue(quote, start); + } else if (ch == quote) { + break; + } + } + this.position = currpos; + char[] chs = new char[currpos - start]; + System.arraycopy(text0, start, chs, 0, chs.length); + return new String(chs); + } else { + int start = currpos; + for (;;) { + if (currpos == eof) break; + ch = text0[++currpos]; + if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') break; + } + int len = currpos - start; + if (len < 1) { + this.position = currpos; + return String.valueOf(ch); + } + this.position = currpos - 1; + if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null; + return new String(text0, start, len); + } + } + + /** + * 读取一个int + * + * @return + */ + @Override + public final int readInt() { + final char[] text0 = this.text; + final int eof = this.limit; + int currpos = this.position; + char firstchar = text0[++currpos]; + if (firstchar <= ' ') { + for (;;) { + firstchar = text0[++currpos]; + if (firstchar > ' ') break; + } + } + if (firstchar == '"' || firstchar == '\'') { + firstchar = text0[++currpos]; + if (firstchar == '"' || firstchar == '\'') { + this.position = currpos; + return 0; + } + } + int value = 0; + final boolean negative = firstchar == '-'; + if (!negative) { + if (firstchar < '0' || firstchar > '9') throw new NumberFormatException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); + value = firstchar - '0'; + } + for (;;) { + if (currpos == eof) break; + char ch = text0[++currpos]; + if (ch >= '0' && ch <= '9') { + value = (value << 3) + (value << 1) + (ch - '0'); + } else if (ch == '"' || ch == '\'') { + } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { + break; + } else { + throw new NumberFormatException("illegal escape(" + ch + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); + } + } + this.position = currpos - 1; + return negative ? -value : value; + } + + /** + * 读取一个long + * + * @return + */ + @Override + public final long readLong() { + final char[] text0 = this.text; + final int eof = this.limit; + int currpos = this.position; + char firstchar = text0[++currpos]; + if (firstchar <= ' ') { + for (;;) { + firstchar = text0[++currpos]; + if (firstchar > ' ') break; + } + } + if (firstchar == '"' || firstchar == '\'') { + firstchar = text0[++currpos]; + if (firstchar == '"' || firstchar == '\'') { + this.position = currpos; + return 0L; + } + } + long value = 0; + final boolean negative = firstchar == '-'; + if (!negative) { + if (firstchar < '0' || firstchar > '9') throw new NumberFormatException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); + value = firstchar - '0'; + } + for (;;) { + if (currpos == eof) break; + char ch = text0[++currpos]; + if (ch >= '0' && ch <= '9') { + value = (value << 3) + (value << 1) + (ch - '0'); + } else if (ch == '"' || ch == '\'') { + } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { + break; + } else { + throw new NumberFormatException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + } + this.position = currpos - 1; + return negative ? -value : value; + } + + @Override + public DeMember readField(final AtomicInteger index, final DeMember[] members) { + final String exceptedfield = this.readSmallString(); + final int len = members.length; + int v = index.get(); + if (v >= len) { + v = 0; + index.set(0); + } + for (int k = v; k < len; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + index.set(k); + return members[k]; + } + } + for (int k = 0; k < v; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + index.set(k); + return members[k]; + } + } + return null; + //if (result == null && len == 1 && text0[start] == '@') return REFER; + } +//------------------------------------------------------------ + + @Override + public boolean readBoolean() { + return "true".equalsIgnoreCase(this.readSmallString()); + } + + @Override + public byte readByte() { + return (byte) readInt(); + } + + @Override + public char readChar() { + return (char) readInt(); + } + + @Override + public short readShort() { + return (short) readInt(); + } + + @Override + public float readFloat() { + String chars = readSmallString(); + if (chars == null || chars.isEmpty()) return 0.f; + return Float.parseFloat(chars); + } + + @Override + public double readDouble() { + String chars = readSmallString(); + if (chars == null || chars.isEmpty()) return 0.0; + return Double.parseDouble(chars); + } + + /** + * 读取字符串, 必须是"或者'包围的字符串值 + * + * @return + */ + @Override + public String readString() { + final char[] text0 = this.text; + int currpos = this.position; + char expected = text0[++currpos]; + if (expected <= ' ') { + for (;;) { + expected = text0[++currpos]; + if (expected > ' ') break; + } + } + if (expected != '"' && expected != '\'') { + if (expected == 'n' && text0.length > currpos + 3) { + if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') { + this.position = currpos; + if (text0.length > currpos + 4) { + char ch = text0[currpos + 1]; + if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') return null; + } else { + return null; + } + } + } else { + final int start = currpos; + for (;;) { + char ch = text0[currpos]; + if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break; + currpos++; + } + if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); + this.position = currpos - 1; + return new String(text0, start, currpos - start); + } + this.position = currpos; + throw new ConvertException("expected a ':' after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); + } + final int start = ++currpos; + for (;;) { + char ch = text0[currpos]; + if (ch == expected) { + break; + } else if (ch == '\\') { + this.position = currpos - 1; + return readEscapeValue(expected, start); + } + currpos++; + } + this.position = currpos; + return new String(text0, start, currpos - start); + } + + private String readEscapeValue(final char expected, int start) { + StringBuilder array = new StringBuilder(); + final char[] text0 = this.text; + int pos = this.position; + array.append(text0, start, pos + 1 - start); + char c; + for (;;) { + c = text0[++pos]; + if (c == expected) { + this.position = pos; + return array.toString(); + } else if (c == '\\') { + c = text0[++pos]; + switch (c) { + case '"': + case '\'': + case '\\': + case '/': + array.append(c); + break; + case 'n': + array.append('\n'); + break; + case 'r': + array.append('\r'); + break; + case 'u': + array.append((char) Integer.parseInt(new String(new char[]{text0[++pos], text0[++pos], text0[++pos], text0[++pos]}), 16)); + break; + case 't': + array.append('\t'); + break; + case 'b': + array.append('\b'); + break; + case 'f': + array.append('\f'); + break; + default: + this.position = pos; + throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ") in (" + new String(this.text) + ")"); + } + } else { + array.append(c); + } + } + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/JsonSimpledCoder.java b/android-jdk6-redkale/src/org/redkale/convert/json/JsonSimpledCoder.java new file mode 100644 index 000000000..396cba71a --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/JsonSimpledCoder.java @@ -0,0 +1,17 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import org.redkale.convert.SimpledCoder; + +/** + * + * @author zhangjx + * @param + */ +public abstract class JsonSimpledCoder extends SimpledCoder { + +} diff --git a/android-jdk6-redkale/src/org/redkale/convert/json/JsonWriter.java b/android-jdk6-redkale/src/org/redkale/convert/json/JsonWriter.java new file mode 100644 index 000000000..6766406af --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/convert/json/JsonWriter.java @@ -0,0 +1,268 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert.json; + +import java.nio.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * + * writeTo系列的方法输出的字符不能含特殊字符 + * + * @author zhangjx + */ +public class JsonWriter implements Writer { + + private static final char[] CHARS_TUREVALUE = "true".toCharArray(); + + private static final char[] CHARS_FALSEVALUE = "false".toCharArray(); + + private static final int defaultSize = Integer.getInteger("convert.json.writer.buffer.defsize", 1024); + + private int count; + + private char[] content; + + protected boolean tiny; + + public static ObjectPool createPool(int max) { + return new ObjectPool(max, new Creator() { + + @Override + public JsonWriter create(Object... params) { + return new JsonWriter(); + } + }, null, new Predicate() { + + @Override + public boolean test(JsonWriter t) { + return t.recycle(); + } + }); + } + + public JsonWriter() { + this(defaultSize); + } + + public JsonWriter(int size) { + this.content = new char[size > 128 ? size : 128]; + } + + @Override + public boolean isTiny() { + return tiny; + } + + public JsonWriter setTiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + /** + * 返回指定至少指定长度的缓冲区 + * + * @param len + * @return + */ + private char[] expand(int len) { + int newcount = count + len; + if (newcount <= content.length) return content; + char[] newdata = new char[Math.max(content.length * 3 / 2, newcount)]; + System.arraycopy(content, 0, newdata, 0, count); + this.content = newdata; + return newdata; + } + + public void writeTo(final char ch) { //只能是 0 - 127 的字符 + expand(1); + content[count++] = ch; + } + + public void writeTo(final char[] chs, final int start, final int len) { //只能是 0 - 127 的字符 + expand(len); + System.arraycopy(chs, start, content, count, len); + count += len; + } + + /** + * 注意: 该String值不能为null且不会进行转义, 只用于不含需要转义字符的字符串,例如enum、double、BigInteger转换的String + * + * @param quote + * @param value + */ + public void writeTo(final boolean quote, final String value) { + int len = value.length(); + expand(len + (quote ? 2 : 0)); + if (quote) content[count++] = '"'; + value.getChars(0, len, content, count); + count += len; + if (quote) content[count++] = '"'; + } + + protected boolean recycle() { + this.count = 0; + if (this.content.length > defaultSize) { + this.content = new char[defaultSize]; + } + return true; + } + + public ByteBuffer[] toBuffers() { + return new ByteBuffer[]{ByteBuffer.wrap(Utility.encodeUTF8(content, 0, count))}; + } + + public int count() { + return this.count; + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + expand(value.length() * 2 + 2); + content[count++] = '"'; + for (char ch : Utility.charArray(value)) { + switch (ch) { + case '\n': content[count++] = '\\'; + content[count++] = 'n'; + break; + case '\r': content[count++] = '\\'; + content[count++] = 'r'; + break; + case '\t': content[count++] = '\\'; + content[count++] = 't'; + break; + case '\\': content[count++] = '\\'; + content[count++] = ch; + break; + case '"': content[count++] = '\\'; + content[count++] = ch; + break; + default: content[count++] = ch; + break; + } + } + content[count++] = '"'; + } + + @Override + public void writeField(boolean comma, Attribute attribute) { + if (comma) writeTo(','); + writeTo(true, attribute.field()); + writeTo(':'); + } + + @Override + public void writeSmallString(String value) { + writeTo(false, value); + } + + @Override + public String toString() { + return new String(content, 0, count); + } + + //---------------------------------------------------------------------------------------------- + public final void writeTo(final char... chs) { //只能是 0 - 127 的字符 + writeTo(chs, 0, chs.length); + } + + @Override + public final void writeBoolean(boolean value) { + writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); + } + + @Override + public final void writeByte(byte value) { + writeInt(value); + } + + @Override + public final void writeChar(char value) { + writeInt(value); + } + + @Override + public final void writeShort(short value) { + writeInt(value); + } + + @Override + public final void writeInt(int value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void writeLong(long value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void writeFloat(float value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void writeDouble(double value) { + writeSmallString(String.valueOf(value)); + } + + @Override + public final void wirteClassName(String clazz) { + } + + @Override + public final void writeObjectB(int fieldCount, Object obj) { + writeTo('{'); + } + + @Override + public final void writeObjectE(Object obj) { + writeTo('}'); + } + + @Override + public final void writeNull() { + writeTo('n', 'u', 'l', 'l'); + } + + @Override + public final void writeArrayB(int size) { + writeTo('['); + } + + @Override + public final void writeArrayMark() { + writeTo(','); + } + + @Override + public final void writeArrayE() { + writeTo(']'); + } + + @Override + public final void writeMapB(int size) { + writeTo('{'); + } + + @Override + public final void writeMapMark() { + writeTo(':'); + } + + @Override + public final void writeMapE() { + writeTo('}'); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/net/client/HttpClient.java b/android-jdk6-redkale/src/org/redkale/net/client/HttpClient.java new file mode 100644 index 000000000..d27696719 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/net/client/HttpClient.java @@ -0,0 +1,89 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.client; + +import java.net.*; +import java.util.*; + +/** + * + * @author zhangjx + */ +public final class HttpClient { + + protected List cookies; + + protected Map headers; + + protected Map params; + + protected final HttpFactory factory; + + protected final URL url; + + HttpClient(HttpFactory factory, URL url) { + this.factory = factory; + this.url = url; + } + + public HttpClient setTimeoutListener(Runnable runner) { + return this; + } + + public Map getHeaders() { + return headers == null ? null : new HashMap(headers); + } + + public HttpClient addHeader(String name, String value) { + if (headers == null) this.headers = new HashMap(); + headers.put(name, value); + return this; + } + + public HttpClient removeHeader(String name) { + if (this.headers == null) return this; + headers.remove(name); + return this; + } + + public List getCookies() { + return cookies == null ? null : new ArrayList(cookies); + } + + public HttpClient addCookie(HttpCookie cookie) { + if (cookies == null) this.cookies = new ArrayList(); + if (cookie != null) cookies.add(cookie); + return this; + } + + public HttpClient addCookie(HttpCookie... cookies) { + if (cookies == null) this.cookies = new ArrayList(); + if (cookies != null) { + for (HttpCookie c : cookies) { + if (c != null) this.cookies.add(c); + } + } + return this; + } + + public HttpClient removeCookie(String name) { + if (this.cookies == null) return this; + HttpCookie cookie = null; + for (HttpCookie c : cookies) { + if (c.getName().equals(name)) { + cookie = c; + break; + } + } + cookies.remove(cookie); + return this; + } + + public static void main(String[] args) throws Exception { + URL url = new URL("https://www.wentch.com"); + System.out.println(url.openConnection().getClass()); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/net/client/HttpFactory.java b/android-jdk6-redkale/src/org/redkale/net/client/HttpFactory.java new file mode 100644 index 000000000..af276593e --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/net/client/HttpFactory.java @@ -0,0 +1,85 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.client; + +import java.net.*; +import java.util.*; +import java.util.concurrent.*; + +/** + * + * @author zhangjx + */ +public class HttpFactory { + + private static final HttpFactory instance = new HttpFactory(null); + + final HttpFactory parent; + + final List defaultCookies = new CopyOnWriteArrayList(); + + final Map defaultHeaders = new ConcurrentHashMap(); + + private HttpFactory(HttpFactory parent) { + this.parent = parent; + } + + public HttpFactory parent() { + return this.parent; + } + + public static HttpFactory root() { + return instance; + } + + public HttpFactory createChild() { + return new HttpFactory(this); + } + + public Map getDefaultHeader() { + return new HashMap(defaultHeaders); + } + + public HttpFactory addDefaultHeader(String name, String value) { + defaultHeaders.put(name, value); + return this; + } + + public HttpFactory removeDefaultHeader(String name) { + defaultHeaders.remove(name); + return this; + } + + public HttpFactory addDefaultCookie(HttpCookie cookie) { + if (cookie != null) defaultCookies.add(cookie); + return this; + } + + public HttpFactory addDefaultCookie(HttpCookie... cookies) { + if (cookies != null) { + for (HttpCookie c : cookies) { + if (c != null) defaultCookies.add(c); + } + } + return this; + } + + public HttpFactory removeDefaultCookie(String name) { + HttpCookie cookie = null; + for (HttpCookie c : defaultCookies) { + if (c.getName().equals(name)) { + cookie = c; + break; + } + } + defaultCookies.remove(cookie); + return this; + } + + public HttpClient open(URL url) { + return new HttpClient(this, url); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/net/client/WebSocketClient.java b/android-jdk6-redkale/src/org/redkale/net/client/WebSocketClient.java new file mode 100644 index 000000000..eca39a863 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/net/client/WebSocketClient.java @@ -0,0 +1,154 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.client; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import javax.net.ssl.*; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public class WebSocketClient { + + protected final boolean ssl; + + protected final URI uri; + + protected final Map headers = new HashMap(); + + private Proxy proxy; + + private SSLContext sslContext; + + private Socket socket; + + private final Map attributes = new ConcurrentHashMap(); + + private WebSocketClient(URI uri, Map headers0) { + this.uri = uri; + this.ssl = "wss".equalsIgnoreCase(uri.getScheme()); + if (headers0 != null) this.headers.putAll(headers0); + } + + public URI getURI() { + return uri; + } + + public static WebSocketClient create(URI uri) { + return create(uri, null); + } + + public static WebSocketClient create(URI uri, Map headers) { + return new WebSocketClient(uri, headers); + } + + public WebSocketClient setSSLContext(SSLContext sslContext) { + this.sslContext = sslContext; + return this; + } + + public WebSocketClient setProxy(Proxy proxy) { + this.proxy = proxy; + return this; + } + + public WebSocketClient addHeader(String name, String value) { + this.headers.put(name, value); + return this; + } + + public int getPort() { + int port = uri.getPort(); + if (port > 0) return port; + return ssl ? 443 : 80; + } + + public void connect() throws IOException { + if (ssl) { + if (proxy == null) { + this.socket = (sslContext == null ? Utility.getDefaultSSLContext() : sslContext).getSocketFactory().createSocket(uri.getHost(), getPort()); + } else { + Socket s = new Socket(proxy); + this.socket.setSoTimeout(3000); + s.connect(new InetSocketAddress(uri.getHost(), getPort())); + this.socket = (sslContext == null ? Utility.getDefaultSSLContext() : sslContext).getSocketFactory().createSocket(s, uri.getHost(), getPort(), true); + } + } else { + this.socket = proxy == null ? new Socket() : new Socket(proxy); + this.socket.setSoTimeout(3000); + this.socket.connect(new InetSocketAddress(uri.getHost(), getPort())); + } + } + + public static void main(String[] args) throws Exception { + URI uri = new URI("ws://10.28.2.207:5050/pipes/ws/listen?test=aa"); + WebSocketClient client = WebSocketClient.create(uri); + client.connect(); + System.out.println(); + } + + public void onConnected() { + } + + public void onMessage(String text) { + } + + public void onPing(byte[] bytes) { + } + + public void onPong(byte[] bytes) { + } + + public void onMessage(byte[] bytes) { + } + + public void onFragment(String text, boolean last) { + } + + public void onFragment(byte[] bytes, boolean last) { + } + + public void onClose(int code, String reason) { + } + + /** + * 获取当前WebSocket下的属性 + *

+ * @param + * @param name + * @return + */ + @SuppressWarnings("unchecked") + public final T getAttribute(String name) { + return (T) attributes.get(name); + } + + /** + * 移出当前WebSocket下的属性 + *

+ * @param + * @param name + * @return + */ + public final T removeAttribute(String name) { + return (T) attributes.remove(name); + } + + /** + * 给当前WebSocket下的增加属性 + *

+ * @param name + * @param value + */ + public final void setAttribute(String name, Object value) { + attributes.put(name, value); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/Attribute.java b/android-jdk6-redkale/src/org/redkale/util/Attribute.java new file mode 100644 index 000000000..432365320 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/Attribute.java @@ -0,0 +1,300 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.lang.reflect.*; +import static org.objectweb.asm.Opcodes.*; +import org.objectweb.asm.Type; + +/** + * 该类功能是动态映射一个Data类中成员对应的getter、setter方法; 代替低效的反射实现方式。 + * 映射Field时,field要么是public非final,要么存在对应的getter、setter方法。 + * + * @author zhangjx + * @param + * @param + */ +public interface Attribute { + + public Class type(); + + public Class declaringClass(); + + public String field(); + + public F get(T obj); + + public void set(T obj, F value); + + public static final class Attributes { + + public static Attribute create(final Field field) { + return create((Class) field.getDeclaringClass(), field.getName(), field, null, null); + } + + public static Attribute create(String fieldname, final Field field) { + return create((Class) field.getDeclaringClass(), fieldname, field, null, null); + } + + public static Attribute create(Class clazz, final String fieldname) { + try { + return create(clazz, fieldname, clazz.getDeclaredField(fieldname), null, null); + } catch (NoSuchFieldException ex) { + throw new RuntimeException(ex); + } catch (SecurityException ex2) { + throw new RuntimeException(ex2); + } + } + + public static Attribute create(Class clazz, final java.lang.reflect.Field field) { + return create(clazz, field.getName(), field); + } + + public static Attribute create(Class clazz, final String fieldname, final java.lang.reflect.Field field) { + return create(clazz, fieldname, field, null, null); + } + + public static Attribute create(final Method getter, final Method setter) { + return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), null, null, getter, setter); + } + + public static Attribute create(Class clazz, final Method getter, final Method setter) { + return create(clazz, null, null, getter, setter); + } + + public static Attribute create(Class clazz, final String fieldalias, final Method getter, final Method setter) { + return create(clazz, fieldalias, null, getter, setter); + } + + @SuppressWarnings("unchecked") + public static Attribute create(final Class clazz, String fieldalias0, final Field field0, Method getter0, Method setter0) { + if (fieldalias0 != null && fieldalias0.isEmpty()) fieldalias0 = null; + int mod = field0 == null ? Modifier.STATIC : field0.getModifiers(); + if (field0 != null && !Modifier.isStatic(mod) && !Modifier.isPublic(mod)) { + Class t = field0.getType(); + char[] fs = field0.getName().toCharArray(); + fs[0] = Character.toUpperCase(fs[0]); + String mn = new String(fs); + if (getter0 == null) { + String prefix = t == boolean.class || t == Boolean.class ? "is" : "get"; + try { + getter0 = clazz.getMethod(prefix + mn); + } catch (Exception ex) { + } + } + if (setter0 == null) { + try { + setter0 = clazz.getMethod("set" + mn, field0.getType()); + } catch (Exception ex) { + } + } + } + final Field field = field0 == null ? null : (!Modifier.isPublic(mod) || Modifier.isStatic(mod) ? null : field0); + final java.lang.reflect.Method getter = getter0; + final java.lang.reflect.Method setter = setter0; + if (fieldalias0 == null) { + if (field0 != null) { + fieldalias0 = field0.getName(); + } else { + String s; + if (getter0 != null) { + s = getter0.getName().substring(getter0.getName().startsWith("is") ? 2 : 3); + } else { + s = setter0.getName().substring(3); + } + char[] d = s.toCharArray(); + if (d.length < 2 || Character.isLowerCase(d[1])) { + d[0] = Character.toLowerCase(d[0]); + } + fieldalias0 = new String(d); + } + } + if (getter == null && setter == null && field == null) { + throw new RuntimeException("[" + clazz + "]have no public field or setter or getter"); + } + final String fieldname = fieldalias0; + Class column; + if (field != null) { // public field + column = field.getType(); + } else if (getter != null) { + column = getter.getReturnType(); + } else { // setter != null + column = setter.getParameterTypes()[0]; + } + final Class pcolumn = column; + if (column.isPrimitive()) column = Array.get(Array.newInstance(column, 1), 0).getClass(); + final String supDynName = Attribute.class.getName().replace('.', '/'); + final String interName = clazz.getName().replace('.', '/'); + final String columnName = column.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(clazz); + final String columnDesc = Type.getDescriptor(column); + + ClassLoader loader = Attribute.class.getClassLoader(); + String newDynName = supDynName + "_Dyn_" + clazz.getSimpleName() + "_" + + fieldname.substring(fieldname.indexOf('.') + 1) + "_" + pcolumn.getSimpleName().replace("[]", "Array"); + if (String.class.getClassLoader() != clazz.getClassLoader()) { + loader = clazz.getClassLoader(); + newDynName = interName + "_Dyn" + Attribute.class.getSimpleName() + "_" + + fieldname.substring(fieldname.indexOf('.') + 1) + "_" + pcolumn.getSimpleName().replace("[]", "Array"); + } + try { + return (Attribute) Class.forName(newDynName.replace('/', '.')).newInstance(); + } catch (Exception ex) { + } + //--------------------------------------------------- + final org.objectweb.asm.ClassWriter cw = new org.objectweb.asm.ClassWriter(0); + org.objectweb.asm.MethodVisitor mv; + + cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + columnDesc + ">;", "java/lang/Object", new String[]{supDynName}); + + { //构造方法 + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { //field 方法 + mv = cw.visitMethod(ACC_PUBLIC, "field", "()Ljava/lang/String;", null, null); + mv.visitLdcInsn(fieldname); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //type 方法 + mv = cw.visitMethod(ACC_PUBLIC, "type", "()Ljava/lang/Class;", null, null); + if (pcolumn == boolean.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == byte.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == char.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == short.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == int.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == float.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == long.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == double.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); + } else { + mv.visitLdcInsn(Type.getType(pcolumn)); + } + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //declaringClass 方法 + mv = cw.visitMethod(ACC_PUBLIC, "declaringClass", "()Ljava/lang/Class;", null, null); + mv.visitLdcInsn(Type.getType(clazz)); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //get 方法 + mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + interDesc + ")" + columnDesc, null, null); + int m = 1; + if (getter == null) { + if (field == null) { + mv.visitInsn(ACONST_NULL); + } else { //public field + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, interName, field.getName(), Type.getDescriptor(pcolumn)); + if (pcolumn != column) { + mv.visitMethodInsn(INVOKESTATIC, columnName, "valueOf", "(" + Type.getDescriptor(pcolumn) + ")" + columnDesc, false); + } + } + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, interName, getter.getName(), Type.getMethodDescriptor(getter), false); + if (pcolumn != column) { + mv.visitMethodInsn(INVOKESTATIC, columnName, "valueOf", "(" + Type.getDescriptor(pcolumn) + ")" + columnDesc, false); + m = 2; + } + } + mv.visitInsn(ARETURN); + mv.visitMaxs(m, 2); + mv.visitEnd(); + } + { //set 方法 + mv = cw.visitMethod(ACC_PUBLIC, "set", "(" + interDesc + columnDesc + ")V", null, null); + int m = 2; + if (setter == null) { + if (field == null || Modifier.isFinal(field.getModifiers())) { + m = 0; + } else { //public field + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + if (pcolumn != column) { + try { + java.lang.reflect.Method pm = column.getMethod(pcolumn.getSimpleName() + "Value"); + mv.visitMethodInsn(INVOKEVIRTUAL, columnName, pm.getName(), Type.getMethodDescriptor(pm), false); + } catch (Exception ex) { + throw new RuntimeException(ex); //不可能会发生 + } + } + mv.visitFieldInsn(PUTFIELD, interName, field.getName(), Type.getDescriptor(pcolumn)); + } + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + if (pcolumn != column) { + try { + java.lang.reflect.Method pm = column.getMethod(pcolumn.getSimpleName() + "Value"); + mv.visitMethodInsn(INVOKEVIRTUAL, columnName, pm.getName(), Type.getMethodDescriptor(pm), false); + m = 3; + } catch (Exception ex) { + throw new RuntimeException(ex); //不可能会发生 + } + } + mv.visitMethodInsn(INVOKEVIRTUAL, interName, setter.getName(), Type.getMethodDescriptor(setter), false); + } + mv.visitInsn(RETURN); + mv.visitMaxs(m, 3); + mv.visitEnd(); + } + { //虚拟get + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, interName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "get", "(" + interDesc + ")" + columnDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + {//虚拟set + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, interName); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, columnName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "set", "(" + interDesc + columnDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Class creatorClazz = (Class) new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + try { + return creatorClazz.newInstance(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/ByteArray.java b/android-jdk6-redkale/src/org/redkale/util/ByteArray.java new file mode 100644 index 000000000..f6fddf6ad --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/ByteArray.java @@ -0,0 +1,161 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.nio.*; +import java.nio.charset.*; + +/** + * + * @author zhangjx + */ +public final class ByteArray { + + private byte[] content; + + private int count; + + public ByteArray() { + this(1024); + } + + public ByteArray(int size) { + content = new byte[Math.max(128, size)]; + } + + public void clear() { + this.count = 0; + } + + public int find(byte value) { + return find(0, value); + } + + public boolean equal(final byte[] bytes) { + if (bytes == null || count != bytes.length) return false; + for (int i = 0; i < count; i++) { + if (content[i] != bytes[i]) return false; + } + return true; + } + + public boolean isEmpty() { + return count == 0; + } + + public int count() { + return count; + } + + public void write(byte[] buf) { + System.arraycopy(this.content, 0, buf, 0, count); + } + + public byte[] directBytes() { + return content; + } + + public int find(int offset, char value) { + return find(offset, (byte) value); + } + + public int find(int offset, byte value) { + return find(offset, -1, value); + } + + public int find(int offset, int limit, char value) { + return find(offset, limit, (byte) value); + } + + public int find(int offset, int limit, byte value) { + byte[] bytes = this.content; + int end = limit > 0 ? limit : count; + for (int i = offset; i < end; i++) { + if (bytes[i] == value) return i; + } + return -1; + } + + public void removeLastByte() { + if (count > 0) count--; + } + + public void addInt(int value) { + add((byte) (value >> 24 & 0xFF), (byte) (value >> 16 & 0xFF), (byte) (value >> 8 & 0xFF), (byte) (value & 0xFF)); + } + + public void add(byte value) { + if (count >= content.length - 1) { + byte[] ns = new byte[content.length + 8]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + content[count++] = value; + } + + public void add(byte... values) { + if (count >= content.length - values.length) { + byte[] ns = new byte[content.length + values.length]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + System.arraycopy(content, count, values, 0, values.length); + count += values.length; + } + + public void add(ByteBuffer buffer, int len) { + if (len < 1) return; + if (count >= content.length - len) { + byte[] ns = new byte[content.length + len]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + buffer.get(content, count, len); + count += len; + } + + @Override + public String toString() { + return new String(content, 0, count); + } + + public String toString(final Charset charset) { + return toString(0, count, charset); + } + + public String toString(final int offset, int len, final Charset charset) { + if (charset == null) return new String(Utility.decodeUTF8(content, offset, len)); + return new String(content, offset, len, charset); + } + + public String toDecodeString(final int offset, int len, final Charset charset) { + int index = offset; + for (int i = offset; i < (offset + len); i++) { + if (content[i] == '+') { + content[index] = ' '; + } else if (content[i] == '%') { + content[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); + } else { + content[index] = content[i]; + } + index++; + } + for (int i = index + 1; i < (offset + len); i++) { + content[i] = ' '; + } + len = index - offset; + if (charset == null) return new String(Utility.decodeUTF8(content, offset, len)); + return new String(content, offset, len, charset); + } + + private static int hexBit(byte b) { + if ('0' <= b && '9' >= b) return b - '0'; + if ('a' <= b && 'z' >= b) return b - 'a' + 10; + if ('A' <= b && 'Z' >= b) return b - 'A' + 10; + return b; + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/util/ConstructorProperties.java b/android-jdk6-redkale/src/org/redkale/util/ConstructorProperties.java new file mode 100644 index 000000000..a6b9010a8 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/ConstructorProperties.java @@ -0,0 +1,24 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * + * @author zhangjx + */ +@Documented @Target(CONSTRUCTOR) @Retention(RUNTIME) +public @interface ConstructorProperties { + /** +

The getter names.

+ @return the getter names corresponding to the parameters in the + annotated constructor. + */ + String[] value(); +} diff --git a/android-jdk6-redkale/src/org/redkale/util/Creator.java b/android-jdk6-redkale/src/org/redkale/util/Creator.java new file mode 100644 index 000000000..2c8adff43 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/Creator.java @@ -0,0 +1,210 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.lang.reflect.*; +import java.util.*; +import org.objectweb.asm.*; +import static org.objectweb.asm.Opcodes.*; +import org.objectweb.asm.Type; + +/** + * 实现一个类的构造方法。 代替低效的反射实现方式。 + * + * @author zhangjx + * @param + */ +public interface Creator { +// +// static class PooledCreator implements Creator { +// +// private final T defValue; +// +// private final Reproduce reproduce; +// +// private final ReferenceQueue refQueue = new ReferenceQueue(); +// +// private final Queue queue; +// +// private final Creator creator; +// +// public PooledCreator(int max, Class clazz, Creator creator) { +// this.creator = creator; +// this.defValue = creator.create(); +// this.reproduce = Reproduce.create(clazz, clazz); +// this.queue = new ArrayBlockingQueue<>(Math.max(Runtime.getRuntime().availableProcessors() * 2, max)); +// new Thread() { +// { +// setDaemon(true); +// setName(PooledCreator.class.getSimpleName() + " " + clazz.getSimpleName() + " Reference Handler"); +// } +// +// @Override +// public void run() { +// try { +// for (;;) { +// T r = refQueue.remove().get(); +// if (r == null) continue; +// reproduce.copy(r, defValue); +// queue.offer(r); +// } +// } catch (Exception e) { +// //do nothind +// } +// } +// }.start(); +// } +// +// @Override +// public T create(Object... params) { +// T rs = queue.poll(); +// if (rs == null) { +// rs = creator.create(params); +// } +// return new WeakReference<>(rs, refQueue).get(); +// } +// +// } +// +// @SuppressWarnings("unchecked") +// public static Creator create(int max, Class clazz) { +// return new PooledCreator<>(max, clazz, create(clazz)); +// } +// +// @SuppressWarnings("unchecked") +// public static Creator create(int max, Class clazz, Creator creator) { +// return new PooledCreator<>(max, clazz, creator); +// } + + public T create(Object... params); + + public static final class Creators { + + @SuppressWarnings("unchecked") + public static Creator create(Class clazz) { + if (clazz.isAssignableFrom(ArrayList.class)) { + clazz = (Class) ArrayList.class; + } else if (clazz.isAssignableFrom(HashMap.class)) { + clazz = (Class) HashMap.class; + } else if (clazz.isAssignableFrom(HashSet.class)) { + clazz = (Class) HashSet.class; + } + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { + throw new RuntimeException("[" + clazz + "] is a interface or abstract class, cannot create it's Creator."); + } + final String supDynName = Creator.class.getName().replace('.', '/'); + final String interName = clazz.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(clazz); + ClassLoader loader = Creator.class.getClassLoader(); + String newDynName = supDynName + "_" + clazz.getSimpleName() + "_" + (System.currentTimeMillis() % 10000); + if (String.class.getClassLoader() != clazz.getClassLoader()) { + loader = clazz.getClassLoader(); + newDynName = interName + "_Dyn" + Creator.class.getSimpleName(); + } + try { + return (Creator) Class.forName(newDynName.replace('/', '.')).newInstance(); + } catch (Exception ex) { + } + Constructor constructor = null; + for (Constructor c : clazz.getConstructors()) { + if (c.getParameterTypes().length == 0) { + constructor = c; + break; + } + } + if (constructor == null) { + for (Constructor c : clazz.getConstructors()) { + if (c.getAnnotation(ConstructorProperties.class) != null) { + constructor = c; + break; + } + } + } + if (constructor == null) throw new RuntimeException("[" + clazz + "] have no public or java.beans.ConstructorProperties-Annotation constructor."); + //------------------------------------------------------------- + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + ">;", "java/lang/Object", new String[]{supDynName}); + + {//构造方法 + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + ConstructorProperties cps = constructor.getAnnotation(ConstructorProperties.class); + if (cps != null) { + av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true); + AnnotationVisitor av1 = av0.visitArray("value"); + for (String n : cps.value()) { + av1.visit(null, n); + } + av1.visitEnd(); + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + {//create 方法 + mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null); + mv.visitTypeInsn(NEW, interName); + mv.visitInsn(DUP); + //--------------------------------------- + final Class[] params = constructor.getParameterTypes(); + { + + final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5}; + for (int i = 0; i < params.length; i++) { + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else { + mv.visitIntInsn(BIPUSH, i); + } + mv.visitInsn(AALOAD); + Class ct = params[i]; + mv.visitTypeInsn(CHECKCAST, Type.getInternalName(ct)); + if (ct.isPrimitive()) { + Class fct = Array.get(Array.newInstance(ct, 1), 0).getClass(); + try { + Method pm = ct.getMethod(ct.getSimpleName() + "Value"); + mv.visitMethodInsn(INVOKEVIRTUAL, fct.getName().replace('.', '/'), pm.getName(), Type.getMethodDescriptor(pm), false); + } catch (Exception ex) { + throw new RuntimeException(ex); //不可能会发生 + } + } + } + } + //--------------------------------------- + mv.visitMethodInsn(INVOKESPECIAL, interName, "", Type.getConstructorDescriptor(constructor), false); + mv.visitInsn(ARETURN); + mv.visitMaxs((params.length > 0 ? (params.length + 3) : 2), 2); + mv.visitEnd(); + } + { //虚拟 create 方法 + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, "create", "([Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "create", "([Ljava/lang/Object;)" + interDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class creatorClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + try { + return (Creator) creatorClazz.newInstance(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/DLong.java b/android-jdk6-redkale/src/org/redkale/util/DLong.java new file mode 100644 index 000000000..6d5351f0e --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/DLong.java @@ -0,0 +1,81 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +/** + * + * @author zhangjx + */ +public final class DLong extends Number implements Comparable { + + private final long first; + + private final long second; + + public DLong(long one, long two) { + this.first = one; + this.second = two; + } + + public long getFirst() { + return first; + } + + public long getSecond() { + return second; + } + + public boolean equals(long one, long two) { + return this.first == one && this.second == two; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final DLong other = (DLong) obj; + return (this.first == other.first && this.second == other.second); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 89 * hash + (int) (this.first ^ (this.first >>> 32)); + hash = 89 * hash + (int) (this.second ^ (this.second >>> 32)); + return hash; + } + + @Override + public String toString() { + return this.first + "_" + this.second; + } + + @Override + public int intValue() { + return (int) longValue(); + } + + @Override + public long longValue() { + return first ^ second; + } + + @Override + public float floatValue() { + return (float) longValue(); + } + + @Override + public double doubleValue() { + return (double) longValue(); + } + + @Override + public int compareTo(DLong o) { + return (int) (first == o.first ? (second - o.second) : (first - o.first)); + } + +} diff --git a/android-jdk6-redkale/src/org/redkale/util/DebugMethodVisitor.java b/android-jdk6-redkale/src/org/redkale/util/DebugMethodVisitor.java new file mode 100644 index 000000000..e58f8823e --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/DebugMethodVisitor.java @@ -0,0 +1,143 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.util.*; +import org.objectweb.asm.*; + +/** + * + * @author zhangjx + */ +public class DebugMethodVisitor { + + private final MethodVisitor visitor; + + private boolean debug = false; + + public void setDebug(boolean d) { + debug = d; + } + + private final Map labels = new LinkedHashMap(); + + private static final String[] opcodes = new String[200]; //0 -18 + + static { + try { + for (java.lang.reflect.Field field : Opcodes.class.getFields()) { + String name = field.getName(); + if (name.startsWith("ASM")) continue; + if (name.startsWith("V1_")) continue; + if (name.startsWith("ACC_")) continue; + if (name.startsWith("T_")) continue; + if (name.startsWith("H_")) continue; + if (name.startsWith("F_")) continue; + if (field.getType() != int.class) continue; + opcodes[(int) (Integer) field.get(null)] = name; + } + } catch (Exception ex) { + throw new RuntimeException(ex); //不可能会发生 + } + } + + public DebugMethodVisitor(MethodVisitor visitor) { + //super(Opcodes.ASM5, visitor); + this.visitor = visitor; + } + + public AnnotationVisitor visitAnnotation(String desc, boolean flag) { + AnnotationVisitor av = visitor.visitAnnotation(desc, flag); + if (debug) System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");"); + return av; + } + + public void visitParameter(String name, int access) { + visitor.visitParameter(name, access); + if (debug) System.out.println("mv.visitParameter(" + name + ", " + access + ");"); + } + + public void visitVarInsn(int opcode, int var) { + visitor.visitVarInsn(opcode, var); + if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); + } + + public void visitJumpInsn(int opcode, Label var) { //调用次方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建 + visitor.visitJumpInsn(opcode, var); + if (debug) { + Integer index = labels.get(var); + if (index == null) { + index = labels.size(); + labels.put(var, index); + System.out.println("Label l" + index + " = new Label();"); + } + System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");"); + } + } + + public void visitCode() { + visitor.visitCode(); + if (debug) System.out.println("mv.visitCode();"); + } + + public void visitLabel(Label var) { + visitor.visitLabel(var); + if (debug) { + Integer index = labels.get(var); + if (index == null) { + index = labels.size(); + labels.put(var, index); + System.out.println("Label l" + index + " = new Label();"); + } + System.out.println("mv.visitLabel(l" + index + ");"); + } + } + + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + visitor.visitMethodInsn(opcode, owner, name, desc, itf); + if (debug) System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\", " + itf + ");"); + } + + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + visitor.visitFieldInsn(opcode, owner, name, desc); + if (debug) System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\");"); + } + + public void visitTypeInsn(int opcode, String type) { + visitor.visitTypeInsn(opcode, type); + if (debug) System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");"); + } + + public void visitInsn(int opcode) { + visitor.visitInsn(opcode); + if (debug) System.out.println("mv.visitInsn(" + opcodes[opcode] + ");"); + } + + public void visitIntInsn(int opcode, int value) { + visitor.visitIntInsn(opcode, value); + if (debug) System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");"); + } + + public void visitIincInsn(int opcode, int value) { + visitor.visitIincInsn(opcode, value); + if (debug) System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");"); + } + + public void visitLdcInsn(Object o) { + visitor.visitLdcInsn(o); + if (debug) System.out.println("mv.visitLdcInsn(" + o + ");"); + } + + public void visitMaxs(int maxStack, int maxLocals) { + visitor.visitMaxs(maxStack, maxLocals); + if (debug) System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");"); + } + + public void visitEnd() { + visitor.visitEnd(); + if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n"); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/ObjectPool.java b/android-jdk6-redkale/src/org/redkale/util/ObjectPool.java new file mode 100644 index 000000000..8b601f3f3 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/ObjectPool.java @@ -0,0 +1,100 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import org.redkale.util.Creator.Creators; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; + +/** + * + * @author zhangjx + * @param + */ +public final class ObjectPool implements Supplier { + + private static final Logger logger = Logger.getLogger(ObjectPool.class.getSimpleName()); + + private final boolean debug; + + private final Queue queue; + + private Creator creator; + + private final Consumer prepare; + + private final Predicate recycler; + + private final AtomicLong creatCounter; + + private final AtomicLong cycleCounter; + + public ObjectPool(Class clazz, Consumer prepare, Predicate recycler) { + this(2, clazz, prepare, recycler); + } + + public ObjectPool(int max, Class clazz, Consumer prepare, Predicate recycler) { + this(max, Creators.create(clazz), prepare, recycler); + } + + public ObjectPool(Creator creator, Consumer prepare, Predicate recycler) { + this(2, creator, prepare, recycler); + } + + public ObjectPool(int max, Creator creator, Consumer prepare, Predicate recycler) { + this(null, null, max, creator, prepare, recycler); + } + + public ObjectPool(AtomicLong creatCounter, AtomicLong cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { + this.creatCounter = creatCounter; + this.cycleCounter = cycleCounter; + this.creator = creator; + this.prepare = prepare; + this.recycler = recycler; + this.queue = new ArrayBlockingQueue(Math.max(Runtime.getRuntime().availableProcessors() * 2, max)); + this.debug = logger.isLoggable(Level.FINER); + } + + public void setCreator(Creator creator) { + this.creator = creator; + } + + @Override + public T get() { + T result = queue.poll(); + if (result == null) { + if (creatCounter != null) creatCounter.incrementAndGet(); + result = this.creator.create(); + } + if (prepare != null) prepare.accept(result); + return result; + } + + public void offer(final T e) { + if (e != null && recycler.test(e)) { + if (cycleCounter != null) cycleCounter.incrementAndGet(); + if (debug) { + for (T t : queue) { + if (t == e) { + logger.log(Level.WARNING, "[" + Thread.currentThread().getName() + "] repeat offer the same object(" + e + ")", new Exception()); + return; + } + } + } + queue.offer(e); + } + } + + public long getCreatCount() { + return creatCounter.longValue(); + } + + public long getCycleCount() { + return cycleCounter.longValue(); + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/Sheet.java b/android-jdk6-redkale/src/org/redkale/util/Sheet.java new file mode 100644 index 000000000..7aeeadae4 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/Sheet.java @@ -0,0 +1,87 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.util.*; + +/** + * + * @author zhangjx + * @param + */ +@SuppressWarnings("unchecked") +public class Sheet implements java.io.Serializable { + + private long total = -1; + + private Collection rows; + + public Sheet() { + super(); + } + + public Sheet(int total, Collection data) { + this((long) total, data); + } + + public Sheet(long total, Collection data) { + this.total = total; + this.rows = (Collection) data; + } + + public static Sheet asSheet(Collection data) { + return data == null ? new Sheet() : new Sheet(data.size(), data); + } + + public void copyTo(Sheet copy) { + if (copy == null) return; + copy.total = this.total; + if (this.getRows() != null) { + copy.setRows(new ArrayList(this.getRows())); + } else { + copy.rows = null; + } + } + + /** + * 判断数据列表是否为空 + * + * @return + */ + public boolean isEmpty() { + return this.rows == null || this.rows.isEmpty(); + } + + @Override + public String toString() { + return "Sheet[total=" + this.total + ", rows=" + this.rows + "]"; + } + + public long getTotal() { + return this.total; + } + + public void setTotal(long total) { + this.total = total; + } + + public Collection getRows() { + return this.rows; + } + + public List list() { + return list(false); + } + + public List list(boolean created) { + if (this.rows == null) return created ? new ArrayList() : null; + return (this.rows instanceof List) ? (List) this.rows : new ArrayList(this.rows); + } + + public void setRows(Collection data) { + this.rows = (Collection) data; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/TypeToken.java b/android-jdk6-redkale/src/org/redkale/util/TypeToken.java new file mode 100644 index 000000000..38646454e --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/TypeToken.java @@ -0,0 +1,26 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * + * @author zhangjx + * @param + */ +public abstract class TypeToken { + + private final Type type; + + public TypeToken() { + type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + } + + public final Type getType() { + return type; + } +} diff --git a/android-jdk6-redkale/src/org/redkale/util/Utility.java b/android-jdk6-redkale/src/org/redkale/util/Utility.java new file mode 100644 index 000000000..61833c987 --- /dev/null +++ b/android-jdk6-redkale/src/org/redkale/util/Utility.java @@ -0,0 +1,470 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.io.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.charset.*; +import java.util.*; +import javax.net.ssl.*; + +/** + * + * @author zhangjx + */ +public final class Utility { + + private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL"; + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + private static final char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + private static final javax.net.ssl.SSLContext DEFAULTSSL_CONTEXT; + + static { + + try { + DEFAULTSSL_CONTEXT = javax.net.ssl.SSLContext.getInstance("SSL"); + DEFAULTSSL_CONTEXT.init(null, new javax.net.ssl.TrustManager[]{new javax.net.ssl.X509TrustManager() { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { + } + }}, null); + } catch (Exception e) { + throw new RuntimeException(e); //不可能会发生 + } + } + + private Utility() { + } + + public static String now() { + return String.format(format, System.currentTimeMillis()); + } + + public static void println(String string, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) return; + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + buffer.flip(); + println(string, bytes); + } + + public static void println(String string, byte... bytes) { + if (bytes == null) return; + StringBuilder sb = new StringBuilder(); + if (string != null) sb.append(string); + sb.append(bytes.length).append(".["); + boolean last = false; + for (byte b : bytes) { + if (last) sb.append(','); + int v = b & 0xff; + if (v < 16) sb.append('0'); + sb.append(Integer.toHexString(v)); + last = true; + } + sb.append(']'); + (System.out).println(sb); + } + + /** + * 返回本机的第一个内网IPv4地址, 没有则返回null + *

+ * @return + */ + public static InetAddress localInetAddress() { + InetAddress back = null; + try { + Enumeration nifs = NetworkInterface.getNetworkInterfaces(); + while (nifs.hasMoreElements()) { + NetworkInterface nif = nifs.nextElement(); + if (!nif.isUp()) continue; + Enumeration eis = nif.getInetAddresses(); + while (eis.hasMoreElements()) { + InetAddress ia = eis.nextElement(); + if (ia.isLoopbackAddress()) back = ia; + if (ia.isSiteLocalAddress()) return ia; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return back; + } + + public static String binToHexString(byte[] bytes) { + return new String(binToHex(bytes)); + } + + public static char[] binToHex(byte[] bytes) { + return binToHex(bytes, 0, bytes.length); + } + + public static String binToHexString(byte[] bytes, int offset, int len) { + return new String(binToHex(bytes, offset, len)); + } + + public static char[] binToHex(byte[] bytes, int offset, int len) { + final char[] sb = new char[len * 2]; + final int end = offset + len; + int index = 0; + final char[] hexs = hex; + for (int i = offset; i < end; i++) { + byte b = bytes[i]; + sb[index++] = (hexs[((b >> 4) & 0xF)]); + sb[index++] = hexs[((b) & 0xF)]; + } + return sb; + } + + public static byte[] hexToBin(CharSequence src) { + return hexToBin(src, 0, src.length()); + } + + public static byte[] hexToBin(CharSequence src, int offset, int len) { + final int size = (len + 1) / 2; + final byte[] bytes = new byte[size]; + final int end = offset + len; + String digits = "0123456789abcdef"; + for (int i = 0; i < size; i++) { + int ch1 = src.charAt(offset + i * 2); + if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a'; + int ch2 = src.charAt(offset + i * 2 + 1); + if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a'; + int pos1 = digits.indexOf(ch1); + if (pos1 < 0) throw new NumberFormatException(); + int pos2 = digits.indexOf(ch2); + if (pos2 < 0) throw new NumberFormatException(); + bytes[i] = (byte) (pos1 * 0x10 + pos2); + } + return bytes; + } + + public static byte[] hexToBin(char[] src) { + return hexToBin(src, 0, src.length); + } + + public static byte[] hexToBin(char[] src, int offset, int len) { + final int size = (len + 1) / 2; + final byte[] bytes = new byte[size]; + final int end = offset + len; + String digits = "0123456789abcdef"; + for (int i = 0; i < size; i++) { + int ch1 = src[offset + i * 2]; + if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a'; + int ch2 = src[offset + i * 2 + 1]; + if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a'; + int pos1 = digits.indexOf(ch1); + if (pos1 < 0) throw new NumberFormatException(); + int pos2 = digits.indexOf(ch2); + if (pos2 < 0) throw new NumberFormatException(); + bytes[i] = (byte) (pos1 * 0x10 + pos2); + } + return bytes; + } + + //----------------------------------------------------------------------------- + public static char[] decodeUTF8(final byte[] array) { + return decodeUTF8(array, 0, array.length); + } + + public static char[] decodeUTF8(final byte[] array, final int start, final int len) { + byte b; + int size = len; + final byte[] bytes = array; + final int limit = start + len; + for (int i = start; i < limit; i++) { + b = bytes[i]; + if ((b >> 5) == -2) { + size--; + } else if ((b >> 4) == -2) { + size -= 2; + } + } + final char[] text = new char[size]; + size = 0; + for (int i = start; i < limit;) { + b = bytes[i++]; + if (b >= 0) { + text[size++] = (char) b; + } else if ((b >> 5) == -2) { + text[size++] = (char) (((b << 6) ^ bytes[i++]) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80))); + } else if ((b >> 4) == -2) { + text[size++] = (char) ((b << 12) ^ (bytes[i++] << 6) ^ (bytes[i++] ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); + } + } + return text; + } + + public static byte[] encodeUTF8(final String value) { + if (value == null) return new byte[0]; + return encodeUTF8(value.toCharArray()); + } + + public static byte[] encodeUTF8(final char[] array) { + return encodeUTF8(array, 0, array.length); + } + + public static byte[] encodeUTF8(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chars = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chars[i]; + if (c < 0x80) { + size++; + } else if (c < 0x800) { + size += 2; + } else { + size += 3; + } + } + final byte[] bytes = new byte[size]; + size = 0; + for (int i = start; i < limit; i++) { + c = chars[i]; + if (c < 0x80) { + bytes[size++] = (byte) c; + } else if (c < 0x800) { + bytes[size++] = (byte) (0xc0 | (c >> 6)); + bytes[size++] = (byte) (0x80 | (c & 0x3f)); + } else { + bytes[size++] = (byte) (0xe0 | ((c >> 12))); + bytes[size++] = (byte) (0x80 | ((c >> 6) & 0x3f)); + bytes[size++] = (byte) (0x80 | (c & 0x3f)); + } + } + return bytes; + } + + public static char[] charArray(String value) { + return value == null ? null : value.toCharArray(); + } + + public static char[] charArray(StringBuilder value) { + if (value == null) return null; + char[] chs = new char[value.length()]; + value.getChars(0, value.length(), chs, 0); + return chs; + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] array) { + return encodeUTF8(buffer, array, 0, array.length); + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] array) { + return encodeUTF8(buffer, bytesLength, array, 0, array.length); + } + + public static int encodeUTF8Length(String value) { + if (value == null) return -1; + return encodeUTF8Length(value.toCharArray()); + } + + public static int encodeUTF8Length(final char[] text) { + return encodeUTF8Length(text, 0, text.length); + } + + public static int encodeUTF8Length(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chars = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chars[i]; + size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3)); + } + return size; + } + + /** + * 将两个数字组装成一个long + *

+ * @param high + * @param low + * @return + */ + public static long merge(long high, long low) { + return high << 32 | low; + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] text, final int start, final int len) { + return encodeUTF8(buffer, encodeUTF8Length(text, start, len), text, start, len); + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] text, final int start, final int len) { + char c; + char[] chars = text; + final int limit = start + len; + int remain = buffer.remaining(); + final ByteBuffer buffer2 = remain >= bytesLength ? null : ByteBuffer.allocate(bytesLength - remain + 3); //最差情况buffer最后两byte没有填充 + ByteBuffer buf = buffer; + for (int i = start; i < limit; i++) { + c = chars[i]; + if (c < 0x80) { + if (buf.remaining() < 1) buf = buffer2; + buf.put((byte) c); + } else if (c < 0x800) { + if (buf.remaining() < 2) buf = buffer2; + buf.put((byte) (0xc0 | (c >> 6))); + buf.put((byte) (0x80 | (c & 0x3f))); + } else { + if (buf.remaining() < 3) buf = buffer2; + buf.put((byte) (0xe0 | ((c >> 12)))); + buf.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buf.put((byte) (0x80 | (c & 0x3f))); + } + } + if (buffer2 != null) buffer2.flip(); + return buffer2; + } + + //----------------------------------------------------------------------------- + public static javax.net.ssl.SSLContext getDefaultSSLContext() { + return DEFAULTSSL_CONTEXT; + } + + public static Socket createDefaultSSLSocket(InetSocketAddress address) throws IOException { + return createDefaultSSLSocket(address.getAddress(), address.getPort()); + } + + public static Socket createDefaultSSLSocket(InetAddress host, int port) throws IOException { + Socket socket = DEFAULTSSL_CONTEXT.getSocketFactory().createSocket(host, port); + + return socket; + } + + public static String postHttpContent(String url) throws IOException { + return remoteHttpContent(null, "POST", url, null, null).toString("UTF-8"); + } + + public static String postHttpContent(String url, String body) throws IOException { + return remoteHttpContent(null, "POST", url, null, body).toString("UTF-8"); + } + + public static String postHttpContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent(null, "POST", url, headers, body).toString("UTF-8"); + } + + public static String postHttpContent(SSLContext ctx, String url) throws IOException { + return remoteHttpContent(ctx, "POST", url, null, null).toString("UTF-8"); + } + + public static String postHttpContent(SSLContext ctx, String url, String body) throws IOException { + return remoteHttpContent(ctx, "POST", url, null, body).toString("UTF-8"); + } + + public static String postHttpContent(SSLContext ctx, String url, Map headers, String body) throws IOException { + return remoteHttpContent(ctx, "POST", url, headers, body).toString("UTF-8"); + } + + public static byte[] postHttpBytesContent(String url) throws IOException { + return remoteHttpContent(null, "POST", url, null, null).toByteArray(); + } + + public static byte[] postHttpBytesContent(SSLContext ctx, String url) throws IOException { + return remoteHttpContent(ctx, "POST", url, null, null).toByteArray(); + } + + public static byte[] postHttpBytesContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent(null, "POST", url, headers, body).toByteArray(); + } + + public static byte[] postHttpBytesContent(SSLContext ctx, String url, Map headers, String body) throws IOException { + return remoteHttpContent(ctx, "POST", url, headers, body).toByteArray(); + } + + public static String getHttpContent(String url) throws IOException { + return remoteHttpContent(null, "GET", url, null, null).toString("UTF-8"); + } + + public static String getHttpContent(SSLContext ctx, String url) throws IOException { + return remoteHttpContent(ctx, "GET", url, null, null).toString("UTF-8"); + } + + public static String getHttpContent(SSLContext ctx, String url, Map headers, String body) throws IOException { + return remoteHttpContent(ctx, "GET", url, headers, body).toString("UTF-8"); + } + + public static String getHttpContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent(null, "GET", url, headers, body).toString("UTF-8"); + } + + public static byte[] getHttpBytesContent(String url) throws IOException { + return remoteHttpContent(null, "GET", url, null, null).toByteArray(); + } + + public static byte[] getHttpBytesContent(SSLContext ctx, String url) throws IOException { + return remoteHttpContent(ctx, "GET", url, null, null).toByteArray(); + } + + public static byte[] getHttpBytesContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent(null, "GET", url, headers, body).toByteArray(); + } + + public static byte[] getHttpBytesContent(SSLContext ctx, String url, Map headers, String body) throws IOException { + return remoteHttpContent(ctx, "GET", url, headers, body).toByteArray(); + } + + protected static ByteArrayOutputStream remoteHttpContent(SSLContext ctx, String method, String url, Map headers, String body) throws IOException { + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setConnectTimeout(3000); + conn.setReadTimeout(3000); + if (conn instanceof HttpsURLConnection) ((HttpsURLConnection) conn).setSSLSocketFactory((ctx == null ? DEFAULTSSL_CONTEXT : ctx).getSocketFactory()); + conn.setRequestMethod(method); + if (headers != null) { + for (Map.Entry en : headers.entrySet()) { + conn.setRequestProperty(en.getKey(), en.getValue()); + } + } + if (body != null) { + conn.setDoInput(true); + conn.setDoOutput(true); + conn.getOutputStream().write(body.getBytes(UTF_8)); + } + conn.connect(); + int rs = conn.getResponseCode(); + if (rs == 301 || rs == 302) { + String newurl = conn.getHeaderField("Location"); + conn.disconnect(); + return remoteHttpContent(ctx, method, newurl, headers, body); + } + InputStream in = conn.getInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] bytes = new byte[1024]; + int pos; + while ((pos = in.read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + conn.disconnect(); + return out; + } + + public static String read(InputStream in) throws IOException { + return read(in, "UTF-8"); + } + + public static String read(InputStream in, String charsetName) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] bytes = new byte[1024]; + int pos; + while ((pos = in.read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + return charsetName == null ? out.toString() : out.toString(charsetName); + } +}