├── .editorconfig
├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── TODO.md
├── doc
├── img
│ ├── large.png
│ ├── medium.png
│ ├── small.png
│ ├── smartbuf-packet.png
│ └── smartbuf-stream.png
└── index_zh.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── github
│ └── smartbuf
│ ├── SmartBuf.java
│ ├── SmartPacket.java
│ ├── SmartStream.java
│ ├── Type.java
│ ├── converter
│ ├── BeanInfo.java
│ ├── Codec.java
│ ├── CodecFactory.java
│ ├── Converter.java
│ ├── ConverterMap.java
│ ├── ConverterMethod.java
│ ├── ConverterPipeline.java
│ ├── RealConverterMethod.java
│ ├── TranConverterMethod.java
│ └── codec
│ │ ├── ArrayCodec.java
│ │ ├── AtomicCodec.java
│ │ ├── AwtCodec.java
│ │ ├── BufferCodec.java
│ │ ├── CollectionCodec.java
│ │ ├── IOCodec.java
│ │ ├── JavaxCodec.java
│ │ ├── JodaCodec.java
│ │ ├── LangCodec.java
│ │ ├── MapCodec.java
│ │ ├── MathCodec.java
│ │ ├── NetCodec.java
│ │ ├── NumberCodec.java
│ │ ├── PrimaryCodec.java
│ │ ├── ReferenceCodec.java
│ │ ├── SqlCodec.java
│ │ ├── StringCodec.java
│ │ ├── ThrowableCodec.java
│ │ ├── TimeCodec.java
│ │ └── UtilCodec.java
│ ├── exception
│ ├── CircleReferenceException.java
│ ├── InvalidDataException.java
│ ├── InvalidStructException.java
│ ├── InvalidVersionException.java
│ ├── MismatchModeException.java
│ ├── NoShortestPipelineException.java
│ ├── OutOfSpaceException.java
│ ├── SmartBufClosedException.java
│ ├── UnexpectedReadException.java
│ └── UnexpectedSequenceException.java
│ ├── node
│ ├── Node.java
│ ├── NodeCodec.java
│ ├── NodeType.java
│ ├── array
│ │ ├── ArrayNode.java
│ │ ├── BooleanArrayNode.java
│ │ ├── ByteArrayNode.java
│ │ ├── DoubleArrayNode.java
│ │ ├── FloatArrayNode.java
│ │ ├── IntArrayNode.java
│ │ ├── LongArrayNode.java
│ │ └── ShortArrayNode.java
│ └── basic
│ │ ├── BooleanNode.java
│ │ ├── DoubleNode.java
│ │ ├── FloatNode.java
│ │ ├── ObjectNode.java
│ │ ├── StringNode.java
│ │ ├── SymbolNode.java
│ │ └── VarintNode.java
│ ├── reflect
│ ├── BeanField.java
│ ├── BeanReader.java
│ ├── BeanReaderBuilder.java
│ ├── BeanWriter.java
│ ├── BeanWriterBuilder.java
│ ├── TypeRef.java
│ ├── XField.java
│ ├── XType.java
│ ├── XTypeFactory.java
│ └── XTypeUtils.java
│ ├── transport
│ ├── Array.java
│ ├── Const.java
│ ├── IDAllocator.java
│ ├── Input.java
│ ├── InputBuffer.java
│ ├── InputDataPool.java
│ ├── InputMetaPool.java
│ ├── Output.java
│ ├── OutputBuffer.java
│ ├── OutputDataPool.java
│ └── OutputMetaPool.java
│ └── utils
│ ├── ASMUtils.java
│ ├── ArrayUtils.java
│ ├── CodecUtils.java
│ ├── NumberUtils.java
│ ├── ReflectUtils.java
│ ├── TimeUtils.java
│ └── UTF8Utils.java
└── test
├── java
└── com
│ └── github
│ └── smartbuf
│ ├── SmartPacketTest.java
│ ├── SmartStreamTest.java
│ ├── World.java
│ ├── benchmark
│ ├── Runner.java
│ ├── TestBenchmark.java
│ ├── large
│ │ ├── Large.java
│ │ ├── LargeDeserBenchmark.java
│ │ ├── LargeSerialBenchmark.java
│ │ ├── LargeTest.java
│ │ └── TrendModel.java
│ ├── medium
│ │ ├── Medium.java
│ │ ├── MediumDeserBenchmark.java
│ │ ├── MediumSerialBenchmark.java
│ │ ├── MediumTest.java
│ │ └── UserModel.java
│ ├── small
│ │ ├── Small.java
│ │ ├── SmallDeserBenchmark.java
│ │ ├── SmallSerialBenchmark.java
│ │ ├── SmallTest.java
│ │ └── UserModel.java
│ └── tiny
│ │ ├── Tiny.java
│ │ └── TinyTest.java
│ ├── converter
│ ├── CodecFactoryTest.java
│ ├── CodecTest.java
│ ├── ConverterMapTest.java
│ ├── ConverterMethodTest.java
│ ├── ConverterPipelineTest.java
│ └── codec
│ │ ├── ArrayCodecTest.java
│ │ ├── AtomicCodecTest.java
│ │ ├── AwtCodecTest.java
│ │ ├── BufferCodecTest.java
│ │ ├── CollectionCodecTest.java
│ │ ├── IOCodecTest.java
│ │ ├── JavaxCodecTest.java
│ │ ├── JodaCodecTest.java
│ │ ├── LangCodecTest.java
│ │ ├── MapCodecTest.java
│ │ ├── MathCodecTest.java
│ │ ├── NetCodecTest.java
│ │ ├── NumberCodecTest.java
│ │ ├── PrimaryCodecTest.java
│ │ ├── ReferenceCodecTest.java
│ │ ├── SqlCodecTest.java
│ │ ├── StringCodecTest.java
│ │ ├── ThrowableCodecTest.java
│ │ ├── TimeCodecTest.java
│ │ └── UtilCodecTest.java
│ ├── model
│ └── MessageOuterClass.java
│ ├── node
│ ├── NodeCodecTest.java
│ └── NodeTest.java
│ ├── reflect
│ ├── BeanReaderBenchmark.java
│ ├── BeanReaderBuilderTest.java
│ ├── BeanReaderTest.java
│ ├── BeanWriterBuilderTest.java
│ ├── BeanWriterTest.java
│ ├── GenericModel.java
│ ├── TypeRefTest.java
│ ├── TypeTest.java
│ ├── XTypeFactoryTest.java
│ ├── XTypeTest.java
│ └── XTypeUtilsTest.java
│ ├── transport
│ ├── ArrayTest.java
│ ├── BufferTest.java
│ ├── DataPoolTest.java
│ ├── IDAllocatorTest.java
│ ├── IOArrayTest.java
│ ├── IOExpireTest.java
│ ├── IOFullTest.java
│ ├── IOObjectTest.java
│ ├── IOSliceTest.java
│ ├── IOTest.java
│ ├── MetaPoolTest.java
│ └── OutputTest.java
│ └── utils
│ ├── ASMUtilsTest.java
│ ├── ArrayUtilsTest.java
│ ├── NumberUtilsTest.java
│ ├── ReflectUtilsTest.java
│ ├── TimeUtilsTest.java
│ └── UTF8UtilsTest.java
└── resources
├── large.json
├── logback.xml
└── proto
├── large.proto
├── medium.proto
├── message.proto
├── small.proto
└── tiny.proto
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | end_of_line = lf
4 | indent_style = space
5 | indent_size = 4
6 | insert_final_newline = true
7 |
8 | [*.yml]
9 | indent_size = 2
10 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v1
15 | - name: Set up JDK 1.8
16 | uses: actions/setup-java@v1
17 | with:
18 | java-version: 1.8
19 | - name: Build with Maven
20 | run: mvn -B package --file pom.xml
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 | target/
25 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | sudo: false # faster builds
3 | install: true
4 | script: mvn clean test
5 |
6 | after_success:
7 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | 1. Support self-reference
2 |
--------------------------------------------------------------------------------
/doc/img/large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartbuf/smartbuf-java/c069efc25b376852e377bf4d83d8637d9b354ef6/doc/img/large.png
--------------------------------------------------------------------------------
/doc/img/medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartbuf/smartbuf-java/c069efc25b376852e377bf4d83d8637d9b354ef6/doc/img/medium.png
--------------------------------------------------------------------------------
/doc/img/small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartbuf/smartbuf-java/c069efc25b376852e377bf4d83d8637d9b354ef6/doc/img/small.png
--------------------------------------------------------------------------------
/doc/img/smartbuf-packet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartbuf/smartbuf-java/c069efc25b376852e377bf4d83d8637d9b354ef6/doc/img/smartbuf-packet.png
--------------------------------------------------------------------------------
/doc/img/smartbuf-stream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartbuf/smartbuf-java/c069efc25b376852e377bf4d83d8637d9b354ef6/doc/img/smartbuf-stream.png
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/SmartStream.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf;
2 |
3 | import com.github.smartbuf.reflect.TypeRef;
4 |
5 | import java.io.IOException;
6 |
7 | /**
8 | * SmartStream provides an easy way to use "smartbuf" protocol in stream-mode,
9 | * It's similar to {@link SmartPacket}, but support the context concept.
10 | *
11 | * SmartStream is not thread-safe, you have to use it in single thread and orderly.
12 | * Otherwise, it will go into error.
13 | *
14 | * @author sulin
15 | * @since 2019-10-25 14:40:52
16 | */
17 | public final class SmartStream {
18 |
19 | public final SmartBuf buf;
20 |
21 | /**
22 | * Initialize SmartStream
23 | */
24 | public SmartStream() {
25 | this.buf = new SmartBuf(true);
26 | }
27 |
28 | /**
29 | * Use stream-mode to serialize the specified object into byte[].
30 | *
31 | * @param obj The object need to serialize
32 | * @return Serialization result
33 | * @throws IOException if an I/O error occurs.
34 | */
35 | public byte[] serialize(Object obj) throws IOException {
36 | return buf.write(obj);
37 | }
38 |
39 | /**
40 | * Use stream-mode to deserialize byte[] into an object of the specified class.
41 | *
42 | * @param data Binary data in packet-mode format
43 | * @param tClz The specified class to convert
44 | * @param Template of target class
45 | * @return Deserialization result
46 | * @throws IOException if an I/O error occurs.
47 | */
48 | public T deserialize(byte[] data, Class tClz) throws IOException {
49 | return buf.read(data, tClz);
50 | }
51 |
52 | /**
53 | * Use stream-mode to deserialize byte[] into an object of the specified type,
54 | * could used for supporting generic type.
55 | *
56 | * @param data Binary data in packet-mode format
57 | * @param tRef The specified type to convert
58 | * @param Template of target type
59 | * @return Deserialization result
60 | * @throws IOException if an I/O error occurs.
61 | */
62 | public T deserialize(byte[] data, TypeRef tRef) throws IOException {
63 | return buf.read(data, tRef);
64 | }
65 |
66 | /**
67 | * Close this instance, would close the underlying SmartBuf instance.
68 | */
69 | public void close() {
70 | buf.close();
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/Type.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf;
2 |
3 | import java.util.Collection;
4 |
5 | /**
6 | * Redefine some common data types to use switch replacing if/else
7 | *
8 | * @author sulin
9 | * @since 2019-11-10 12:21:55
10 | */
11 | public enum Type {
12 |
13 | Z,
14 | B,
15 | S,
16 | I,
17 | J,
18 | F,
19 | D,
20 | C,
21 |
22 | BOOLEAN,
23 | BYTE,
24 | SHORT,
25 | INTEGER,
26 | LONG,
27 | FLOAT,
28 | DOUBLE,
29 | CHAR,
30 | STRING,
31 | SYMBOL,
32 |
33 | ARRAY,
34 | ARRAY_BOOL,
35 | ARRAY_BYTE,
36 | ARRAY_SHORT,
37 | ARRAY_INT,
38 | ARRAY_LONG,
39 | ARRAY_FLOAT,
40 | ARRAY_DOUBLE,
41 | ARRAY_CHAR,
42 | COLLECTION,
43 | OBJECT,
44 | UNKNOWN;
45 |
46 | /**
47 | * Get Type instance by the specified class
48 | *
49 | * @param cls Original class
50 | * @return Redefined Type
51 | */
52 | public static Type valueOf(Class> cls) {
53 | if (cls == boolean.class) {
54 | return Z;
55 | } else if (cls == Boolean.class) {
56 | return BOOLEAN;
57 | } else if (cls == float.class) {
58 | return F;
59 | } else if (cls == Float.class) {
60 | return FLOAT;
61 | } else if (cls == double.class) {
62 | return D;
63 | } else if (cls == Double.class) {
64 | return DOUBLE;
65 | } else if (cls == byte.class) {
66 | return B;
67 | } else if (cls == Byte.class) {
68 | return BYTE;
69 | } else if (cls == short.class) {
70 | return S;
71 | } else if (cls == Short.class) {
72 | return SHORT;
73 | } else if (cls == int.class) {
74 | return I;
75 | } else if (cls == Integer.class) {
76 | return INTEGER;
77 | } else if (cls == long.class) {
78 | return J;
79 | } else if (cls == Long.class) {
80 | return LONG;
81 | } else if (cls == char.class) {
82 | return C;
83 | } else if (cls == Character.class) {
84 | return CHAR;
85 | } else if (CharSequence.class.isAssignableFrom(cls)) {
86 | return STRING;
87 | } else if (Enum.class.isAssignableFrom(cls)) {
88 | return SYMBOL;
89 | } else if (Collection.class.isAssignableFrom(cls)) {
90 | return COLLECTION;
91 | } else if (cls.isArray()) {
92 | if (cls == boolean[].class) {
93 | return ARRAY_BOOL;
94 | } else if (cls == byte[].class) {
95 | return ARRAY_BYTE;
96 | } else if (cls == short[].class) {
97 | return ARRAY_SHORT;
98 | } else if (cls == int[].class) {
99 | return ARRAY_INT;
100 | } else if (cls == long[].class) {
101 | return ARRAY_LONG;
102 | } else if (cls == float[].class) {
103 | return ARRAY_FLOAT;
104 | } else if (cls == double[].class) {
105 | return ARRAY_DOUBLE;
106 | } else if (cls == char[].class) {
107 | return ARRAY_CHAR;
108 | } else {
109 | return ARRAY;
110 | }
111 | } else {
112 | return UNKNOWN;
113 | }
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/BeanInfo.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.BeanWriter;
4 |
5 | /**
6 | * BeanInfo helps convert map or objectnode to T
7 | *
8 | * @author sulin
9 | * @since 2019-11-11 17:59:11
10 | */
11 | public final class BeanInfo {
12 |
13 | private final BeanWriter writer;
14 | private final Object[] values;
15 |
16 | public BeanInfo(BeanWriter writer, Object[] values) {
17 | this.writer = writer;
18 | this.values = values;
19 | }
20 |
21 | public BeanWriter getWriter() {
22 | return writer;
23 | }
24 |
25 | public Object[] getValues() {
26 | return values;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/Codec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.XType;
4 |
5 | import java.lang.reflect.Type;
6 |
7 | /**
8 | * Codec's base class.
9 | *
10 | * @author sulin
11 | * @since 2019-05-12 16:01:19
12 | */
13 | public abstract class Codec {
14 |
15 | private CodecFactory factory;
16 |
17 | /**
18 | * Setup {@link CodecFactory} which owns this codec instance.
19 | *
20 | * @param factory The CodecFactory owns this
21 | */
22 | public void setFactory(CodecFactory factory) {
23 | this.factory = factory;
24 | }
25 |
26 | /**
27 | * Proxy of {@link CodecFactory#toXType(Type)}
28 | *
29 | * @param type The original java type
30 | * @return The parsed xtype, which contains generic info
31 | */
32 | protected final XType> toXType(Type type) {
33 | return factory.toXType(type);
34 | }
35 |
36 | /**
37 | * Proxy of {@link CodecFactory#doConvert(Object, XType)}
38 | *
39 | * @param src The source object, could be null
40 | * @param tgtType The target type
41 | * @return New object which is instance of tgtType
42 | */
43 | protected final Object convert(Object src, XType tgtType) {
44 | return factory.doConvert(src, tgtType);
45 | }
46 |
47 | /**
48 | * Proxy of {@link CodecFactory#doConvert(Object, XType)}
49 | *
50 | * @param src The source object, could be null
51 | * @param clz The target java class
52 | * @param clz's template type
53 | * @return new object which is instance of clz
54 | */
55 | @SuppressWarnings("unchecked")
56 | protected final T convert(Object src, Class clz) {
57 | return (T) factory.doConvert(src, toXType(clz));
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/Converter.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | import static java.lang.annotation.ElementType.*;
9 |
10 | /**
11 | * Data converter
12 | *
13 | * @author sulin
14 | * @since 2019-07-11 14:24:09
15 | */
16 | @Documented
17 | @Retention(RetentionPolicy.RUNTIME)
18 | @Target(value = {METHOD})
19 | public @interface Converter {
20 |
21 | /**
22 | * Indicate this converter accept null or not,
23 | * which means null shouldn't be passed into converter.
24 | *
25 | * @return default false
26 | */
27 | boolean nullable() default false;
28 |
29 | /**
30 | * Indicate this converter is extensible or not,
31 | * which means converter support target-class's subclass
32 | *
33 | * @return default false
34 | */
35 | boolean extensible() default false;
36 |
37 | /**
38 | * Indicate this converter's distance, used for dfs.
39 | *
40 | * @return default 100
41 | */
42 | int distance() default 100;
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/ConverterMethod.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.XType;
4 | import lombok.Getter;
5 |
6 | /**
7 | * ConverterMethod represent a method for converting data from srcClass to tgtClass
8 | *
9 | * @author sulin
10 | * @since 2019-08-01 20:41:42
11 | */
12 | @Getter
13 | public abstract class ConverterMethod {
14 |
15 | private final Class> srcClass;
16 | private final Class> tgtClass;
17 |
18 | public ConverterMethod(Class> srcClass, Class> tgtClass) {
19 | this.srcClass = srcClass;
20 | this.tgtClass = tgtClass;
21 | }
22 |
23 | /**
24 | * Convert the data to target instance
25 | *
26 | * @param data Source data
27 | * @param tgtType Target Type
28 | * @return target instance
29 | */
30 | public abstract Object convert(Object data, XType tgtType);
31 |
32 | /**
33 | * The distance in map, which used for shortest calculation.
34 | *
35 | * @return Distance
36 | */
37 | public abstract int getDistance();
38 |
39 | /**
40 | * This method is extensible or not.
41 | *
42 | * @return extensible
43 | */
44 | public abstract boolean isExtensible();
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/RealConverterMethod.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.XType;
4 | import lombok.extern.slf4j.Slf4j;
5 |
6 | import java.lang.reflect.Method;
7 |
8 | /**
9 | * ConvertMethod, Must match `[S] S convert(T t, Class[S] clz)`
10 | *
11 | * @author sulin
12 | * @since 2019-06-06 12:19:53
13 | */
14 | @Slf4j
15 | public final class RealConverterMethod extends ConverterMethod {
16 |
17 | protected Codec codec;
18 | protected boolean hasTypeArg;
19 | protected Converter annotation;
20 | protected Method method;
21 |
22 | RealConverterMethod(Class> srcClass, Class> tgtClass) {
23 | super(srcClass, tgtClass);
24 | }
25 |
26 | /**
27 | * Create RealConverterMethod by Codec and Method
28 | *
29 | * @param codec Codec instance
30 | * @param method Method reference
31 | * @return RealConverterMethod
32 | */
33 | public static RealConverterMethod valueOf(Codec codec, Method method) {
34 | Class>[] argTypes = method.getParameterTypes();
35 | Class> rtType = method.getReturnType();
36 | Converter annotation = method.getAnnotation(Converter.class);
37 | if (annotation == null) {
38 | log.debug("ignore method that don't have @Converter: {}", method);
39 | return null;
40 | }
41 | if (method.isVarArgs()) {
42 | log.debug("ignore varargs method: {}", method);
43 | return null;
44 | }
45 | if (rtType == void.class || rtType == Void.class) {
46 | log.debug("ignore method by void return: {}", method);
47 | return null; // ignore void return
48 | }
49 | if (argTypes.length != 1 && argTypes.length != 2) {
50 | log.debug("ignore method by argument count: {}", method);
51 | return null;
52 | }
53 | if (argTypes.length == 2 && argTypes[1] != XType.class) {
54 | log.debug("ignore method by the second argument!=Type: {}", method);
55 | return null;
56 | }
57 | RealConverterMethod result = new RealConverterMethod(argTypes[0], rtType);
58 | result.annotation = annotation;
59 | result.method = method;
60 | result.codec = codec;
61 | result.hasTypeArg = argTypes.length == 2;
62 | return result;
63 | }
64 |
65 | @Override
66 | public Object convert(Object data, XType tgtType) {
67 | if (!annotation.nullable() && data == null) {
68 | return null;
69 | }
70 | if (data != null && !this.getSrcClass().isAssignableFrom(data.getClass())) {
71 | throw new IllegalArgumentException("data type unmatched: " + this.getSrcClass() + ", " + data.getClass());
72 | }
73 | try {
74 | if (hasTypeArg) {
75 | return method.invoke(codec, data, tgtType);
76 | } else {
77 | return method.invoke(codec, data);
78 | }
79 | } catch (Exception e) {
80 | throw new IllegalStateException("invoke codec failed.", e);
81 | }
82 | }
83 |
84 | @Override
85 | public int getDistance() {
86 | return annotation.distance();
87 | }
88 |
89 | @Override
90 | public boolean isExtensible() {
91 | return annotation.extensible();
92 | }
93 |
94 | public boolean isHasTypeArg() {
95 | return hasTypeArg;
96 | }
97 |
98 | @Override
99 | public String toString() {
100 | return String.format("[%s]", method.toString());
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/TranConverterMethod.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.XType;
4 |
5 | /**
6 | * Simple convert data from subclass to class
7 | *
8 | * @author sulin
9 | * @since 2019-08-01 20:13:39
10 | */
11 | public final class TranConverterMethod extends ConverterMethod {
12 |
13 | public TranConverterMethod(Class> srcClass, Class> tgtClass) {
14 | super(srcClass, tgtClass);
15 | }
16 |
17 | @Override
18 | public Object convert(Object data, XType tgtType) {
19 | return data;
20 | }
21 |
22 | @Override
23 | public int getDistance() {
24 | return 1 << 4;
25 | }
26 |
27 | @Override
28 | public boolean isExtensible() {
29 | return false;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return String.format("[%s->%s]", getSrcClass().getName(), getTgtClass().getName());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/AtomicCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 | import com.github.smartbuf.reflect.XType;
6 |
7 | import java.util.concurrent.atomic.*;
8 |
9 | /**
10 | * Codec for java.util.concurrent.atomic package.
11 | *
12 | * @author sulin
13 | * @since 2019-07-25 12:00:54
14 | */
15 | public final class AtomicCodec extends Codec {
16 |
17 | @Converter
18 | public AtomicBoolean toAtomicBoolean(Boolean b) {
19 | return new AtomicBoolean(b);
20 | }
21 |
22 | @Converter
23 | public Boolean toBoolean(AtomicBoolean ab) {
24 | return ab.get();
25 | }
26 |
27 | @Converter
28 | public AtomicIntegerArray toAtomicIntegerArray(int[] arr) {
29 | return new AtomicIntegerArray(arr);
30 | }
31 |
32 | @Converter
33 | public int[] toIntegerArray(AtomicIntegerArray aia) {
34 | int[] result = new int[aia.length()];
35 | for (int i = 0; i < result.length; i++) {
36 | result[i] = aia.get(i);
37 | }
38 | return result;
39 | }
40 |
41 | @Converter
42 | public AtomicInteger toAtomicInteger(Integer i) {
43 | return new AtomicInteger(i);
44 | }
45 |
46 | @Converter
47 | public Integer toInteger(AtomicInteger ai) {
48 | return ai.get();
49 | }
50 |
51 | @Converter
52 | public AtomicLongArray toAtomicLongArray(long[] arr) {
53 | return new AtomicLongArray(arr);
54 | }
55 |
56 | @Converter
57 | public long[] toLongArray(AtomicLongArray ala) {
58 | long[] result = new long[ala.length()];
59 | for (int i = 0; i < result.length; i++) {
60 | result[i] = ala.get(i);
61 | }
62 | return result;
63 | }
64 |
65 | @Converter
66 | public AtomicLong toAtomicLong(Long l) {
67 | return new AtomicLong(l);
68 | }
69 |
70 | @Converter
71 | public Long toLong(AtomicLong al) {
72 | return al.get();
73 | }
74 |
75 | @Converter
76 | public AtomicReference> toAtomicReference(Object obj, XType type) {
77 | XType> refType = type.getParameterizedType();
78 | if (refType.isPure() && refType.getRawType().isAssignableFrom(obj.getClass())) {
79 | return new AtomicReference<>(obj); // compatible
80 | }
81 | return new AtomicReference<>(convert(obj, refType));
82 | }
83 |
84 | @Converter(extensible = true)
85 | public Object toObject(AtomicReference ref, XType type) {
86 | Object data = ref.get();
87 | return convert(data, type);
88 | }
89 |
90 | @Converter
91 | public DoubleAdder toDoubleAdder(Double d) {
92 | DoubleAdder addr = new DoubleAdder();
93 | addr.add(d);
94 | return addr;
95 | }
96 |
97 | @Converter
98 | public Double toDouble(DoubleAdder adder) {
99 | return adder.doubleValue();
100 | }
101 |
102 | @Converter
103 | public LongAdder toLongAdder(Long l) {
104 | LongAdder adder = new LongAdder();
105 | adder.add(l);
106 | return adder;
107 | }
108 |
109 | @Converter
110 | public Long toLong(LongAdder adder) {
111 | return adder.longValue();
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/AwtCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | import java.awt.*;
7 | import java.util.HashMap;
8 | import java.util.LinkedHashMap;
9 | import java.util.Map;
10 |
11 | /**
12 | * Codec for `java.awt` package, support Point/Dimension/Rectangle/Font/Color/etc.
13 | *
14 | * @author sulin
15 | * @since 2019-07-25 14:28:03
16 | */
17 | @SuppressWarnings({"MagicConstant"})
18 | public final class AwtCodec extends Codec {
19 |
20 | private final String FONT_NAME = "name";
21 | private final String FONT_STYLE = "style";
22 | private final String FONT_SIZE = "size";
23 | private final String POINT_X = "x";
24 | private final String POINT_Y = "y";
25 | private final String DIMENSION_WIDTH = "width";
26 | private final String DIMENSION_HEIGHT = "height";
27 |
28 | @Converter
29 | public Font toFont(Map map) {
30 | String name = convert(map.get(FONT_NAME), String.class);
31 | Integer style = convert(map.get(FONT_STYLE), Integer.class);
32 | Integer size = convert(map.get(FONT_SIZE), Integer.class);
33 | if (style == null) {
34 | style = Font.PLAIN;
35 | }
36 | if (size == null) {
37 | size = 12;
38 | }
39 | return new Font(name, style, size);
40 | }
41 |
42 | @Converter
43 | public Map toMap(Font font) {
44 | Map map = new LinkedHashMap<>();
45 | map.put(FONT_NAME, font.getName());
46 | map.put(FONT_STYLE, font.getStyle());
47 | map.put(FONT_SIZE, font.getSize());
48 |
49 | return map;
50 | }
51 |
52 | /*
53 | * Convert Color to String, like #00112233
54 | */
55 | @Converter
56 | public String toString(Color c) {
57 | return String.format("#%02x%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
58 | }
59 |
60 | /*
61 | * Convert String to Color, support like #001122 or #00112233
62 | */
63 | @Converter
64 | public Color toColor(String s) {
65 | int value = Integer.decode(s);
66 | if (s.length() == 9 && s.charAt(0) == '#') {
67 | return new Color(value >> 24 & 0xFF, value >> 16 & 0xFF, value >> 8 & 0xFF, value & 0xFF);
68 | }
69 | return new Color((value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF);
70 | }
71 |
72 | @Converter
73 | public Map toMap(Point point) {
74 | Map map = new HashMap<>();
75 | map.put(POINT_X, (int) point.getX());
76 | map.put(POINT_Y, (int) point.getY());
77 | return map;
78 | }
79 |
80 | @Converter
81 | public Point toPoint(Map map) {
82 | Integer x = convert(map.get(POINT_X), Integer.class);
83 | Integer y = convert(map.get(POINT_Y), Integer.class);
84 | return new Point(x, y);
85 | }
86 |
87 | @Converter
88 | public Map toMap(Dimension dimension) {
89 | Map map = new HashMap<>();
90 | map.put(DIMENSION_WIDTH, (int) dimension.getWidth());
91 | map.put(DIMENSION_HEIGHT, (int) dimension.getHeight());
92 | return map;
93 | }
94 |
95 | @Converter
96 | public Dimension toDimension(Map map) {
97 | Integer width = convert(map.get(DIMENSION_WIDTH), Integer.class);
98 | Integer height = convert(map.get(DIMENSION_HEIGHT), Integer.class);
99 | return new Dimension(width, height);
100 | }
101 |
102 | @Converter
103 | public Map toMap(Rectangle rect) {
104 | Map map = new HashMap<>();
105 | map.put(POINT_X, (int) rect.getX());
106 | map.put(POINT_Y, (int) rect.getY());
107 | map.put(DIMENSION_WIDTH, (int) rect.getWidth());
108 | map.put(DIMENSION_HEIGHT, (int) rect.getHeight());
109 | return map;
110 | }
111 |
112 | @Converter
113 | public Rectangle toRectangle(Map map) {
114 | Integer x = convert(map.get(POINT_X), Integer.class);
115 | Integer y = convert(map.get(POINT_Y), Integer.class);
116 | Integer width = convert(map.get(DIMENSION_WIDTH), Integer.class);
117 | Integer height = convert(map.get(DIMENSION_HEIGHT), Integer.class);
118 | return new Rectangle(x, y, width, height);
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/BufferCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Converter;
4 | import com.github.smartbuf.converter.Codec;
5 |
6 | import java.nio.*;
7 |
8 | /**
9 | * Codec for java.nio.Buffer, and correlated class
10 | *
11 | * @author sulin
12 | * @since 2019-07-25 17:32:41
13 | */
14 | public final class BufferCodec extends Codec {
15 |
16 | @Converter
17 | public byte[] toByteArray(ByteBuffer buf) {
18 | byte[] arr = new byte[buf.remaining()];
19 | buf.get(arr, 0, arr.length);
20 | return arr;
21 | }
22 |
23 | @Converter
24 | public ByteBuffer toByteBuffer(byte[] bs) {
25 | return ByteBuffer.wrap(bs);
26 | }
27 |
28 | @Converter
29 | public char[] toCharArray(CharBuffer buf) {
30 | char[] arr = new char[buf.remaining()];
31 | buf.get(arr, 0, arr.length);
32 | return arr;
33 | }
34 |
35 | @Converter
36 | public CharBuffer toCharBuffer(char[] chars) {
37 | return CharBuffer.wrap(chars);
38 | }
39 |
40 | @Converter
41 | public CharBuffer toCharBuffer(ByteBuffer buf) {
42 | return buf.asCharBuffer();
43 | }
44 |
45 | @Converter
46 | public float[] toFloatArray(FloatBuffer buf) {
47 | float[] arr = new float[buf.remaining()];
48 | buf.get(arr, 0, arr.length);
49 | return arr;
50 | }
51 |
52 | @Converter
53 | public FloatBuffer toFloatBuffer(float[] floats) {
54 | return FloatBuffer.wrap(floats);
55 | }
56 |
57 | @Converter
58 | public FloatBuffer toFloatBuffer(ByteBuffer buf) {
59 | return buf.asFloatBuffer();
60 | }
61 |
62 | @Converter
63 | public double[] toDoubleArray(DoubleBuffer buf) {
64 | double[] arr = new double[buf.remaining()];
65 | buf.get(arr, 0, arr.length);
66 | return arr;
67 | }
68 |
69 | @Converter
70 | public DoubleBuffer toDoubleBuffer(double[] doubles) {
71 | return DoubleBuffer.wrap(doubles);
72 | }
73 |
74 | @Converter
75 | public DoubleBuffer toDoubleBuffer(ByteBuffer buf) {
76 | return buf.asDoubleBuffer();
77 | }
78 |
79 | @Converter
80 | public short[] toShortArray(ShortBuffer buf) {
81 | short[] arr = new short[buf.remaining()];
82 | buf.get(arr, 0, arr.length);
83 | return arr;
84 | }
85 |
86 | @Converter
87 | public ShortBuffer toShortBuffer(short[] shorts) {
88 | return ShortBuffer.wrap(shorts);
89 | }
90 |
91 | @Converter
92 | public ShortBuffer toShortBuffer(ByteBuffer buf) {
93 | return buf.asShortBuffer();
94 | }
95 |
96 | @Converter
97 | public int[] toIntArray(IntBuffer buf) {
98 | int[] arr = new int[buf.remaining()];
99 | buf.get(arr, 0, arr.length);
100 | return arr;
101 | }
102 |
103 | @Converter
104 | public IntBuffer toIntBuffer(int[] ints) {
105 | return IntBuffer.wrap(ints);
106 | }
107 |
108 | @Converter
109 | public IntBuffer toIntBuffer(ByteBuffer buf) {
110 | return buf.asIntBuffer();
111 | }
112 |
113 | @Converter
114 | public long[] toLongArray(LongBuffer buf) {
115 | long[] arr = new long[buf.remaining()];
116 | buf.get(arr, 0, arr.length);
117 | return arr;
118 | }
119 |
120 | @Converter
121 | public LongBuffer toLongBuffer(long[] longs) {
122 | return LongBuffer.wrap(longs);
123 | }
124 |
125 | @Converter
126 | public LongBuffer toLongBuffer(ByteBuffer buf) {
127 | return buf.asLongBuffer();
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/IOCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 | import com.github.smartbuf.reflect.XType;
6 |
7 | import java.io.*;
8 | import java.nio.CharBuffer;
9 | import java.nio.charset.Charset;
10 |
11 | /**
12 | * Codec for `java.io` and `java.nio` packages.
13 | *
14 | * @author sulin
15 | * @since 2019-07-25 14:40:12
16 | */
17 | public final class IOCodec extends Codec {
18 |
19 | @Converter
20 | public Charset toCharset(String s) {
21 | return Charset.forName(s);
22 | }
23 |
24 | @Converter
25 | public String toString(Charset c) {
26 | return c.name();
27 | }
28 |
29 | @Converter
30 | public String toString(File file) {
31 | return file.toString();
32 | }
33 |
34 | @Converter
35 | public byte[] toByteArray(InputStream is) throws IOException {
36 | ByteArrayOutputStream output = new ByteArrayOutputStream();
37 | byte[] buffer = new byte[1024];
38 | for (int n; (n = is.read(buffer)) >= 0; ) {
39 | output.write(buffer, 0, n);
40 | }
41 | return output.toByteArray();
42 | }
43 |
44 | @Converter
45 | public InputStream toInputStream(byte[] bytes, XType type) {
46 | Class> clz = type.getRawType();
47 | if (clz.isAssignableFrom(ByteArrayInputStream.class)) {
48 | return new ByteArrayInputStream(bytes);
49 | }
50 | if (clz.isAssignableFrom(BufferedInputStream.class)) {
51 | return new BufferedInputStream(new ByteArrayInputStream(bytes));
52 | }
53 | if (clz.isAssignableFrom(DataInputStream.class)) {
54 | return new DataInputStream(new ByteArrayInputStream(bytes));
55 | }
56 | throw new UnsupportedOperationException("unsupported type: " + clz);
57 | }
58 |
59 | @Converter
60 | public String toString(Readable reader) throws IOException {
61 | StringBuilder sb = new StringBuilder();
62 | CharBuffer buf = CharBuffer.allocate(1024);
63 | while (reader.read(buf) >= 0) {
64 | buf.flip();
65 | while (buf.hasRemaining()) {
66 | sb.append(buf.get());
67 | }
68 | buf.clear();
69 | }
70 | return sb.toString();
71 | }
72 |
73 | @Converter
74 | public Readable toReadable(String s, XType type) {
75 | Class> clz = type.getRawType();
76 | if (clz.isAssignableFrom(StringReader.class)) {
77 | return new StringReader(s);
78 | }
79 | if (clz.isAssignableFrom(CharArrayReader.class)) {
80 | return new CharArrayReader(s.toCharArray());
81 | }
82 | if (clz.isAssignableFrom(BufferedReader.class)) {
83 | return new BufferedReader(new StringReader(s));
84 | }
85 |
86 | throw new UnsupportedOperationException("Unsupported Readable: " + clz);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/JavaxCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | import javax.xml.datatype.XMLGregorianCalendar;
7 | import java.util.Calendar;
8 |
9 | /**
10 | * Codec for javax.xml package.
11 | *
12 | * @author sulin
13 | * @since 2019-05-13 18:25:17
14 | */
15 | public final class JavaxCodec extends Codec {
16 |
17 | @Converter
18 | public Calendar toCalendar(XMLGregorianCalendar calendar) {
19 | return calendar.toGregorianCalendar();
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/JodaCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 | import org.joda.time.*;
6 | import org.joda.time.format.DateTimeFormat;
7 | import org.joda.time.format.DateTimeFormatter;
8 |
9 | import java.util.TimeZone;
10 |
11 | /**
12 | * Codec for `org.joda.time` package.
13 | *
14 | * https://blog.joda.org/2014/11/converting-from-joda-time-to-javatime.html
15 | *
16 | * @author sulin
17 | * @since 2019-07-26 11:56:20
18 | */
19 | public final class JodaCodec extends Codec {
20 |
21 | @Converter
22 | public LocalDateTime toLocalDateTime(java.time.LocalDateTime dt) {
23 | return new LocalDateTime(dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth(),
24 | dt.getHour(), dt.getMinute(), dt.getSecond(), dt.getNano() / 1000000);
25 | }
26 |
27 | @Converter
28 | public java.time.LocalDateTime toLocalDateTime(LocalDateTime dt) {
29 | return java.time.LocalDateTime.of(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth(),
30 | dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute(), dt.getMillisOfSecond() * 1000000);
31 | }
32 |
33 | @Converter
34 | public DateTime toDateTime(LocalDateTime ldt) {
35 | return ldt.toDateTime();
36 | }
37 |
38 | @Converter
39 | public LocalDateTime toLocalDateTime(DateTime dt) {
40 | return dt.toLocalDateTime();
41 | }
42 |
43 | @Converter
44 | public LocalDate toLocalDate(java.time.LocalDate ldt) {
45 | return new LocalDate(ldt.getYear(), ldt.getMonthValue(), ldt.getDayOfMonth());
46 | }
47 |
48 | @Converter
49 | public java.time.LocalDate toLocalDate(LocalDate date) {
50 | return java.time.LocalDate.of(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth());
51 | }
52 |
53 | @Converter
54 | public LocalTime toLocalTime(java.time.LocalTime time) {
55 | return LocalTime.fromMillisOfDay(time.toNanoOfDay() / 1000000L);
56 | }
57 |
58 | @Converter
59 | public java.time.LocalTime toLocalTime(LocalTime time) {
60 | return java.time.LocalTime.ofNanoOfDay(time.getMillisOfDay() * 1000000L);
61 | }
62 |
63 | @Converter
64 | public Duration toDuration(java.time.Duration d) {
65 | return Duration.millis(d.toMillis());
66 | }
67 |
68 | @Converter
69 | public java.time.Duration toDuration(Duration d) {
70 | return java.time.Duration.ofMillis(d.getMillis());
71 | }
72 |
73 | @Converter
74 | public Instant toInstant(java.time.Instant instant) {
75 | return Instant.ofEpochMilli(instant.toEpochMilli());
76 | }
77 |
78 | @Converter
79 | public java.time.Instant toInstant(Instant instant) {
80 | return java.time.Instant.ofEpochMilli(instant.getMillis());
81 | }
82 |
83 | @Converter
84 | public TimeZone toTimeZone(DateTimeZone zone) {
85 | return zone.toTimeZone();
86 | }
87 |
88 | @Converter
89 | public DateTimeZone toDateTimeZone(TimeZone zone) {
90 | return DateTimeZone.forTimeZone(zone);
91 | }
92 |
93 | @Converter
94 | public String toString(DateTimeFormatter formatter) {
95 | throw new UnsupportedOperationException();
96 | }
97 |
98 | @Converter
99 | public DateTimeFormatter toDateTimeFormatter(String str) {
100 | return DateTimeFormat.forPattern(str);
101 | }
102 |
103 | @Converter
104 | public Period toPeriod(String str) {
105 | return Period.parse(str);
106 | }
107 |
108 | @Converter
109 | public String toString(Period period) {
110 | return period.toString();
111 | }
112 |
113 | @Converter
114 | public Interval toInterval(String str) {
115 | return Interval.parse(str);
116 | }
117 |
118 | @Converter
119 | public String toString(Interval interval) {
120 | return interval.toString();
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/MathCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Converter;
4 | import com.github.smartbuf.converter.Codec;
5 |
6 | import java.math.BigDecimal;
7 | import java.math.BigInteger;
8 |
9 | /**
10 | * Codec for java.math package, include BigDecimal and BigInteger.
11 | *
12 | * @author sulin
13 | * @since 2019-07-25 12:17:16
14 | */
15 | public final class MathCodec extends Codec {
16 |
17 | @Converter
18 | public BigDecimal toBigDecimal(String s) {
19 | return new BigDecimal(s);
20 | }
21 |
22 | @Converter
23 | public String toString(BigDecimal bd) {
24 | return bd.toPlainString();
25 | }
26 |
27 | @Converter
28 | public BigInteger toBigInteger(String s) {
29 | return new BigInteger(s);
30 | }
31 |
32 | @Converter
33 | public String toString(BigInteger bi) {
34 | return bi.toString();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/NetCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | import java.net.*;
7 |
8 | /**
9 | * Codec for `java.net` package
10 | *
11 | * @author sulin
12 | * @since 2019-07-25 20:44:11
13 | */
14 | public final class NetCodec extends Codec {
15 |
16 | @Converter
17 | public URI toURI(String s) {
18 | return URI.create(s);
19 | }
20 |
21 | @Converter
22 | public String toString(URI uri) {
23 | return uri.toString();
24 | }
25 |
26 | @Converter
27 | public URL toURL(String s) throws MalformedURLException {
28 | return new URL(s);
29 | }
30 |
31 | @Converter
32 | public String toString(URL url) {
33 | return url.toString();
34 | }
35 |
36 | /*
37 | * Convert String to InetAddress, support Inet4Address and Inet6Address
38 | */
39 | @Converter(extensible = true)
40 | public InetAddress toInetAddress(String s) throws UnknownHostException {
41 | int off = s.indexOf('/');
42 | if (off >= 0) {
43 | String hostname = s.substring(0, off);
44 | String address = s.substring(off + 1);
45 | s = hostname.length() == 0 ? address : hostname;
46 | }
47 | return InetAddress.getByName(s);
48 | }
49 |
50 | /*
51 | * Convert InetAddress to String, support Inet4Address and Inet6Address
52 | */
53 | @Converter
54 | public String toString(InetAddress addr) {
55 | return addr.getHostAddress();
56 | }
57 |
58 | @Converter
59 | public InetSocketAddress toInetSocketAddress(String s) {
60 | String host, port = null;
61 | int off = s.indexOf(':');
62 | if (off > 0) {
63 | host = s.substring(0, off);
64 | port = s.substring(off + 1);
65 | } else {
66 | host = s;
67 | }
68 | InetAddress addr = convert(host, InetAddress.class);
69 | if (port == null) {
70 | return new InetSocketAddress(addr, 0);
71 | }
72 | return new InetSocketAddress(addr, Integer.parseInt(port));
73 | }
74 |
75 | @Converter
76 | public String toString(InetSocketAddress addr) {
77 | return addr.getHostString() + ":" + addr.getPort();
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/NumberCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | import java.text.DecimalFormat;
7 |
8 | /**
9 | * Codec for Number and its descendants, include Boolean
10 | *
11 | * @author sulin
12 | * @since 2019-05-13 18:14:18
13 | */
14 | public final class NumberCodec extends Codec {
15 |
16 | private static final DecimalFormat F_F = new DecimalFormat("0.#######");
17 | private static final DecimalFormat D_F = new DecimalFormat("0.################");
18 |
19 | @Converter
20 | public Long toLong(String s) {
21 | return Long.parseLong(s);
22 | }
23 |
24 | @Converter
25 | public String toString(Long l) {
26 | return l.toString();
27 | }
28 |
29 | @Converter
30 | public Short toShort(Long l) {
31 | return l.shortValue();
32 | }
33 |
34 | @Converter
35 | public Long toLong(Short s) {
36 | return s.longValue();
37 | }
38 |
39 | @Converter
40 | public Integer toInteger(Long l) {
41 | return l.intValue();
42 | }
43 |
44 | @Converter
45 | public Long toLong(Integer i) {
46 | return i.longValue();
47 | }
48 |
49 | @Converter
50 | public Float toFloat(Double d) {
51 | return d.floatValue();
52 | }
53 |
54 | @Converter
55 | public Float toFloat(String s) {
56 | return Float.parseFloat(s);
57 | }
58 |
59 | @Converter
60 | public Double toDouble(Float f) {
61 | return f.doubleValue();
62 | }
63 |
64 | @Converter
65 | public String toString(Float f) {
66 | return F_F.format(f);
67 | }
68 |
69 | @Converter
70 | public Double toDouble(String s) {
71 | return Double.parseDouble(s);
72 | }
73 |
74 | @Converter
75 | public Double toDouble(Long l) {
76 | return l.doubleValue();
77 | }
78 |
79 | @Converter
80 | public Long toLong(Double d) {
81 | return d.longValue();
82 | }
83 |
84 | @Converter
85 | public String toString(Double d) {
86 | return D_F.format(d);
87 | }
88 |
89 | @Converter
90 | public Byte toByte(Long l) {
91 | return l.byteValue();
92 | }
93 |
94 | @Converter
95 | public Long toLong(Byte b) {
96 | return b.longValue();
97 | }
98 |
99 | @Converter
100 | public Boolean toBoolean(Long l) {
101 | // Convert Integer to Boolean; 0 => false; !0 => true
102 | return l != 0;
103 | }
104 |
105 | @Converter
106 | public Long toLong(Boolean b) {
107 | return b ? 1L : 0L;
108 | }
109 |
110 | @Converter
111 | public Boolean toBoolean(String s) {
112 | return Boolean.valueOf(s);
113 | }
114 |
115 | @Converter
116 | public String toString(Boolean b) {
117 | return b.toString();
118 | }
119 |
120 | @Converter
121 | public Character toCharacter(Long i) {
122 | return (char) i.intValue();
123 | }
124 |
125 | @Converter
126 | public Long toInteger(Character c) {
127 | return (long) (int) c;
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/PrimaryCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | /**
7 | * Codec for primary data type
8 | *
9 | * @author sulin
10 | * @since 2019-08-05 19:44:37
11 | */
12 | public final class PrimaryCodec extends Codec {
13 |
14 | @Converter
15 | public boolean toBoolean(Boolean b) {
16 | return b;
17 | }
18 |
19 | @Converter
20 | public Boolean toBoolean(boolean b) {
21 | return b;
22 | }
23 |
24 | @Converter
25 | public byte toByte(Byte b) {
26 | return b;
27 | }
28 |
29 | @Converter
30 | public Byte toByte(byte b) {
31 | return b;
32 | }
33 |
34 | @Converter
35 | public short toShort(Short s) {
36 | return s;
37 | }
38 |
39 | @Converter
40 | public Short toShort(short s) {
41 | return s;
42 | }
43 |
44 | @Converter
45 | public int toInt(Integer i) {
46 | return i;
47 | }
48 |
49 | @Converter
50 | public Integer toInteger(int i) {
51 | return i;
52 | }
53 |
54 | @Converter
55 | public long toLong(Long l) {
56 | return l;
57 | }
58 |
59 | @Converter
60 | public Long toLong(long l) {
61 | return l;
62 | }
63 |
64 | @Converter
65 | public float toFloat(Float f) {
66 | return f;
67 | }
68 |
69 | @Converter
70 | public Float toFloat(float f) {
71 | return f;
72 | }
73 |
74 | @Converter
75 | public double toDouble(Double d) {
76 | return d;
77 | }
78 |
79 | @Converter
80 | public Double toDouble(double d) {
81 | return d;
82 | }
83 |
84 | @Converter
85 | public char toChar(Character c) {
86 | return c;
87 | }
88 |
89 | @Converter
90 | public Character toCharacter(char c) {
91 | return c;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/ReferenceCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 | import com.github.smartbuf.reflect.XType;
6 |
7 | import java.lang.ref.Reference;
8 | import java.lang.ref.SoftReference;
9 | import java.lang.ref.WeakReference;
10 |
11 | /**
12 | * Reference's codec
13 | *
14 | * @author sulin
15 | * @since 2019-05-13 18:39:05
16 | */
17 | public final class ReferenceCodec extends Codec {
18 |
19 | @Converter(extensible = true)
20 | public Reference toReference(Object obj, XType type) {
21 | XType> paramType = type.getParameterizedType();
22 | Object value;
23 | if (paramType.isPure() && paramType.getRawType().isAssignableFrom(obj.getClass())) {
24 | value = obj; // compatible
25 | } else {
26 | value = convert(obj, paramType); // convert
27 | }
28 | // build reference
29 | Class> refClass = type.getRawType();
30 | if (refClass == SoftReference.class || refClass == Reference.class) {
31 | return new SoftReference<>(value);
32 | }
33 | if (refClass == WeakReference.class) {
34 | return new WeakReference<>(value);
35 | }
36 | throw new IllegalArgumentException("Unsupport Reference: " + refClass);
37 | }
38 |
39 | @Converter(extensible = true)
40 | public Object toObject(Reference> ref, XType> type) {
41 | Object obj = ref.get();
42 | if (type.isPure() && type.getRawType().isInstance(obj)) {
43 | return obj;
44 | }
45 | return convert(obj, type);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/SqlCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | import javax.sql.rowset.serial.SerialBlob;
7 | import javax.sql.rowset.serial.SerialClob;
8 | import java.io.InputStream;
9 | import java.io.Reader;
10 | import java.sql.*;
11 |
12 | /**
13 | * Codec for `java.sql` package
14 | *
15 | * @author sulin
16 | * @since 2019-07-25 20:49:12
17 | */
18 | public final class SqlCodec extends Codec {
19 |
20 | @Converter
21 | public Blob toBlob(byte[] bytes) throws SQLException {
22 | return new SerialBlob(bytes);
23 | }
24 |
25 | @Converter
26 | public InputStream toInputStream(Blob b) throws SQLException {
27 | return b.getBinaryStream();
28 | }
29 |
30 | @Converter
31 | public Clob toClob(String str) throws SQLException {
32 | return new SerialClob(str.toCharArray());
33 | }
34 |
35 | @Converter
36 | public Reader toReader(Clob c) throws SQLException {
37 | return c.getCharacterStream();
38 | }
39 |
40 | @Converter
41 | public Date toDate(Long time) {
42 | return new Date(time);
43 | }
44 |
45 | @Converter
46 | public Long toLong(Date date) {
47 | return date.getTime();
48 | }
49 |
50 | @Converter
51 | public Time toTime(Long time) {
52 | return new Time(time);
53 | }
54 |
55 | @Converter
56 | public Long toLong(Time time) {
57 | return time.getTime();
58 | }
59 |
60 | @Converter
61 | public Timestamp toTimestamp(Long time) {
62 | return new Timestamp(time);
63 | }
64 |
65 | @Converter
66 | public Long toLong(Timestamp t) {
67 | return t.getTime();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/converter/codec/StringCodec.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.Converter;
5 |
6 | import java.text.StringCharacterIterator;
7 |
8 | /**
9 | * String's codec
10 | *
11 | * @author sulin
12 | * @since 2019-05-13 18:14:25
13 | */
14 | public final class StringCodec extends Codec {
15 |
16 | @Converter
17 | public String toString(StringBuffer sb) {
18 | return sb.toString();
19 | }
20 |
21 | @Converter
22 | public StringBuffer toStringBuffer(String s) {
23 | return new StringBuffer(s);
24 | }
25 |
26 | @Converter
27 | public String toString(StringBuilder sb) {
28 | return sb.toString();
29 | }
30 |
31 | @Converter
32 | public StringBuilder toStringBuilder(String s) {
33 | return new StringBuilder(s);
34 | }
35 |
36 | @Converter(distance = 101)
37 | public Character toCharacter(String s) {
38 | if (s.length() != 1) {
39 | throw new UnsupportedOperationException("Convert string to char failed, string.length > 0: " + s);
40 | }
41 | return s.charAt(0);
42 | }
43 |
44 | @Converter(distance = 101)
45 | public String toString(Character c) {
46 | return c.toString();
47 | }
48 |
49 | @Converter
50 | public String toString(char[] chars) {
51 | return new String(chars);
52 | }
53 |
54 | @Converter
55 | public char[] toCharArray(String s) {
56 | return s.toCharArray();
57 | }
58 |
59 | @Converter
60 | public String toString(byte[] bytes) {
61 | return new String(bytes);
62 | }
63 |
64 | @Converter
65 | public byte[] toByteArray(String s) {
66 | return s.getBytes();
67 | }
68 |
69 | @Converter
70 | public String toString(StringCharacterIterator sc) {
71 | StringBuilder sb = new StringBuilder();
72 | char c = sc.first();
73 | while (c != StringCharacterIterator.DONE) {
74 | sb.append(c);
75 | c = sc.next();
76 | }
77 | return sb.toString();
78 | }
79 |
80 | @Converter
81 | public StringCharacterIterator toStringCharacterIterator(String s) {
82 | return new StringCharacterIterator(s);
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/CircleReferenceException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | /**
4 | * CircularReferenceException represents that the specified object has circular reference problem,
5 | * which causes it's no serializable.
6 | *
7 | * @author sulin
8 | * @since 2019-10-22 20:55:29
9 | */
10 | public class CircleReferenceException extends RuntimeException {
11 |
12 | public CircleReferenceException(String message) {
13 | super(message);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/InvalidDataException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * InvalidDataException indicates the specified data-id is invalid.
7 | *
8 | * @author sulin
9 | * @since 2019-11-08 11:34:08
10 | */
11 | public class InvalidDataException extends IOException {
12 |
13 | public InvalidDataException(String message) {
14 | super(message);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/InvalidStructException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * InvalidStructException indicates that the specified struct-id is invalid.
7 | *
8 | * @author sulin
9 | * @since 2019-11-08 14:18:56
10 | */
11 | public class InvalidStructException extends IOException {
12 |
13 | public InvalidStructException(String message) {
14 | super(message);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/InvalidVersionException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * InvalidVersionException indicates the specified data has an invalid version
7 | *
8 | * @author sulin
9 | * @since 2019-10-22 17:17:44
10 | */
11 | public class InvalidVersionException extends IOException {
12 |
13 | public InvalidVersionException(int expectedVer, int ver) {
14 | super("Expect " + Integer.toHexString(expectedVer) + ", but received " + Integer.toHexString(ver));
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/MismatchModeException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * MismatchModeException indicates the `mode` flag didn't match between input and output.
7 | *
8 | * @author sulin
9 | * @since 2019-10-22 16:49:56
10 | */
11 | public class MismatchModeException extends IOException {
12 |
13 | public MismatchModeException(boolean localEnableStream) {
14 | super(localEnableStream ?
15 | "expect stream mode, but data has no-stream mode flag" :
16 | "expect no-stream mode, but data has stream mode flag");
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/NoShortestPipelineException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 |
5 | /**
6 | * NoShortestPipelineException indicates the {@link CodecFactory}
7 | * can't decide the shortest codec-pipeline to use.
8 | *
9 | * @author sulin
10 | * @since 2019-11-11 21:47:21
11 | */
12 | public class NoShortestPipelineException extends RuntimeException {
13 |
14 | public NoShortestPipelineException(String message) {
15 | super(message);
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/OutOfSpaceException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * OutOfSpaceException indicates that the data to write is too big to handle.
7 | *
8 | * @author sulin
9 | * @since 2019-10-27 15:55:25
10 | */
11 | public class OutOfSpaceException extends IOException {
12 |
13 | public OutOfSpaceException(String message) {
14 | super(message);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/SmartBufClosedException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * SmartBufClosedException indicates the closed SmartBuf instance are reused.
7 | *
8 | * @author sulin
9 | * @since 2019-10-28 17:22:11
10 | */
11 | public class SmartBufClosedException extends IOException {
12 |
13 | public SmartBufClosedException(String message) {
14 | super(message);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/UnexpectedReadException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * UnexpectedReadException indicates Input run into some unexpected data.
7 | *
8 | * @author sulin
9 | * @since 2019-10-22 17:10:07
10 | */
11 | public class UnexpectedReadException extends IOException {
12 |
13 | public UnexpectedReadException(String message) {
14 | super(message);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/exception/UnexpectedSequenceException.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.exception;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * UnexpectedSequenceException indicates the sequence of input data is unexpected,
7 | * Maybe packet-lost occured, in this case, should reset all input/output context.
8 | *
9 | * @author sulin
10 | * @since 2019-10-22 17:00:39
11 | */
12 | public class UnexpectedSequenceException extends IOException {
13 |
14 | public UnexpectedSequenceException(long local, long seq) {
15 | super("The sequence of schema-area is unexpected, expect " + local + ", but received " + seq);
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/Node.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node;
2 |
3 | /**
4 | * Base class of Node, and provider some common features.
5 | *
6 | * @author sulin
7 | * @since 2019-05-08 20:33:51
8 | */
9 | public abstract class Node {
10 |
11 | /**
12 | * Get this Node's value
13 | *
14 | * @return Node's real value
15 | */
16 | public abstract Object value();
17 |
18 | /**
19 | * Get this Node's datatype
20 | *
21 | * @return Node's real type
22 | */
23 | public abstract NodeType type();
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/NodeType.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node;
2 |
3 | /**
4 | * NodeType represents datatype of {@link Node},
5 | * it could help use switch to optimize a little performance.
6 | *
7 | * @author sulin
8 | * @since 2019-11-10 12:12:51
9 | */
10 | public enum NodeType {
11 | UNKNOWN,
12 |
13 | BOOLEAN,
14 | VARINT,
15 | FLOAT,
16 | DOUBLE,
17 | STRING,
18 | SYMBOL,
19 | OBJECT,
20 |
21 | ARRAY,
22 | ARRAY_BOOLEAN,
23 | ARRAY_BYTE,
24 | ARRAY_SHORT,
25 | ARRAY_INT,
26 | ARRAY_LONG,
27 | ARRAY_FLOAT,
28 | ARRAY_DOUBLE
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/ArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | import java.util.Collection;
7 |
8 | /**
9 | * ArrayNode represents unknown data's array
10 | *
11 | * @author sulin
12 | * @since 2019-11-03 14:54:55
13 | */
14 | public final class ArrayNode extends Node {
15 |
16 | private final Collection> data;
17 |
18 | public ArrayNode(Collection> data) {
19 | this.data = data;
20 | }
21 |
22 | @Override
23 | public Object value() {
24 | return data;
25 | }
26 |
27 | @Override
28 | public NodeType type() {
29 | return NodeType.ARRAY;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/BooleanArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * BooleanArrayNode represents boolean[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:46:34
11 | */
12 | public final class BooleanArrayNode extends Node {
13 |
14 | private final boolean[] data;
15 |
16 | public BooleanArrayNode(boolean[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_BOOLEAN;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/ByteArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * ByteArrayNode represents byte[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:46:42
11 | */
12 | public final class ByteArrayNode extends Node {
13 |
14 | private final byte[] data;
15 |
16 | public ByteArrayNode(byte[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_BYTE;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/DoubleArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * DoubleArrayNode represents double[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:47:29
11 | */
12 | public final class DoubleArrayNode extends Node {
13 |
14 | private final double[] data;
15 |
16 | public DoubleArrayNode(double[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_DOUBLE;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/FloatArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * FloatArrayNode represents float[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:47:16
11 | */
12 | public final class FloatArrayNode extends Node {
13 |
14 | private final float[] data;
15 |
16 | public FloatArrayNode(float[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_FLOAT;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/IntArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * IntArrayNode represents int[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:46:58
11 | */
12 | public final class IntArrayNode extends Node {
13 |
14 | private final int[] data;
15 |
16 | public IntArrayNode(int[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_INT;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/LongArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * LongArrayNode represents long[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:47:09
11 | */
12 | public final class LongArrayNode extends Node {
13 |
14 | private final long[] data;
15 |
16 | public LongArrayNode(long[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_LONG;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/array/ShortArrayNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.array;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * ShortArrayNode represents short[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-03 14:46:51
11 | */
12 | public final class ShortArrayNode extends Node {
13 |
14 | private final short[] data;
15 |
16 | public ShortArrayNode(short[] data) {
17 | this.data = data;
18 | }
19 |
20 | @Override
21 | public Object value() {
22 | return data;
23 | }
24 |
25 | @Override
26 | public NodeType type() {
27 | return NodeType.ARRAY_SHORT;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/BooleanNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * BooleanNode represents boolean and Boolean.
8 | *
9 | * @author sulin
10 | * @since 2019-05-08 21:00:07
11 | */
12 | public final class BooleanNode extends Node {
13 |
14 | public final static BooleanNode TRUE = new BooleanNode();
15 | public final static BooleanNode FALSE = new BooleanNode();
16 |
17 | private BooleanNode() {
18 | }
19 |
20 | public static BooleanNode valueOf(boolean b) {
21 | return b ? TRUE : FALSE;
22 | }
23 |
24 | public static BooleanNode valueOf(Boolean b) {
25 | return valueOf(b.booleanValue());
26 | }
27 |
28 | @Override
29 | public Object value() {
30 | return this == TRUE;
31 | }
32 |
33 | @Override
34 | public NodeType type() {
35 | return NodeType.BOOLEAN;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/DoubleNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * DoubleNode represents double and Double.
8 | *
9 | * @author sulin
10 | * @since 2019-05-08 21:00:27
11 | */
12 | public final class DoubleNode extends Node {
13 |
14 | public final static DoubleNode ZERO = new DoubleNode(0);
15 |
16 | private final double value;
17 |
18 | private DoubleNode(double value) {
19 | this.value = value;
20 | }
21 |
22 | public static DoubleNode valueOf(double d) {
23 | if (d == 0) {
24 | return ZERO;
25 | }
26 | return new DoubleNode(d);
27 | }
28 |
29 | public static DoubleNode valueOf(Double d) {
30 | return valueOf(d.doubleValue());
31 | }
32 |
33 | @Override
34 | public Object value() {
35 | return value;
36 | }
37 |
38 | @Override
39 | public NodeType type() {
40 | return NodeType.DOUBLE;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/FloatNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * FloatNode represents float and Float.
8 | *
9 | * @author sulin
10 | * @since 2019-05-08 21:00:21
11 | */
12 | public final class FloatNode extends Node {
13 |
14 | public final static FloatNode ZERO = new FloatNode(0);
15 |
16 | private final float value;
17 |
18 | private FloatNode(float value) {
19 | this.value = value;
20 | }
21 |
22 | public static FloatNode valueOf(float f) {
23 | if (f == 0) {
24 | return ZERO;
25 | }
26 | return new FloatNode(f);
27 | }
28 |
29 | public static FloatNode valueOf(Float f) {
30 | return valueOf(f.floatValue());
31 | }
32 |
33 | @Override
34 | public Object value() {
35 | return value;
36 | }
37 |
38 | @Override
39 | public NodeType type() {
40 | return NodeType.FLOAT;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/ObjectNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.Type;
4 | import com.github.smartbuf.node.Node;
5 | import com.github.smartbuf.node.NodeType;
6 |
7 | /**
8 | * ObjectNode represents JavaBean or Map.
9 | *
10 | * @author sulin
11 | * @since 2019-05-08 21:02:12
12 | */
13 | public final class ObjectNode extends Node {
14 |
15 | public final static ObjectNode EMPTY = new ObjectNode(true, new String[0], new Object[0]);
16 |
17 | /**
18 | * Stable object's keys must be ordered
19 | */
20 | private final boolean stable;
21 |
22 | private final String[] keys;
23 | private final Object[] fields;
24 | private final Type[] types;
25 |
26 | public ObjectNode(boolean stable, String[] keys, Object[] values) {
27 | this.stable = stable;
28 | this.keys = keys;
29 | this.fields = values;
30 | this.types = null;
31 | }
32 |
33 | public ObjectNode(boolean stable, String[] keys, Object[] values, Type[] types) {
34 | this.stable = stable;
35 | this.keys = keys;
36 | this.fields = values;
37 | this.types = types;
38 | }
39 |
40 | public boolean isStable() {
41 | return stable;
42 | }
43 |
44 | public String[] keys() {
45 | return keys;
46 | }
47 |
48 | public Object[] values() {
49 | return fields;
50 | }
51 |
52 | public Type[] types() {
53 | return types;
54 | }
55 |
56 | @Override
57 | public Object value() {
58 | return this;
59 | }
60 |
61 | @Override
62 | public NodeType type() {
63 | return NodeType.OBJECT;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/StringNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * StringNode represents String.
8 | *
9 | * @author sulin
10 | * @since 2019-05-08 21:00:34
11 | */
12 | public final class StringNode extends Node {
13 |
14 | public final static StringNode EMPTY = new StringNode("");
15 |
16 | private final String value;
17 |
18 | private StringNode(String value) {
19 | this.value = value;
20 | }
21 |
22 | public static StringNode valueOf(String str) {
23 | if (str.isEmpty()) {
24 | return EMPTY;
25 | }
26 | return new StringNode(str);
27 | }
28 |
29 | @Override
30 | public Object value() {
31 | return value;
32 | }
33 |
34 | @Override
35 | public NodeType type() {
36 | return NodeType.STRING;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/SymbolNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 |
6 | /**
7 | * SymbolNode represents constant String or Enum etc.
8 | *
9 | * @author sulin
10 | * @since 2019-06-04 20:23:31
11 | */
12 | public final class SymbolNode extends Node {
13 |
14 | private String data;
15 |
16 | private SymbolNode(String data) {
17 | this.data = data;
18 | }
19 |
20 | public static SymbolNode valueOf(String str) {
21 | return new SymbolNode(str);
22 | }
23 |
24 | public static SymbolNode valueOf(Enum en) {
25 | return new SymbolNode(en.name()); // don't need cache
26 | }
27 |
28 | @Override
29 | public Object value() {
30 | return data;
31 | }
32 |
33 | @Override
34 | public NodeType type() {
35 | return NodeType.SYMBOL;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/node/basic/VarintNode.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node.basic;
2 |
3 | import com.github.smartbuf.node.Node;
4 | import com.github.smartbuf.node.NodeType;
5 | import com.github.smartbuf.utils.NumberUtils;
6 |
7 | /**
8 | * VarintNode represents all number like byte/short/int/long.
9 | *
10 | * @author sulin
11 | * @since 2019-05-08 21:00:46
12 | */
13 | public final class VarintNode extends Node {
14 |
15 | private final static VarintNode[] TABLE = new VarintNode[256];
16 |
17 | static {
18 | for (int i = 0; i < TABLE.length; i++) {
19 | TABLE[i] = new VarintNode(NumberUtils.uintToInt(i));
20 | }
21 | }
22 |
23 | private final long value;
24 |
25 | private VarintNode(long value) {
26 | this.value = value;
27 | }
28 |
29 | public static VarintNode valueOf(byte b) {
30 | return valueOf((long) b);
31 | }
32 |
33 | public static VarintNode valueOf(Byte b) {
34 | return valueOf(b.byteValue());
35 | }
36 |
37 | public static VarintNode valueOf(short s) {
38 | return valueOf((long) s);
39 | }
40 |
41 | public static VarintNode valueOf(Short s) {
42 | return valueOf(s.shortValue());
43 | }
44 |
45 | public static VarintNode valueOf(int i) {
46 | return valueOf((long) i);
47 | }
48 |
49 | public static VarintNode valueOf(Integer i) {
50 | return valueOf(i.intValue());
51 | }
52 |
53 | public static VarintNode valueOf(long l) {
54 | long ul = NumberUtils.intToUint(l);
55 | if (ul >= 0 && ul < TABLE.length) {
56 | return TABLE[(int) ul];
57 | }
58 | return new VarintNode(l);
59 | }
60 |
61 | public static VarintNode valueOf(Long l) {
62 | return valueOf(l.longValue());
63 | }
64 |
65 | @Override
66 | public Object value() {
67 | return value;
68 | }
69 |
70 | @Override
71 | public NodeType type() {
72 | return NodeType.VARINT;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/reflect/BeanField.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import com.github.smartbuf.Type;
4 |
5 | import java.lang.reflect.Field;
6 | import java.lang.reflect.Method;
7 |
8 | /**
9 | * BeanField represents an field which support getter or setter
10 | *
11 | * @author sulin
12 | * @since 2019-10-29 15:46:00
13 | */
14 | public final class BeanField {
15 |
16 | final String name;
17 | final Class cls;
18 | final Type type;
19 |
20 | Field field;
21 | Method getter;
22 | Method setter;
23 |
24 | public BeanField(String name, Class cls) {
25 | this.name = name;
26 | this.cls = cls;
27 | this.type = Type.valueOf(cls);
28 | }
29 |
30 | public String getName() {
31 | return name;
32 | }
33 |
34 | public Type getType() {
35 | return type;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/reflect/BeanReader.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import com.github.smartbuf.Type;
4 |
5 | /**
6 | * BeanReader provides {@link #getValues} for normal pojos.
7 | *
8 | * @author sulin
9 | * @since 2019-11-08 18:01:40
10 | */
11 | public final class BeanReader {
12 |
13 | static String API_NAME = API.class.getName().replace('.', '/');
14 |
15 | final API api;
16 | final BeanField[] fields;
17 | final String[] fieldNames;
18 | final Type[] fieldTypes;
19 |
20 | BeanReader(API api, BeanField[] fields) {
21 | this.api = api;
22 | this.fields = fields;
23 | this.fieldNames = new String[fields.length];
24 | this.fieldTypes = new Type[fields.length];
25 | for (int i = 0; i < fields.length; i++) {
26 | BeanField field = fields[i];
27 | this.fieldNames[i] = field.getName();
28 | this.fieldTypes[i] = field.getType();
29 | }
30 | }
31 |
32 | /**
33 | * Get all readable field's names of this reader
34 | *
35 | * @return All readable field's names
36 | */
37 | public String[] getFieldNames() {
38 | return fieldNames;
39 | }
40 |
41 | /**
42 | * Get all readable field's types of this reader
43 | *
44 | * @return All readable field's types
45 | */
46 | public Type[] getFieldTypes() {
47 | return fieldTypes;
48 | }
49 |
50 | /**
51 | * Get all values of the specified object's properties.
52 | *
53 | * @param t The specified object to get values
54 | * @return t's all values
55 | */
56 | public Object[] getValues(Object t) {
57 | Object[] result = new Object[fieldNames.length];
58 | api.getAll(t, result);
59 | return result;
60 | }
61 |
62 | public interface API {
63 | /**
64 | * Fetch all properties of the specified object by predefined fields and their order
65 | *
66 | * @param o The Object to access, its getter will be called in predefined order
67 | * @param values The array to accept getter's result
68 | */
69 | void getAll(Object o, Object[] values);
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/reflect/BeanWriter.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | /**
4 | * BeanWriter provides {@link #setValues} for normal pojos.
5 | *
6 | * @author sulin
7 | * @since 2019-11-08 17:52:09
8 | */
9 | public final class BeanWriter {
10 |
11 | static String API_NAME = API.class.getName().replace('.', '/');
12 |
13 | private final API api;
14 | private final BeanField[] fields;
15 |
16 | public BeanWriter(API api, BeanField[] fields) {
17 | this.api = api;
18 | this.fields = fields;
19 | }
20 |
21 | /**
22 | * Get all fields of this reader
23 | *
24 | * @return All fields
25 | */
26 | public BeanField[] getFields() {
27 | return fields;
28 | }
29 |
30 | /**
31 | * Set all values of the specified object' properties
32 | *
33 | * @param t The specified object to set values
34 | * @param values all values to setup
35 | */
36 | public void setValues(Object t, Object[] values) {
37 | if (values == null || values.length != fields.length) {
38 | throw new IllegalArgumentException("invalid values");
39 | }
40 | api.setAll(t, values);
41 | }
42 |
43 | public interface API {
44 | /**
45 | * Setup all properties of the specified object by predefined fields and their order
46 | *
47 | * @param o The Object to access, its setter will be called in predefined order
48 | * @param values The values which need to set into object
49 | */
50 | void setAll(Object o, Object[] values);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/reflect/TypeRef.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import java.lang.reflect.ParameterizedType;
4 | import java.lang.reflect.Type;
5 |
6 | /**
7 | * Comment copied from `fastjson`:
8 | *
9 | * Represents a generic type {@code T}. Java doesn't yet provide a way to
10 | * represent generic types, so this class does. Forces clients to create a
11 | * subclass of this class which enables retrieval the type information even at
12 | * runtime.
13 | *
14 | * @author sulin
15 | * @since 2019-07-22 15:38:53
16 | */
17 | public abstract class TypeRef {
18 |
19 | private final Type type;
20 |
21 | /**
22 | * Constructs a new type literal. Derives represented class from type parameter.
23 | *
24 | * If caller didnt specify generic type, throw exception directly.
25 | */
26 | protected TypeRef() {
27 | Type superClass = getClass().getGenericSuperclass();
28 | if (superClass instanceof ParameterizedType) {
29 | type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
30 | } else {
31 | throw new IllegalArgumentException("Must specify TypeRef's parameterized type");
32 | }
33 | }
34 |
35 | /**
36 | * Gets underlying {@code Type} instance.
37 | *
38 | * @return The underlying java type
39 | */
40 | public Type getType() {
41 | return type;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/reflect/XField.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import java.lang.reflect.Field;
4 |
5 | /**
6 | * XField represents a field of class, with clear generic type.
7 | *
8 | * @author sulin
9 | * @since 2019-07-15 20:42:17
10 | */
11 | public final class XField {
12 |
13 | /**
14 | * Field's name
15 | */
16 | private String name;
17 | /**
18 | * Java's reflect field
19 | */
20 | private Field field;
21 | /**
22 | * Field's clear type
23 | */
24 | private XType type;
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public Field getField() {
35 | return field;
36 | }
37 |
38 | public void setField(Field field) {
39 | this.field = field;
40 | }
41 |
42 | public XType getType() {
43 | return type;
44 | }
45 |
46 | public void setType(XType type) {
47 | this.type = type;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/reflect/XTypeUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import java.lang.ref.Reference;
4 | import java.lang.reflect.Type;
5 | import java.util.Collection;
6 | import java.util.Map;
7 |
8 | /**
9 | * This is a convenience utils for XTypeFactory, use common Classes as Stop-Classes by default.
10 | *
11 | * @author sulin
12 | * @since 2019-07-22 14:46:05
13 | */
14 | public final class XTypeUtils {
15 |
16 | // Global default XTypeFactory
17 | private static final XTypeFactory factory = new XTypeFactory().addStopClass(
18 | Object[].class,
19 | Boolean.class,
20 | Number.class,
21 | CharSequence.class,
22 | Collection.class,
23 | Map.class,
24 | Reference.class
25 | );
26 |
27 | private XTypeUtils() {
28 | }
29 |
30 | /**
31 | * Convert Type to XType, all generic types should be resolved.
32 | *
33 | * @param type Standard type like Class/ParameterizedType/GenericArrayType/etc...
34 | * @return XType instance
35 | */
36 | public static XType> toXType(Type type) {
37 | return factory.toXType(type);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/transport/Array.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * Array like T[], but support more features like auto-scale
7 | *
8 | * @author sulin
9 | * @since 2019-09-26 14:21:44
10 | */
11 | @SuppressWarnings("unchecked")
12 | public final class Array {
13 |
14 | private int size;
15 | private T[] data;
16 |
17 | /**
18 | * Add new object into the final offset of this List
19 | *
20 | * @param val New object of T
21 | * @return New item's offset
22 | */
23 | public int add(T val) {
24 | int pos = this.size;
25 | this.put(pos, val);
26 | return pos;
27 | }
28 |
29 | /**
30 | * Put value into the specified offset of this List
31 | *
32 | * @param pos The specified offset
33 | * @param val New instance of T
34 | */
35 | public void put(int pos, T val) {
36 | if (data == null) {
37 | data = (T[]) new Object[4];
38 | }
39 | if (pos >= data.length) {
40 | T[] newArr = (T[]) new Object[data.length * 2];
41 | System.arraycopy(data, 0, newArr, 0, data.length);
42 | data = newArr;
43 | }
44 | if (pos >= this.size) {
45 | size = pos + 1;
46 | }
47 | data[pos] = val;
48 | }
49 |
50 | /**
51 | * Get T value from the specified offset
52 | *
53 | * @param offset The specified offset to fetch
54 | * @return Value at offsetd
55 | */
56 | public T get(int offset) {
57 | return data[offset];
58 | }
59 |
60 | /**
61 | * Return real size of this array
62 | *
63 | * @return real size of this array
64 | */
65 | public int size() {
66 | return size;
67 | }
68 |
69 | /**
70 | * Return capacity of this array
71 | *
72 | * @return capacity of this array
73 | */
74 | public int cap() {
75 | return data == null ? 0 : data.length;
76 | }
77 |
78 | /**
79 | * Clear this array, don't need release reference, only reset position
80 | */
81 | public void clear() {
82 | size = 0;
83 | }
84 |
85 | @Override
86 | public boolean equals(Object obj) {
87 | if (!(obj instanceof Array)) {
88 | return false;
89 | }
90 | Array objArr = (Array) obj;
91 | if (objArr.size != size) {
92 | return false;
93 | }
94 | for (int i = 0; i < size; i++) {
95 | if (!Objects.deepEquals(data[i], objArr.data[i])) {
96 | return false;
97 | }
98 | }
99 | return true;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/transport/Const.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | /**
4 | * Constants that shared between input and output
5 | *
6 | * @author sulin
7 | * @since 2019-10-02 16:42:24
8 | */
9 | interface Const {
10 |
11 | byte VER = 0b0001_0000;
12 | byte VER_STREAM = 0b0000_1000;
13 | byte VER_HAS_DATA = 0b0000_0100;
14 | byte VER_HAS_META = 0b0000_0010;
15 | byte VER_HAS_SEQ = 0b0000_0001;
16 |
17 | byte FLAG_META_NAME_TMP = 1 << 1;
18 | byte FLAG_META_NAME_ADDED = 2 << 1;
19 | byte FLAG_META_NAME_EXPIRED = 3 << 1;
20 | byte FLAG_META_STRUCT_TMP = 4 << 1;
21 | byte FLAG_META_STRUCT_ADDED = 5 << 1;
22 | byte FLAG_META_STRUCT_EXPIRED = 6 << 1;
23 | byte FLAG_META_STRUCT_REFERRED = 7 << 1;
24 |
25 | byte FLAG_DATA_FLOAT = 1 << 1;
26 | byte FLAG_DATA_DOUBLE = 2 << 1;
27 | byte FLAG_DATA_VARINT = 3 << 1;
28 | byte FLAG_DATA_STRING = 4 << 1;
29 | byte FLAG_DATA_SYMBOL_ADDED = 5 << 1;
30 | byte FLAG_DATA_SYMBOL_EXPIRED = 6 << 1;
31 |
32 | byte CONST_NULL = 0x00;
33 | byte CONST_FALSE = 0x01;
34 | byte CONST_TRUE = 0x02;
35 | byte CONST_ZERO_ARRAY = 0x03;
36 |
37 | byte TYPE_CONST = -1;
38 | byte TYPE_VARINT = 0;
39 | byte TYPE_FLOAT = 1;
40 | byte TYPE_DOUBLE = 2;
41 | byte TYPE_STRING = 3;
42 | byte TYPE_SYMBOL = 4;
43 | byte TYPE_OBJECT = 5;
44 | byte TYPE_ARRAY = 6;
45 | byte TYPE_NARRAY = 7;
46 |
47 | byte TYPE_NARRAY_BOOL = 1 << 3 | TYPE_NARRAY;
48 | byte TYPE_NARRAY_BYTE = 2 << 3 | TYPE_NARRAY;
49 | byte TYPE_NARRAY_SHORT = 3 << 3 | TYPE_NARRAY;
50 | byte TYPE_NARRAY_INT = 4 << 3 | TYPE_NARRAY;
51 | byte TYPE_NARRAY_LONG = 5 << 3 | TYPE_NARRAY;
52 | byte TYPE_NARRAY_FLOAT = 6 << 3 | TYPE_NARRAY;
53 | byte TYPE_NARRAY_DOUBLE = 7 << 3 | TYPE_NARRAY;
54 |
55 | byte TYPE_SLICE_NULL = 0x00;
56 | byte TYPE_SLICE_BOOL = 0x01;
57 | byte TYPE_SLICE_FLOAT = 0x02;
58 | byte TYPE_SLICE_DOUBLE = 0x03;
59 | byte TYPE_SLICE_BYTE = 0x04;
60 | byte TYPE_SLICE_SHORT = 0x05;
61 | byte TYPE_SLICE_INT = 0x06;
62 | byte TYPE_SLICE_LONG = 0x07;
63 | byte TYPE_SLICE_STRING = 0x08;
64 | byte TYPE_SLICE_SYMBOL = 0x09;
65 | byte TYPE_SLICE_OBJECT = 0x0A;
66 | byte TYPE_SLICE_UNKNOWN = 0x0B;
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/transport/IDAllocator.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import com.github.smartbuf.utils.ArrayUtils;
4 |
5 | /**
6 | * allocate [0, max] id
7 | *
8 | * @author sulin
9 | * @since 2019-04-29 17:37:20
10 | */
11 | public final class IDAllocator {
12 |
13 | /**
14 | * The next incremental id, if no reuseIds, it should be used at next time.
15 | */
16 | private int nextId;
17 | /**
18 | * The real count of reuseIds.
19 | */
20 | private int reuseCount;
21 | /**
22 | * The id was released.
23 | */
24 | private int[] reuseIds;
25 |
26 | /**
27 | * Acquire an unique and incremental id, if have released id, use it first.
28 | *
29 | * @return Unique and incremental id
30 | */
31 | public int acquire() {
32 | if (reuseCount == 0) {
33 | return nextId++;
34 | }
35 | return this.reuseIds[--reuseCount];
36 | }
37 |
38 | /**
39 | * Release the specified id, It will be used in high priority.
40 | *
41 | * @param id ID was released
42 | */
43 | public void release(int id) {
44 | if (id >= nextId) {
45 | throw new IllegalArgumentException(id + " is not acquired");
46 | }
47 | if (reuseIds == null) {
48 | reuseIds = new int[4];
49 | } else if (reuseCount >= reuseIds.length) {
50 | int[] tmp = new int[reuseIds.length * 2];
51 | System.arraycopy(reuseIds, 0, tmp, 0, reuseIds.length);
52 | this.reuseIds = tmp;
53 | }
54 | this.reuseIds[this.reuseCount] = id;
55 | ArrayUtils.descFastSort(this.reuseIds, 0, this.reuseCount);
56 |
57 | this.reuseCount++;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/utils/ArrayUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import java.lang.reflect.Array;
4 |
5 | /**
6 | * Some utils for array, meanly sort
7 | *
8 | * @author sulin
9 | * @since 2019-10-02 15:16:34
10 | */
11 | public final class ArrayUtils {
12 |
13 | private ArrayUtils() {
14 | }
15 |
16 | /**
17 | * Fast-Sort arithmetic which support descend sort for int[]
18 | *
19 | * @param arr Source array
20 | * @param from start offset, include
21 | * @param to end offset, include
22 | */
23 | public static void descFastSort(final int[] arr, final int from, final int to) {
24 | if (to - from < 1) {
25 | return;
26 | }
27 | int low = from;
28 | int high = to;
29 | int baseVal = arr[low];
30 |
31 | while (low < high) {
32 | for (; high > low; high--) {
33 | if (arr[high] > baseVal) {
34 | arr[low] = arr[high];
35 | low++;
36 | break;
37 | }
38 | }
39 | for (; high > low; low++) {
40 | if (arr[low] < baseVal) {
41 | arr[high] = arr[low];
42 | high--;
43 | break;
44 | }
45 | }
46 | }
47 |
48 | arr[low] = baseVal;
49 | if (low - from > 1) {
50 | descFastSort(arr, from, low - 1);
51 | }
52 | if (to - low > 1) {
53 | descFastSort(arr, low + 1, to);
54 | }
55 | }
56 |
57 | /**
58 | * Fast-Sort arithmetic which support descend sort for long[]
59 | *
60 | * @param arr Source array
61 | * @param from start offset, include
62 | * @param to end offset, include
63 | */
64 | public static void descFastSort(final long[] arr, final int from, final int to) {
65 | if (to - from < 1) {
66 | return;
67 | }
68 | int low = from;
69 | int high = to;
70 | long baseVal = arr[low];
71 |
72 | while (low < high) {
73 | for (; high > low; high--) {
74 | if (arr[high] > baseVal) {
75 | arr[low] = arr[high];
76 | low++;
77 | break;
78 | }
79 | }
80 | for (; high > low; low++) {
81 | if (arr[low] < baseVal) {
82 | arr[high] = arr[low];
83 | high--;
84 | break;
85 | }
86 | }
87 | }
88 |
89 | arr[low] = baseVal;
90 | if (low - from > 1) {
91 | descFastSort(arr, from, low - 1);
92 | }
93 | if (to - low > 1) {
94 | descFastSort(arr, low + 1, to);
95 | }
96 | }
97 |
98 | /**
99 | * put value into array's specified position, execute expansion automatically.
100 | *
101 | * @param arr Source array
102 | * @param pos Put position
103 | * @param val New item
104 | * @param T
105 | * @return Put result
106 | */
107 | @SuppressWarnings("unchecked")
108 | public static T[] put(T[] arr, int pos, T val) {
109 | if (arr == null) {
110 | arr = (T[]) new Object[4];
111 | }
112 | if (arr.length <= pos) {
113 | T[] newArr = (T[]) Array.newInstance(arr.getClass().getComponentType(), arr.length * 2);
114 | System.arraycopy(arr, 0, newArr, 0, arr.length);
115 | arr = newArr;
116 | }
117 | arr[pos] = val;
118 | return arr;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/utils/CodecUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import com.github.smartbuf.converter.Codec;
4 | import com.github.smartbuf.converter.CodecFactory;
5 | import com.github.smartbuf.converter.ConverterPipeline;
6 | import com.github.smartbuf.node.NodeCodec;
7 | import com.github.smartbuf.reflect.TypeRef;
8 | import com.github.smartbuf.reflect.XType;
9 |
10 | import java.lang.reflect.Type;
11 |
12 | /**
13 | * CodecUtils wraps an global {@link CodecFactory} and provides some useful features.
14 | *
15 | * @author sulin
16 | * @since 2019-11-09 20:19:49
17 | */
18 | public final class CodecUtils {
19 |
20 | private static final CodecFactory factory = new CodecFactory();
21 |
22 | static {
23 | factory.installCodec(NodeCodec.class);
24 | }
25 |
26 | private CodecUtils() {
27 | }
28 |
29 | /**
30 | * Install new {@link Codec} into the default CodecFactory
31 | *
32 | * @param codec The new codec implementation
33 | */
34 | public static void installCodec(Codec codec) {
35 | factory.installCodec(codec);
36 | }
37 |
38 | /**
39 | * Convert the specified object to instance of the specified class
40 | *
41 | * @param src source data
42 | * @param clz target class
43 | * @param Target template type
44 | * @return instance of the specified class
45 | */
46 | public static T convert(Object src, Class clz) {
47 | return factory.convert(src, clz);
48 | }
49 |
50 | /**
51 | * Convert the specified object to the specified type
52 | *
53 | * @param src Source data
54 | * @param type Target type
55 | * @param Target's real type
56 | * @return instance of the specified type
57 | */
58 | public static T convert(Object src, TypeRef type) {
59 | return convert(src, type.getType());
60 | }
61 |
62 | /**
63 | * Convert the specified object to the specified type
64 | *
65 | * @param src Source data
66 | * @param type Target type, suport generic type
67 | * @param Target's real type
68 | * @return instance of the specified type
69 | */
70 | @SuppressWarnings("unchecked")
71 | public static T convert(Object src, Type type) {
72 | return (T) factory.convert(src, type);
73 | }
74 |
75 | /**
76 | * Convert the specified {@link Type} into {@link XType}
77 | *
78 | * @param type original type
79 | * @return type's XType instance
80 | */
81 | public static XType> toXType(Type type) {
82 | return factory.toXType(type);
83 | }
84 |
85 | /**
86 | * Get a pipeline which could convert srcClass's instance into tgtClass's instance
87 | *
88 | * @param srcClass Source Class
89 | * @param tgtClass Target Class
90 | * @return The final pipeline
91 | */
92 | public static ConverterPipeline getPipeline(Class srcClass, Class tgtClass) {
93 | return factory.getPipeline(srcClass, tgtClass);
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/utils/NumberUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | /**
4 | * NumberUtils provides some useful features for number convert operation.
5 | *
6 | * @author sulin
7 | * @since 2019-04-27 16:03:53
8 | */
9 | public final class NumberUtils {
10 |
11 | private NumberUtils() {
12 | }
13 |
14 | public static long intToUint(long l) {
15 | return (l << 1) ^ (l >> 63);
16 | }
17 |
18 | public static long uintToInt(long l) {
19 | return (l >>> 1) ^ -(l & 1);
20 | }
21 |
22 | public static int floatToBits(float f) {
23 | return Float.floatToRawIntBits(f);
24 | }
25 |
26 | public static float bitsToFloat(int i) {
27 | return Float.intBitsToFloat(i);
28 | }
29 |
30 | public static long doubleToBits(double d) {
31 | return Double.doubleToRawLongBits(d);
32 | }
33 |
34 | public static double bitsToDouble(long l) {
35 | return Double.longBitsToDouble(l);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/utils/TimeUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import java.lang.management.ManagementFactory;
4 |
5 | /**
6 | * Some time utils for convenience or performance
7 | *
8 | * @author sulin
9 | * @since 2019-10-08 21:02:56
10 | */
11 | public final class TimeUtils {
12 |
13 | public static int INTERVAL = 500;
14 |
15 | static final long UP_TIME = ManagementFactory.getRuntimeMXBean().getStartTime();
16 | static final Thread TIMER_THREAD;
17 |
18 | private static long now;
19 | private static long uptime;
20 |
21 | static {
22 | TIMER_THREAD = new Thread(() -> {
23 | while (true) {
24 | flush();
25 | try {
26 | Thread.sleep(INTERVAL);
27 | } catch (InterruptedException ignored) {
28 | }
29 | }
30 | });
31 | TIMER_THREAD.setName("TimeUtils-Timer");
32 | TIMER_THREAD.setDaemon(true);
33 | TIMER_THREAD.start();
34 | flush();
35 | }
36 |
37 | private TimeUtils() {
38 | }
39 |
40 | /**
41 | * Fetch current second from 1970.1.1, this is faster and fuzzier
42 | *
43 | * @return Now second
44 | */
45 | public static long fastNow() {
46 | return now;
47 | }
48 |
49 | /**
50 | * Fetch current second from uptime, this is faster and fuzzier
51 | *
52 | * @return Uptime second
53 | */
54 | public static long fastUpTime() {
55 | return uptime;
56 | }
57 |
58 | private static void flush() {
59 | long ms = System.currentTimeMillis();
60 | now = ms;
61 | uptime = ms - UP_TIME;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/github/smartbuf/utils/UTF8Utils.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import java.nio.charset.Charset;
4 |
5 | /**
6 | * UTF8Utils wraps encode and decode functions for utf-8 charset,
7 | * it provides higher performance to convert String as byte[]
8 | *
9 | * @author sulin
10 | * @since 2019-11-05 19:51:53
11 | */
12 | public final class UTF8Utils {
13 |
14 | public static final byte REPL = 63;
15 |
16 | private UTF8Utils() {
17 | }
18 |
19 | /**
20 | * Encode the speicifed CharSequence into byte[], it works like {@link String#getBytes(Charset)}
21 | *
22 | * @param cs The original string to encode
23 | * @return Encoding result
24 | */
25 | public static byte[] encode(CharSequence cs) {
26 | byte[] buf = new byte[cs.length() * 3];
27 | int size = encode(cs, buf, 0);
28 | byte[] result = new byte[size];
29 | System.arraycopy(buf, 0, result, 0, size);
30 | return result;
31 | }
32 |
33 | /**
34 | * Use UTF-8 encode the specified {@link CharSequence} to bytes, and write them into the specified buf
35 | *
36 | * @param str The original string to encode
37 | * @param buf The buffer to accept encoding result
38 | * @param bufOffset buf's write offset
39 | * @return Final position of writing
40 | */
41 | public static int encode(CharSequence str, byte[] buf, int bufOffset) {
42 | int charOff = 0;
43 | int charNum = str.length();
44 |
45 | // encode the beginning ascii chars [0, 128)
46 | for (char c; charOff < charNum; charOff++) {
47 | if ((c = str.charAt(charOff)) >= 128) {
48 | break;
49 | }
50 | buf[bufOffset++] = (byte) c;
51 | }
52 |
53 | while (charOff < charNum) {
54 | char c = str.charAt(charOff++);
55 | if (c < 128) {
56 | buf[bufOffset++] = (byte) c;
57 | } else if (c < 2048) {
58 | buf[bufOffset++] = (byte) (192 | c >> 6);
59 | buf[bufOffset++] = (byte) (128 | c & 63);
60 | } else if (Character.isSurrogate(c)) {
61 |
62 | int code = parse(str, c, charOff - 1, charNum);
63 | if (code < 0) {
64 | buf[bufOffset++] = REPL;
65 | } else {
66 | buf[bufOffset++] = (byte) (240 | code >> 18);
67 | buf[bufOffset++] = (byte) (128 | code >> 12 & 63);
68 | buf[bufOffset++] = (byte) (128 | code >> 6 & 63);
69 | buf[bufOffset++] = (byte) (128 | code & 63);
70 | ++charOff;
71 | }
72 | } else {
73 | buf[bufOffset++] = (byte) (224 | c >> 12);
74 | buf[bufOffset++] = (byte) (128 | c >> 6 & 63);
75 | buf[bufOffset++] = (byte) (128 | c & 63);
76 | }
77 | }
78 |
79 | return bufOffset;
80 | }
81 |
82 | /**
83 | * surrogate char parser, mainly copied from {@link sun.nio.cs.Surrogate.Parser#parse}
84 | */
85 | private static int parse(CharSequence cs, char c, int pos, int limit) {
86 | int character;
87 | if (Character.isHighSurrogate(c)) {
88 | if (limit - pos < 2) {
89 | return -1;
90 | } else {
91 | char var5 = cs.charAt(pos + 1);
92 | if (Character.isLowSurrogate(var5)) {
93 | character = Character.toCodePoint(c, var5);
94 | return character;
95 | } else {
96 | return -1;
97 | }
98 | }
99 | } else {
100 | return -1;
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/Runner.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark;
2 |
3 | import com.github.smartbuf.benchmark.large.LargeDeserBenchmark;
4 | import com.github.smartbuf.benchmark.large.LargeSerialBenchmark;
5 | import com.github.smartbuf.benchmark.medium.MediumDeserBenchmark;
6 | import com.github.smartbuf.benchmark.medium.MediumSerialBenchmark;
7 | import com.github.smartbuf.benchmark.small.SmallDeserBenchmark;
8 | import com.github.smartbuf.benchmark.small.SmallSerialBenchmark;
9 | import org.openjdk.jmh.runner.RunnerException;
10 | import org.openjdk.jmh.runner.options.OptionsBuilder;
11 |
12 | /**
13 | * @author sulin
14 | * @since 2019-11-12 12:13:41
15 | */
16 | public class Runner {
17 |
18 | public static void main(String[] args) {
19 | OptionsBuilder builder = new OptionsBuilder();
20 |
21 | builder.include(SmallSerialBenchmark.class.getName());
22 | builder.include(SmallDeserBenchmark.class.getName());
23 |
24 | builder.include(MediumSerialBenchmark.class.getName());
25 | builder.include(MediumDeserBenchmark.class.getName());
26 |
27 | builder.include(LargeSerialBenchmark.class.getName());
28 | builder.include(LargeDeserBenchmark.class.getName());
29 |
30 | try {
31 | new org.openjdk.jmh.runner.Runner(builder.build()).run();
32 | } catch (RunnerException e) {
33 | throw new RuntimeException(e);
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/TestBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark;
2 |
3 | import org.apache.commons.lang3.RandomUtils;
4 | import org.openjdk.jmh.annotations.*;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.concurrent.TimeUnit;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-10-30 20:21:38
13 | */
14 | @Warmup(iterations = 2, time = 2)
15 | @Fork(2)
16 | @Measurement(iterations = 3, time = 3)
17 | @BenchmarkMode(Mode.AverageTime)
18 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
19 | public class TestBenchmark {
20 |
21 | static Object[] arr = new Object[1024];
22 | static List list = new ArrayList<>();
23 |
24 | static {
25 | for (int i = 0; i < arr.length; i++) {
26 | arr[i] = RandomUtils.nextDouble();
27 | list.add(arr[i]);
28 | }
29 | }
30 |
31 | @Benchmark
32 | public void test() {
33 | Class> prevCls = null;
34 | Class> currCls = null;
35 | int i = 0;
36 | // 674ns
37 | for (Object o : list) {
38 | currCls = o == null ? null : o.getClass();
39 | if (prevCls == currCls) {
40 | i++;
41 | }
42 | prevCls = currCls;
43 | }
44 | }
45 |
46 | @Benchmark
47 | public void test2() {
48 | Class> cls = Object.class;
49 | cls.isEnum();
50 | cls.isArray();
51 | cls.getName();
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/large/LargeDeserBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.large;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.io.ByteBufferInput;
5 | import com.esotericsoftware.kryo.io.ByteBufferOutput;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.github.smartbuf.SmartPacket;
8 | import com.github.smartbuf.SmartStream;
9 | import org.msgpack.MessagePack;
10 | import org.openjdk.jmh.annotations.*;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * Benchmark Mode Cnt Score Error Units
17 | * LargeDeserBenchmark.json avgt 9 215988.530 ± 14369.676 ns/op
18 | * LargeDeserBenchmark.kryo avgt 9 144229.596 ± 8665.693 ns/op
19 | * LargeDeserBenchmark.msgpack avgt 9 91418.850 ± 2470.538 ns/op
20 | * LargeDeserBenchmark.protobuf avgt 9 49573.240 ± 483.989 ns/op
21 | * LargeDeserBenchmark.sb_packet avgt 9 105982.178 ± 6484.683 ns/op
22 | * LargeDeserBenchmark.sb_stream avgt 9 98243.964 ± 2018.606 ns/op
23 | *
24 | * @author sulin
25 | * @since 2019-11-11 10:58:07
26 | */
27 | @Warmup(iterations = 2, time = 2)
28 | @Fork(3)
29 | @Measurement(iterations = 3, time = 3)
30 | @BenchmarkMode(Mode.AverageTime)
31 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
32 | public class LargeDeserBenchmark {
33 |
34 | static final LargeTest.TrendsModel trends = LargeTest.trendsModel;
35 |
36 | static final ObjectMapper MAPPER = new ObjectMapper();
37 | static final SmartStream STREAM = new SmartStream();
38 | static final MessagePack MSGPACK = new MessagePack();
39 | static final Kryo KRYO = new Kryo();
40 |
41 | static byte[] jsonBytes;
42 | static byte[] kryoBytes;
43 | static byte[] msgpackBytes;
44 | static byte[] pbBytes;
45 | static byte[] packetBytes;
46 | static byte[] streamBytes;
47 |
48 | static {
49 | ByteBufferOutput kryoOutput = new ByteBufferOutput(1 << 20);
50 |
51 | try {
52 | KRYO.writeObject(kryoOutput, trends);
53 | kryoBytes = kryoOutput.toBytes();
54 | jsonBytes = MAPPER.writeValueAsBytes(trends);
55 | msgpackBytes = MSGPACK.write(trends);
56 | pbBytes = trends.toPB().toByteArray();
57 | packetBytes = SmartPacket.serialize(trends);
58 | streamBytes = STREAM.serialize(trends);
59 |
60 | // smartbuf's stream-mode need warm up to avoid sequence error
61 | STREAM.deserialize(streamBytes, LargeTest.TrendsModel.class);
62 |
63 | jsonBytes = MAPPER.writeValueAsBytes(trends);
64 | pbBytes = trends.toPB().toByteArray();
65 | packetBytes = SmartPacket.serialize(trends);
66 | streamBytes = STREAM.serialize(trends);
67 | } catch (IOException e) {
68 | throw new RuntimeException(e);
69 | }
70 | }
71 |
72 | @Benchmark
73 | public void json() throws Exception {
74 | MAPPER.readValue(jsonBytes, LargeTest.TrendsModel.class);
75 | }
76 |
77 | @Benchmark
78 | public void kryo() {
79 | KRYO.readObject(new ByteBufferInput(kryoBytes), LargeTest.TrendsModel.class);
80 | }
81 |
82 | @Benchmark
83 | public void msgpack() throws IOException {
84 | MSGPACK.read(msgpackBytes, LargeTest.TrendsModel.class);
85 | }
86 |
87 | @Benchmark
88 | public void protobuf() throws Exception {
89 | Large.Trends.parseFrom(pbBytes);
90 | }
91 |
92 | @Benchmark
93 | public void sb_packet() throws Exception {
94 | SmartPacket.deserialize(packetBytes, LargeTest.TrendsModel.class);
95 | }
96 |
97 | @Benchmark
98 | public void sb_stream() throws Exception {
99 | STREAM.deserialize(streamBytes, LargeTest.TrendsModel.class);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/large/LargeSerialBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.large;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.io.ByteBufferOutput;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.github.smartbuf.SmartPacket;
7 | import com.github.smartbuf.SmartStream;
8 | import org.msgpack.MessagePack;
9 | import org.openjdk.jmh.annotations.*;
10 |
11 | import java.io.IOException;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | /**
15 | * Benchmark Mode Cnt Score Error Units
16 | * LargeSerialBenchmark.json avgt 9 126749.482 ± 3173.811 ns/op
17 | * LargeSerialBenchmark.kryo avgt 9 134176.479 ± 1208.534 ns/op
18 | * LargeSerialBenchmark.msgpack avgt 9 70548.730 ± 3072.337 ns/op
19 | * LargeSerialBenchmark.protobuf avgt 9 97395.157 ± 1056.336 ns/op
20 | * LargeSerialBenchmark.sb_packet avgt 9 81460.734 ± 1396.504 ns/op
21 | * LargeSerialBenchmark.sb_stream avgt 9 77611.622 ± 430.881 ns/op
22 | *
23 | * @author sulin
24 | * @since 2019-11-10 16:12:28
25 | */
26 | @Warmup(iterations = 2, time = 2)
27 | @Fork(3)
28 | @Measurement(iterations = 3, time = 3)
29 | @BenchmarkMode(Mode.AverageTime)
30 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
31 | public class LargeSerialBenchmark {
32 |
33 | static final LargeTest.TrendsModel trends = LargeTest.trendsModel;
34 |
35 | static final ObjectMapper MAPPER = new ObjectMapper();
36 | static final SmartStream STREAM = new SmartStream();
37 | static final MessagePack MSGPACK = new MessagePack();
38 | static final Kryo KRYO = new Kryo();
39 |
40 | static ByteBufferOutput kryoOutput = new ByteBufferOutput(1 << 20);
41 |
42 | @Benchmark
43 | public void json() throws Exception {
44 | MAPPER.writeValueAsBytes(trends);
45 | }
46 |
47 | @Benchmark
48 | public void kryo() {
49 | KRYO.writeObject(kryoOutput, trends);
50 | kryoOutput.toBytes();
51 | kryoOutput.clear();
52 | }
53 |
54 | @Benchmark
55 | public void msgpack() throws IOException {
56 | MSGPACK.write(trends);
57 | }
58 |
59 | @Benchmark
60 | public void protobuf() {
61 | trends.toPB().toByteArray();
62 | }
63 |
64 | @Benchmark
65 | public void sb_packet() throws Exception {
66 | SmartPacket.serialize(trends);
67 | }
68 |
69 | @Benchmark
70 | public void sb_stream() throws Exception {
71 | STREAM.serialize(trends);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/medium/MediumDeserBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.medium;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.io.ByteBufferInput;
5 | import com.esotericsoftware.kryo.io.ByteBufferOutput;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.github.smartbuf.SmartPacket;
8 | import com.github.smartbuf.SmartStream;
9 | import org.msgpack.MessagePack;
10 | import org.openjdk.jmh.annotations.*;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * Benchmark Mode Cnt Score Error Units
17 | * MediumDeserBenchmark.json avgt 6 7040.950 ± 459.725 ns/op
18 | * MediumDeserBenchmark.kryo avgt 6 6432.450 ± 731.190 ns/op
19 | * MediumDeserBenchmark.msgpack avgt 6 15989.744 ± 208.045 ns/op
20 | * MediumDeserBenchmark.protobuf avgt 6 2598.041 ± 135.756 ns/op
21 | * MediumDeserBenchmark.sb_packet avgt 6 6819.044 ± 546.147 ns/op
22 | * MediumDeserBenchmark.sb_stream avgt 6 5466.728 ± 141.585 ns/op
23 | *
24 | * @author sulin
25 | * @since 2019-11-11 10:53:43
26 | */
27 | @Warmup(iterations = 2, time = 2)
28 | @Fork(2)
29 | @Measurement(iterations = 3, time = 3)
30 | @BenchmarkMode(Mode.AverageTime)
31 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
32 | public class MediumDeserBenchmark {
33 |
34 | private static final UserModel user = UserModel.random();
35 |
36 | static final ObjectMapper MAPPER = new ObjectMapper();
37 | static final SmartStream STREAM = new SmartStream();
38 | static final MessagePack MSGPACK = new MessagePack();
39 | static final Kryo KRYO = new Kryo();
40 |
41 | static byte[] jsonBytes;
42 | static byte[] kryoBytes;
43 | static byte[] msgpackBytes;
44 | static byte[] pbBytes;
45 | static byte[] packetBytes;
46 | static byte[] streamBytes;
47 |
48 | static {
49 | KRYO.register(UserModel.class);
50 | KRYO.register(UserModel.Message.class);
51 | KRYO.register(UserModel.Tag.class);
52 |
53 | ByteBufferOutput kryoOutput = new ByteBufferOutput(1024);
54 | try {
55 | KRYO.writeObject(kryoOutput, user);
56 |
57 | jsonBytes = MAPPER.writeValueAsBytes(user);
58 | msgpackBytes = MSGPACK.write(user);
59 | kryoBytes = kryoOutput.toBytes();
60 | pbBytes = user.toUser().toByteArray();
61 | packetBytes = SmartPacket.serialize(user);
62 | streamBytes = STREAM.serialize(user);
63 | // smartbuf's stream-mode need warm up to avoid sequence error
64 | STREAM.deserialize(streamBytes, UserModel.class);
65 |
66 | jsonBytes = MAPPER.writeValueAsBytes(user);
67 | pbBytes = user.toUser().toByteArray();
68 | packetBytes = SmartPacket.serialize(user);
69 | streamBytes = STREAM.serialize(user);
70 | } catch (IOException e) {
71 | throw new RuntimeException(e);
72 | }
73 | }
74 |
75 | @Benchmark
76 | public void json() throws Exception {
77 | MAPPER.readValue(jsonBytes, UserModel.class);
78 | }
79 |
80 | @Benchmark
81 | public void msgpack() throws IOException {
82 | MSGPACK.read(msgpackBytes, UserModel.class);
83 | }
84 |
85 | @Benchmark
86 | public void kryo() {
87 | KRYO.readObject(new ByteBufferInput(kryoBytes), UserModel.class);
88 | }
89 |
90 | @Benchmark
91 | public void protobuf() throws Exception {
92 | Medium.User.parseFrom(pbBytes);
93 | }
94 |
95 | @Benchmark
96 | public void sb_packet() throws Exception {
97 | SmartPacket.deserialize(packetBytes, UserModel.class);
98 | }
99 |
100 | @Benchmark
101 | public void sb_stream() throws Exception {
102 | STREAM.deserialize(streamBytes, UserModel.class);
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/medium/MediumSerialBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.medium;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.io.ByteBufferOutput;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.github.smartbuf.SmartPacket;
7 | import com.github.smartbuf.SmartStream;
8 | import org.msgpack.MessagePack;
9 | import org.openjdk.jmh.annotations.*;
10 |
11 | import java.util.concurrent.TimeUnit;
12 |
13 | /**
14 | * Benchmark Mode Cnt Score Error Units
15 | * MediumSerialBenchmark.json avgt 9 4329.829 ± 69.129 ns/op
16 | * MediumSerialBenchmark.kryo avgt 9 5325.744 ± 142.879 ns/op
17 | * MediumSerialBenchmark.msgpack avgt 9 21493.727 ± 207.717 ns/op
18 | * MediumSerialBenchmark.protobuf avgt 9 796.052 ± 11.317 ns/op
19 | * MediumSerialBenchmark.sb_packet avgt 9 4486.963 ± 43.700 ns/op
20 | * MediumSerialBenchmark.sb_stream avgt 9 3927.292 ± 57.563 ns/op
21 | *
22 | * @author sulin
23 | * @since 2019-10-31 20:40:55
24 | */
25 | @Warmup(iterations = 2, time = 2)
26 | @Fork(2)
27 | @Measurement(iterations = 3, time = 3)
28 | @BenchmarkMode(Mode.AverageTime)
29 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
30 | public class MediumSerialBenchmark {
31 |
32 | static final ObjectMapper MAPPER = new ObjectMapper();
33 | static final SmartStream STREAM = new SmartStream();
34 | static final MessagePack MSGPACK = new MessagePack();
35 | static final Kryo KRYO = new Kryo();
36 |
37 | static final UserModel model = UserModel.random();
38 |
39 | static final ByteBufferOutput kryoOutput = new ByteBufferOutput(1024);
40 |
41 | static {
42 | KRYO.register(UserModel.class);
43 | KRYO.register(UserModel.Message.class);
44 | KRYO.register(UserModel.Tag.class);
45 | }
46 |
47 | @Benchmark
48 | public void json() throws Exception {
49 | MAPPER.writeValueAsBytes(model);
50 | }
51 |
52 | @Benchmark
53 | public void msgpack() throws Exception {
54 | MSGPACK.write(model);
55 | }
56 |
57 | @Benchmark
58 | public void kryo() {
59 | KRYO.writeObject(kryoOutput, model);
60 | kryoOutput.toBytes();
61 | kryoOutput.clear();
62 | }
63 |
64 | @Benchmark
65 | public void protobuf() {
66 | model.toUser().toBuilder();
67 | }
68 |
69 | @Benchmark
70 | public void sb_packet() throws Exception {
71 | SmartPacket.serialize(model);
72 | }
73 |
74 | @Benchmark
75 | public void sb_stream() throws Exception {
76 | STREAM.serialize(model);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/medium/UserModel.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.medium;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import org.apache.commons.lang3.RandomStringUtils;
7 | import org.apache.commons.lang3.RandomUtils;
8 | import org.msgpack.annotation.Message;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.UUID;
13 |
14 | /**
15 | * @author sulin
16 | * @since 2019-10-31 19:58:41
17 | */
18 | @Data
19 | @Message
20 | public class UserModel {
21 |
22 | private long id;
23 | private String nickname;
24 | private String portrait;
25 | private float score;
26 | private String mail;
27 | private String mobile;
28 | private String token;
29 | private Integer type;
30 | private Integer source;
31 | private Boolean blocked;
32 | private int loginTimes;
33 | private long updateTime;
34 | private long createTime;
35 |
36 | private List msgs;
37 | private List tags;
38 |
39 | public static UserModel random() {
40 | UserModel user = new UserModel();
41 | user.id = RandomUtils.nextLong();
42 | user.nickname = RandomStringUtils.randomAlphanumeric(12);
43 | user.portrait = RandomStringUtils.randomAlphabetic(24);
44 | user.score = RandomUtils.nextFloat();
45 | user.mail = RandomStringUtils.randomAlphanumeric(16) + "@gmail.com";
46 | user.mobile = RandomStringUtils.randomNumeric(12);
47 | user.token = UUID.randomUUID().toString();
48 | user.type = RandomUtils.nextInt(1, 10);
49 | user.source = RandomUtils.nextInt(1, 10);
50 | user.blocked = RandomUtils.nextBoolean();
51 | user.loginTimes = RandomUtils.nextInt(10, 10000);
52 | user.updateTime = System.currentTimeMillis();
53 | user.createTime = System.currentTimeMillis();
54 | user.msgs = new ArrayList<>();
55 | user.tags = new ArrayList<>();
56 |
57 | long toUUID = RandomUtils.nextInt(1000000, 9999999);
58 | for (int i = 0; i < 10; i++) {
59 | Message m = new Message();
60 | m.id = (long) i;
61 | m.from = RandomUtils.nextLong(1000000, 9999999);
62 | m.to = toUUID;
63 | m.msg = RandomStringUtils.randomAlphabetic(40);
64 | m.timestamp = System.currentTimeMillis();
65 | user.msgs.add(m);
66 | }
67 | for (int i = 0; i < 16; i++) {
68 | user.tags.add(new Tag(i, "Tag" + i));
69 | }
70 | return user;
71 | }
72 |
73 | public Medium.User toUser() {
74 | Medium.User.Builder builder = Medium.User.newBuilder()
75 | .setId(id)
76 | .setNickname(nickname)
77 | .setPortrait(portrait)
78 | .setScore(score)
79 | .setMail(mail)
80 | .setMobile(mobile)
81 | .setToken(token)
82 | .setType(type)
83 | .setSource(source)
84 | .setBlocked(blocked)
85 | .setLoginTimes(loginTimes)
86 | .setUpdateTime(updateTime)
87 | .setCreateTime(createTime);
88 |
89 | for (Message msg : msgs) {
90 | builder.addMsgs(Medium.Message.newBuilder()
91 | .setId(msg.id)
92 | .setFrom(msg.from)
93 | .setTo(msg.to)
94 | .setMsg(msg.msg)
95 | .setTimestamp(msg.timestamp)
96 | .build());
97 | }
98 |
99 | for (Tag tag : tags) {
100 | builder.addTags(Medium.Tag.newBuilder()
101 | .setCode(tag.code)
102 | .setName(tag.name)
103 | .build());
104 | }
105 |
106 | return builder.build();
107 | }
108 |
109 | @Data
110 | @org.msgpack.annotation.Message
111 | public static class Message {
112 | private Long id;
113 | private Long from;
114 | private Long to;
115 | private String msg;
116 | private Long timestamp;
117 | }
118 |
119 | @Data
120 | @NoArgsConstructor
121 | @AllArgsConstructor
122 | @org.msgpack.annotation.Message
123 | public static class Tag {
124 | private int code;
125 | private String name;
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/small/SmallDeserBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.small;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.io.ByteBufferInput;
5 | import com.esotericsoftware.kryo.io.ByteBufferOutput;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.github.smartbuf.SmartPacket;
8 | import com.github.smartbuf.SmartStream;
9 | import org.msgpack.MessagePack;
10 | import org.openjdk.jmh.annotations.*;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * Benchmark Mode Cnt Score Error Units
17 | * SmallDeserBenchmark.json avgt 6 831.411 ± 133.241 ns/op
18 | * SmallDeserBenchmark.kryo avgt 6 958.711 ± 901.156 ns/op
19 | * SmallDeserBenchmark.msgpack avgt 6 1304.432 ± 21.346 ns/op
20 | * SmallDeserBenchmark.protobuf avgt 6 142.961 ± 1.740 ns/op
21 | * SmallDeserBenchmark.sb_packet avgt 6 624.565 ± 4.355 ns/op
22 | * SmallDeserBenchmark.sb_stream avgt 6 363.003 ± 8.824 ns/op
23 | *
24 | * @author sulin
25 | * @since 2019-11-11 10:38:04
26 | */
27 | @Warmup(iterations = 2, time = 2)
28 | @Fork(2)
29 | @Measurement(iterations = 3, time = 3)
30 | @BenchmarkMode(Mode.AverageTime)
31 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
32 | public class SmallDeserBenchmark {
33 |
34 | private static final ObjectMapper mapper = new ObjectMapper();
35 | private static final SmartStream stream = new SmartStream();
36 | static final MessagePack MSGPACK = new MessagePack();
37 | static final Kryo KRYO = new Kryo();
38 |
39 | private static final UserModel user = UserModel.random();
40 |
41 | static byte[] jsonBytes;
42 | static byte[] msgpackBytes;
43 | static byte[] kryoBytes;
44 | static byte[] pbBytes;
45 | static byte[] packetBytes;
46 | static byte[] streamBytes;
47 |
48 | static {
49 | try {
50 | ByteBufferOutput kryoOutput = new ByteBufferOutput(1024);
51 |
52 | KRYO.writeObject(kryoOutput, user);
53 |
54 | jsonBytes = mapper.writeValueAsBytes(user);
55 | msgpackBytes = MSGPACK.write(user);
56 | pbBytes = user.toPB().toByteArray();
57 | kryoBytes = kryoOutput.toBytes();
58 | packetBytes = SmartPacket.serialize(user);
59 | streamBytes = stream.serialize(user);
60 |
61 | // smartbuf's stream-mode need warm up to avoid sequence error
62 | stream.deserialize(streamBytes, UserModel.class);
63 |
64 | jsonBytes = mapper.writeValueAsBytes(user);
65 | pbBytes = user.toPB().toByteArray();
66 | packetBytes = SmartPacket.serialize(user);
67 | streamBytes = stream.serialize(user);
68 | } catch (IOException e) {
69 | throw new RuntimeException(e);
70 | }
71 | }
72 |
73 | @Benchmark
74 | public void json() throws Exception {
75 | mapper.readValue(jsonBytes, UserModel.class);
76 | }
77 |
78 | @Benchmark
79 | public void kryo() {
80 | KRYO.readObject(new ByteBufferInput(kryoBytes), UserModel.class);
81 | }
82 |
83 | @Benchmark
84 | public void msgpack() throws Exception {
85 | MSGPACK.read(msgpackBytes, UserModel.class);
86 | }
87 |
88 | @Benchmark
89 | public void protobuf() throws Exception {
90 | Small.User.parseFrom(pbBytes);
91 | }
92 |
93 | @Benchmark
94 | public void sb_packet() throws Exception {
95 | SmartPacket.deserialize(packetBytes, UserModel.class);
96 | }
97 |
98 | @Benchmark
99 | public void sb_stream() throws Exception {
100 | stream.deserialize(streamBytes, UserModel.class);
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/small/SmallSerialBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.small;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.io.ByteBufferOutput;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.github.smartbuf.SmartPacket;
8 | import com.github.smartbuf.SmartStream;
9 | import org.msgpack.MessagePack;
10 | import org.openjdk.jmh.annotations.*;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * Benchmark Mode Cnt Score Error Units
17 | * SmallSerialBenchmark.json avgt 6 767.941 ± 20.675 ns/op
18 | * SmallSerialBenchmark.kryo avgt 6 303.953 ± 5.110 ns/op
19 | * SmallSerialBenchmark.msgpack avgt 6 1458.512 ± 47.205 ns/op
20 | * SmallSerialBenchmark.protobuf avgt 6 210.945 ± 20.209 ns/op
21 | * SmallSerialBenchmark.sb_packet avgt 6 635.780 ± 8.427 ns/op
22 | * SmallSerialBenchmark.sb_stream avgt 6 397.773 ± 12.083 ns/op
23 | *
24 | * @author sulin
25 | * @since 2019-10-28 17:32:33
26 | */
27 | @Warmup(iterations = 2, time = 2)
28 | @Fork(2)
29 | @Measurement(iterations = 3, time = 3)
30 | @BenchmarkMode(Mode.AverageTime)
31 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
32 | public class SmallSerialBenchmark {
33 |
34 | static final UserModel user = UserModel.random();
35 |
36 | static final ObjectMapper MAPPER = new ObjectMapper();
37 | static final SmartStream STREAM = new SmartStream();
38 | static final MessagePack MSGPACK = new MessagePack();
39 | static final Kryo KRYO = new Kryo();
40 |
41 | static final ByteBufferOutput kryoOutput = new ByteBufferOutput(1024);
42 |
43 | static {
44 | KRYO.register(UserModel.class);
45 | }
46 |
47 | @Benchmark
48 | public void json() throws JsonProcessingException {
49 | MAPPER.writeValueAsString(user);
50 | }
51 |
52 | @Benchmark
53 | public void msgpack() throws Exception {
54 | MSGPACK.write(user);
55 | }
56 |
57 | @Benchmark
58 | public void protobuf() {
59 | user.toPB().toByteArray();
60 | }
61 |
62 | @Benchmark
63 | public void kryo() {
64 | KRYO.writeObject(kryoOutput, user);
65 | kryoOutput.toBytes();
66 | kryoOutput.clear();
67 | }
68 |
69 | @Benchmark
70 | public void sb_packet() throws IOException {
71 | SmartPacket.serialize(user);
72 | }
73 |
74 | @Benchmark
75 | public void sb_stream() throws IOException {
76 | STREAM.serialize(user);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/small/UserModel.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.small;
2 |
3 | import lombok.Data;
4 | import org.apache.commons.lang3.RandomStringUtils;
5 | import org.apache.commons.lang3.RandomUtils;
6 | import org.msgpack.annotation.Message;
7 |
8 | /**
9 | * Simple bean for test
10 | *
11 | * @author sulin
12 | * @since 2019-10-28 17:27:09
13 | */
14 | @Data
15 | @Message
16 | public class UserModel {
17 |
18 | private long id;
19 | private Boolean blocked;
20 | private String nickname;
21 | private String portrait;
22 | private float score;
23 | private int loginTimes;
24 | private long createTime;
25 |
26 | public static UserModel random() {
27 | UserModel user = new UserModel();
28 | user.id = RandomUtils.nextLong();
29 | user.blocked = RandomUtils.nextBoolean();
30 | user.nickname = RandomStringUtils.randomAlphanumeric(12);
31 | user.portrait = RandomStringUtils.randomAlphabetic(24);
32 | user.score = RandomUtils.nextFloat();
33 | user.loginTimes = RandomUtils.nextInt(10, 10000);
34 | user.createTime = System.currentTimeMillis();
35 | return user;
36 | }
37 |
38 | public Small.User toPB() {
39 | Small.User.Builder builder = Small.User.newBuilder()
40 | .setId(id)
41 | .setBlocked(blocked)
42 | .setNickname(nickname)
43 | .setPortrait(portrait)
44 | .setScore(score)
45 | .setLoginTimes(loginTimes)
46 | .setCreateTime(createTime);
47 | return builder.build();
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/benchmark/tiny/TinyTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.benchmark.tiny;
2 |
3 | import com.github.smartbuf.SmartPacket;
4 | import com.github.smartbuf.SmartStream;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 | import org.junit.jupiter.api.Test;
9 |
10 | import java.io.IOException;
11 |
12 | /**
13 | * ProtoBuf: [8, -23, 7, 26, 5, 104, 101, 108, 108, 111, 56, -112, 78]
14 | *
15 | * @author sulin
16 | * @since 2019-11-12 20:16:49
17 | */
18 | public class TinyTest {
19 |
20 | @Test
21 | public void testPB() {
22 | Tiny.User user = Tiny.User.newBuilder()
23 | .setId(1001)
24 | .setName("hello")
25 | .setTime(10000L)
26 | .build();
27 |
28 | System.out.println(Integer.toHexString(0b1101001));
29 | System.out.println(Integer.toHexString(0b0010000));
30 | System.out.println(Integer.toBinaryString(1001));
31 | System.out.println(Integer.toBinaryString(10000));
32 | System.out.println(bytesToHex(user.getName().getBytes()));
33 |
34 | System.out.println("ProtoBuf: " + bytesToHex(user.toByteArray()));
35 | }
36 |
37 | @Test
38 | public void testSB() throws IOException {
39 | UserModel user = new UserModel(1001, "hello", 10000L);
40 | SmartStream stream = new SmartStream();
41 |
42 | byte[] streamData = stream.serialize(user);
43 |
44 | UserModel newUser = stream.deserialize(streamData, UserModel.class);
45 | assert user.equals(newUser);
46 |
47 | System.out.println(bytesToHex(streamData));
48 |
49 | streamData = stream.serialize(user);
50 | System.out.println(bytesToHex(streamData));
51 |
52 | // byte[] bytes = SmartPacket.serialize(user);
53 | // UserModel newUser = SmartPacket.deserialize(bytes, UserModel.class);
54 | // assert user.equals(newUser);
55 |
56 | System.out.println(bytesToHex("hello".getBytes()));
57 | System.out.println(bytesToHex("id".getBytes()));
58 | System.out.println(bytesToHex("name".getBytes()));
59 | System.out.println(bytesToHex("time".getBytes()));
60 |
61 | }
62 |
63 | @Data
64 | @NoArgsConstructor
65 | @AllArgsConstructor
66 | public static class UserModel {
67 | private int id;
68 | private String name;
69 | private long time;
70 | }
71 |
72 | private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
73 |
74 | public static String bytesToHex(byte[] bytes) {
75 | StringBuilder sb = new StringBuilder();
76 | for (byte aByte : bytes) {
77 | int v = aByte & 0xFF;
78 | if (sb.length() > 0) {
79 | sb.append(", ");
80 | }
81 | sb.append("0x");
82 | sb.append(HEX_ARRAY[v >>> 4]);
83 | sb.append(HEX_ARRAY[v & 0x0F]);
84 | }
85 | return "[" + sb + "]";
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/CodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | /**
6 | * @author sulin
7 | * @since 2019-05-19 14:11:03
8 | */
9 | public class CodecTest {
10 |
11 | @Test
12 | public void testArray() {
13 | Object intArr = new Integer[0];
14 | System.out.println(intArr.getClass());
15 | System.out.println(intArr instanceof Object[]);
16 | System.out.println(intArr.getClass().getComponentType());
17 |
18 | Object[] objArr = new Object[]{1, 2};
19 | System.out.println(objArr instanceof Integer[]);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/ConverterMapTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.XType;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.util.Date;
7 |
8 | /**
9 | * @author sulin
10 | * @since 2019-08-02 16:31:07
11 | */
12 | public class ConverterMapTest {
13 |
14 | @Test
15 | public void printChart() {
16 | ConverterMap map = CodecFactory.Instance.getConverterMap();
17 | map.printDot();
18 | }
19 |
20 | @Test
21 | public void test() throws NoSuchMethodException {
22 | ConverterMap map = new ConverterMap();
23 | assert map.get(Date.class).isEmpty();
24 | assert map.get(Date.class, Long.class) == null;
25 |
26 | map.put(new TranConverterMethod(Long.class, Number.class));
27 | map.put(new TranConverterMethod(Long.class, Number.class)); // should do nothing
28 | try {
29 | map.put(new InvalidConverterMethod(Long.class, Number.class));
30 | assert false;
31 | } catch (Exception e) {
32 | assert e instanceof IllegalArgumentException;
33 | }
34 |
35 | map.put(RealConverterMethod.valueOf(new TmpCodec(), TmpCodec.class.getDeclaredMethod("toNumber", Long.class)));
36 | map.put(new TranConverterMethod(Long.class, Number.class)); // should do nothing
37 | try {
38 | map.put(new InvalidConverterMethod(Long.class, Number.class));
39 | assert false;
40 | } catch (Exception e) {
41 | assert e instanceof IllegalArgumentException;
42 | }
43 |
44 | map.put(new InvalidConverterMethod(Date.class, Long.class));
45 | try {
46 | map.put(new InvalidConverterMethod(Date.class, Long.class));
47 | assert false;
48 | } catch (Exception e) {
49 | assert e instanceof IllegalArgumentException;
50 | }
51 | }
52 |
53 | static class TmpCodec extends Codec {
54 | @Converter
55 | public Number toNumber(Long l) {
56 | return 0;
57 | }
58 | }
59 |
60 | static class InvalidConverterMethod extends ConverterMethod {
61 |
62 | public InvalidConverterMethod(Class> srcClass, Class> tgtClass) {
63 | super(srcClass, tgtClass);
64 | }
65 |
66 | @Override
67 | public Object convert(Object data, XType tgtType) {
68 | return null;
69 | }
70 |
71 | @Override
72 | public int getDistance() {
73 | return 0;
74 | }
75 |
76 | @Override
77 | public boolean isExtensible() {
78 | return false;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/ConverterMethodTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.XType;
4 | import com.github.smartbuf.reflect.XTypeUtils;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.lang.reflect.Method;
8 | import java.lang.reflect.Type;
9 | import java.sql.Timestamp;
10 | import java.util.*;
11 |
12 | /**
13 | * @author sulin
14 | * @since 2019-08-03 12:07:12
15 | */
16 | public class ConverterMethodTest {
17 |
18 | @Test
19 | public void testTranConverterMethod() {
20 | ConverterMethod method = new TranConverterMethod(ArrayList.class, Collection.class);
21 | Object tgt = method.convert(new ArrayList(), null);
22 | assert tgt != null;
23 | assert tgt instanceof Collection;
24 |
25 | System.out.println(method);
26 | }
27 |
28 | @Test
29 | public void testRealConverterMethod() {
30 | TestCodec codec = new TestCodec();
31 | Map methodMap = new HashMap<>();
32 | for (Method method : codec.getClass().getDeclaredMethods()) {
33 | methodMap.put(method.getName(), RealConverterMethod.valueOf(codec, method));
34 | }
35 |
36 | assert methodMap.get("invalid1") == null;
37 | assert methodMap.get("invalid2") == null;
38 | assert methodMap.get("invalid3") == null;
39 | assert methodMap.get("invalid4") == null;
40 | assert methodMap.get("invalid5") == null;
41 | assert methodMap.get("invalid6") == null;
42 |
43 | assert methodMap.get("valid1") != null;
44 | assert methodMap.get("valid2") != null;
45 |
46 | assert methodMap.get("valid1").getTgtClass() == BitSet.class;
47 | assert methodMap.get("valid1").getSrcClass() == String.class;
48 | assert !methodMap.get("valid1").isHasTypeArg();
49 |
50 | assert methodMap.get("valid2").getTgtClass() == Timestamp.class;
51 | assert methodMap.get("valid2").getSrcClass() == String.class;
52 | assert methodMap.get("valid2").isHasTypeArg();
53 |
54 | RealConverterMethod method = methodMap.get("valid1");
55 | try {
56 | method.convert(new Date(), null);
57 | assert false;
58 | } catch (Exception e) {
59 | assert e instanceof IllegalArgumentException;
60 | }
61 | try {
62 | method.convert(null, XTypeUtils.toXType(BitSet.class));
63 | assert false;
64 | } catch (Exception e) {
65 | assert e instanceof IllegalStateException;
66 | }
67 | }
68 |
69 | private static class TestCodec extends Codec implements IC {
70 |
71 | @Converter(nullable = true)
72 | public BitSet valid1(String s) {
73 | throw new UnsupportedOperationException();
74 | }
75 |
76 | @Converter
77 | public Timestamp valid2(String s, XType type) {
78 | return null;
79 | }
80 |
81 | public Object invalid1(String s) {
82 | return null;
83 | }
84 |
85 | public Object invalid2(String s, XType type) {
86 | return null;
87 | }
88 |
89 | @Converter
90 | public Object invalid3() {
91 | return null;
92 | }
93 |
94 | @Converter
95 | public Object invalid4(String s, Type type) {
96 | return null;
97 | }
98 |
99 | @Converter
100 | public void invalid5(String s) {
101 | }
102 |
103 | @Converter
104 | public Object invalid6(String... s) {
105 | return null;
106 | }
107 |
108 | @Converter
109 | public Void invalid7(String s) {
110 | return null;
111 | }
112 |
113 | @Override
114 | public void setFactory(CodecFactory factory) {
115 | super.setFactory(factory);
116 | }
117 | }
118 |
119 | interface IC {
120 | default void test() {
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/ConverterPipelineTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter;
2 |
3 | import com.github.smartbuf.reflect.TypeRef;
4 | import com.github.smartbuf.reflect.XTypeUtils;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import java.util.*;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-08-03 11:09:37
13 | */
14 | public class ConverterPipelineTest {
15 |
16 | private CodecFactory factory = new CodecFactory();
17 |
18 | @BeforeEach
19 | void setUp() {
20 | factory = CodecFactory.Instance;
21 | }
22 |
23 | @Test
24 | public void convert() {
25 | ConverterPipeline pipeline = factory.getPipeline(BitSet.class, Byte[].class);
26 |
27 | Object tgt = pipeline.convert(BitSet.valueOf(new byte[]{1, 2, 3, 4}), XTypeUtils.toXType(Byte[].class));
28 | assert tgt != null;
29 | assert tgt instanceof Byte[];
30 |
31 | Byte[] bs = (Byte[]) tgt;
32 | assert bs.length == 4;
33 | assert bs[0] == 1;
34 | assert bs[1] == 2;
35 | assert bs[2] == 3;
36 | assert bs[3] == 4;
37 | }
38 |
39 | @Test
40 | public void test() throws Exception {
41 | ConverterPipeline pipeline = factory.getPipeline(Long.class, Optional.class);
42 |
43 | List methods = new ArrayList<>();
44 | for (ConverterMethod method : pipeline.getMethods()) {
45 | if (method instanceof RealConverterMethod) {
46 | methods.add((RealConverterMethod) method);
47 | }
48 | }
49 |
50 | ConverterPipeline.Pipeline pip = ConverterPipeline.build(methods);
51 | Object result = pip.convert(1L, XTypeUtils.toXType(new TypeRef>() {
52 | }.getType()));
53 | System.out.println(result);
54 | }
55 |
56 | @Test
57 | public void testError() {
58 | new ConverterPipeline(Collections.singletonList(new RealConverterMethod(Long.class, BitSet.class)));
59 | }
60 |
61 | @Test
62 | public void disableAsm() {
63 | ConverterPipeline.ENABLE_ASM = false;
64 |
65 | Collection collection = factory.convert(new int[]{1, 2, 3}, Collection.class);
66 | assert collection.size() == 3;
67 |
68 | assert factory.convert(OptionalInt.empty(), BitSet.class) == null;
69 |
70 | ConverterPipeline.ENABLE_ASM = true;
71 | }
72 |
73 | @Test
74 | public void testPrimaryArg() {
75 | CodecFactory factory = new CodecFactory();
76 | factory.installCodec(PrimaryArgCodec.class);
77 |
78 | OptionalInt opt = factory.convert(100, OptionalInt.class);
79 | assert opt.getAsInt() == 101;
80 | }
81 |
82 | public static class PrimaryArgCodec extends Codec {
83 | @Converter(distance = -100)
84 | public OptionalInt toBitSet(int i) {
85 | return OptionalInt.of(i + 1);
86 | }
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/AtomicCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import com.github.smartbuf.reflect.TypeRef;
5 | import com.github.smartbuf.reflect.XTypeUtils;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.util.Arrays;
10 | import java.util.BitSet;
11 | import java.util.Objects;
12 | import java.util.Optional;
13 | import java.util.concurrent.atomic.*;
14 |
15 | /**
16 | * @author sulin
17 | * @since 2019-08-03 16:26:30
18 | */
19 | @SuppressWarnings("ALL")
20 | public class AtomicCodecTest {
21 |
22 | private AtomicCodec codec = new AtomicCodec();
23 |
24 | @BeforeEach
25 | void setUp() {
26 | codec.setFactory(CodecFactory.Instance);
27 | }
28 |
29 | @Test
30 | public void testAtomic() {
31 | assert codec.toBoolean(new AtomicBoolean(true));
32 | assert codec.toAtomicBoolean(true).get();
33 |
34 | assert codec.toInteger(new AtomicInteger(100)) == 100;
35 | assert codec.toAtomicInteger(100).get() == 100;
36 |
37 | assert codec.toLong(new AtomicLong(2000)) == 2000;
38 | assert codec.toAtomicLong(2000L).get() == 2000;
39 |
40 | DoubleAdder doubleAdder = new DoubleAdder();
41 | doubleAdder.add(0.02);
42 | assert codec.toDoubleAdder(0.02).doubleValue() == 0.02;
43 | assert codec.toDouble(doubleAdder) == 0.02;
44 |
45 | LongAdder longAdder = new LongAdder();
46 | longAdder.add(999);
47 | assert codec.toLongAdder(999L).longValue() == 999;
48 | assert codec.toLong(longAdder) == 999;
49 |
50 | int[] ints = new int[]{1, 4, 9};
51 | assert Arrays.equals(codec.toIntegerArray(codec.toAtomicIntegerArray(ints)), ints);
52 |
53 | long[] longs = new long[]{100, 700, 999};
54 | assert Arrays.equals(codec.toLongArray(codec.toAtomicLongArray(longs)), longs);
55 |
56 | Byte[] bytes = new Byte[]{1, 9, 100};
57 | assert bytes == codec.toAtomicReference(bytes, XTypeUtils.toXType(AtomicReference.class)).get();
58 | assert bytes == codec.toAtomicReference(bytes, XTypeUtils.toXType(new TypeRef>() {
59 | }.getType())).get();
60 | AtomicReference ref = (AtomicReference) codec.toAtomicReference(bytes, XTypeUtils.toXType(new TypeRef>() {
61 | }.getType()));
62 | assert ref.get().toByteArray().length == bytes.length;
63 | assert ref.get().toByteArray()[2] == bytes[2];
64 |
65 | Object obj = codec.toObject(ref, XTypeUtils.toXType(Object.class));
66 | assert obj instanceof BitSet;
67 |
68 | AtomicReference ref2 = codec.toAtomicReference(0L, XTypeUtils.toXType(new TypeRef>>() {
69 | }.getType()));
70 | assert ref2.get() instanceof Optional;
71 | assert Objects.equals(0, ((Optional) ref2.get()).get());
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/AwtCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.awt.*;
8 | import java.util.Map;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-08-03 16:43:57
13 | */
14 | @SuppressWarnings("unchecked")
15 | public class AwtCodecTest {
16 |
17 | private AwtCodec codec = new AwtCodec();
18 |
19 | @BeforeEach
20 | void setUp() {
21 | codec.setFactory(CodecFactory.Instance);
22 | }
23 |
24 | @Test
25 | public void testAwt() {
26 | Rectangle rectangle = new Rectangle(1, 1, 100, 200);
27 | Map rectMap = codec.toMap(rectangle);
28 | assert rectangle.equals(codec.toRectangle(rectMap));
29 |
30 | Dimension dimension = new Dimension(100, 400);
31 | Map dimensionMap = codec.toMap(dimension);
32 | assert dimension.equals(codec.toDimension(dimensionMap));
33 |
34 | Point point = new Point(1, 999);
35 | Map pointMap = codec.toMap(point);
36 | assert point.equals(codec.toPoint(pointMap));
37 |
38 | Font font = new Font(Font.SANS_SERIF, Font.BOLD, 20);
39 | Map fontMap = codec.toMap(font);
40 | assert font.equals(codec.toFont(fontMap));
41 |
42 | fontMap.remove("style");
43 | fontMap.remove("size");
44 | Font newFont = codec.toFont(fontMap);
45 | assert newFont.getSize() != font.getSize();
46 | assert newFont.getStyle() != font.getStyle();
47 | assert newFont.getName().equals(font.getName());
48 |
49 | String rgb = "#00FF88";
50 | Color rgbColor = codec.toColor(rgb);
51 | assert (rgb + "FF").equalsIgnoreCase(codec.toString(rgbColor));
52 |
53 | String rgba = "#00112233";
54 | Color rgbaColor = codec.toColor(rgba);
55 | assert rgba.equalsIgnoreCase(codec.toString(rgbaColor));
56 |
57 | codec.toColor("001122330");
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/BufferCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.nio.ByteBuffer;
8 | import java.util.Arrays;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-08-04 15:36:57
13 | */
14 | public class BufferCodecTest {
15 |
16 | private BufferCodec codec = new BufferCodec();
17 |
18 | @BeforeEach
19 | void setUp() {
20 | codec.setFactory(CodecFactory.Instance);
21 | }
22 |
23 | @Test
24 | public void testByteBuffer() {
25 | String str = "hello world";
26 | byte[] bytes = str.getBytes();
27 |
28 | ByteBuffer byteBuffer = codec.toByteBuffer(bytes);
29 | assert Arrays.equals(codec.toByteArray(byteBuffer), bytes);
30 |
31 | assert codec.toCharBuffer(byteBuffer) != null;
32 | assert codec.toShortBuffer(byteBuffer) != null;
33 | assert codec.toIntBuffer(byteBuffer) != null;
34 | assert codec.toLongBuffer(byteBuffer) != null;
35 | assert codec.toFloatBuffer(byteBuffer) != null;
36 | assert codec.toDoubleBuffer(byteBuffer) != null;
37 | }
38 |
39 | @Test
40 | public void testBuffer() {
41 | char[] chars = "hello".toCharArray();
42 | assert Arrays.equals(codec.toCharArray(codec.toCharBuffer(chars)), chars);
43 |
44 | short[] shorts = new short[]{1, 100, 10000};
45 | assert Arrays.equals(shorts, codec.toShortArray(codec.toShortBuffer(shorts)));
46 |
47 | int[] ints = new int[]{1, 200, 50000};
48 | assert Arrays.equals(ints, codec.toIntArray(codec.toIntBuffer(ints)));
49 |
50 | long[] longs = new long[]{100L, 100000L, 100000000L};
51 | assert Arrays.equals(longs, codec.toLongArray(codec.toLongBuffer(longs)));
52 |
53 | float[] floats = new float[]{1.0f, 0.001f, 0.00001f};
54 | assert Arrays.equals(floats, codec.toFloatArray(codec.toFloatBuffer(floats)));
55 |
56 | double[] doubles = new double[]{1.0, 0.000001, 0.00000000000001};
57 | assert Arrays.equals(doubles, codec.toDoubleArray(codec.toDoubleBuffer(doubles)));
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/IOCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import com.github.smartbuf.reflect.XTypeUtils;
5 | import com.github.smartbuf.utils.CodecUtils;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.io.*;
10 | import java.nio.charset.Charset;
11 | import java.nio.charset.StandardCharsets;
12 | import java.util.Arrays;
13 | import java.util.Objects;
14 |
15 | /**
16 | * @author sulin
17 | * @since 2019-08-04 17:02:04
18 | */
19 | public class IOCodecTest {
20 |
21 | private IOCodec codec = new IOCodec();
22 |
23 | @BeforeEach
24 | void setUp() {
25 | codec.setFactory(CodecFactory.Instance);
26 | }
27 |
28 | @Test
29 | public void test() throws IOException {
30 | Charset charset = StandardCharsets.UTF_8;
31 | assert Objects.equals(charset, codec.toCharset(codec.toString(charset)));
32 |
33 | File file = File.createTempFile("100", "test");
34 | String fileName = codec.toString(file);
35 | assert fileName != null;
36 | }
37 |
38 | @Test
39 | public void testInputStream() throws IOException {
40 | byte[] bytes = new byte[]{1, 2, 3, 4, 5};
41 | assert Arrays.equals(bytes, codec.toByteArray(codec.toInputStream(bytes, XTypeUtils.toXType(ByteArrayInputStream.class))));
42 |
43 | assert codec.toInputStream(bytes, XTypeUtils.toXType(ByteArrayInputStream.class)).getClass() == ByteArrayInputStream.class;
44 | assert codec.toInputStream(bytes, XTypeUtils.toXType(BufferedInputStream.class)).getClass() == BufferedInputStream.class;
45 | assert codec.toInputStream(bytes, XTypeUtils.toXType(DataInputStream.class)).getClass() == DataInputStream.class;
46 |
47 | try {
48 | codec.toInputStream(bytes, CodecUtils.toXType(FileInputStream.class));
49 | assert false;
50 | } catch (Exception e) {
51 | assert e instanceof UnsupportedOperationException;
52 | }
53 | }
54 |
55 | @Test
56 | public void testReadable() throws IOException {
57 | String str = "hello world";
58 | Readable readable = codec.toReadable(str, XTypeUtils.toXType(CharArrayReader.class));
59 | assert readable instanceof CharArrayReader;
60 | assert str.equals(codec.toString(readable));
61 |
62 | assert codec.toReadable(str, XTypeUtils.toXType(StringReader.class)) instanceof StringReader;
63 | assert codec.toReadable(str, XTypeUtils.toXType(BufferedReader.class)) instanceof BufferedReader;
64 |
65 | try {
66 | codec.toReadable(str, XTypeUtils.toXType(FileReader.class));
67 | } catch (Exception e) {
68 | assert e instanceof UnsupportedOperationException;
69 | }
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/JodaCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import com.github.smartbuf.utils.CodecUtils;
5 | import org.joda.time.DateTime;
6 | import org.joda.time.Interval;
7 | import org.joda.time.Period;
8 | import org.joda.time.format.DateTimeFormat;
9 | import org.junit.jupiter.api.BeforeEach;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.time.*;
13 | import java.util.TimeZone;
14 |
15 | /**
16 | * @author sulin
17 | * @since 2019-08-04 17:20:28
18 | */
19 | public class JodaCodecTest {
20 |
21 | private JodaCodec codec = new JodaCodec();
22 |
23 | @BeforeEach
24 | void setUp() {
25 | codec.setFactory(CodecFactory.Instance);
26 |
27 | CodecUtils.installCodec(codec);
28 | }
29 |
30 | @Test
31 | public void testDateTime() {
32 | // Instant
33 | Instant instant = Instant.now();
34 | System.out.println(instant);
35 | System.out.println(codec.toInstant(instant));
36 | Instant newInstant = codec.toInstant(codec.toInstant(instant));
37 | System.out.println(newInstant);
38 | assert instant.toEpochMilli() == newInstant.toEpochMilli();
39 |
40 | // Duration
41 | Duration duration = Duration.ofMillis(System.currentTimeMillis());
42 | System.out.println(duration);
43 | System.out.println(codec.toDuration(duration));
44 | assert duration.equals(codec.toDuration(codec.toDuration(duration)));
45 |
46 | // LocalTime
47 | LocalTime localTime = LocalTime.now();
48 | System.out.println(localTime);
49 | System.out.println(codec.toLocalTime(localTime));
50 | LocalTime localTime2 = codec.toLocalTime(codec.toLocalTime(localTime));
51 | assert localTime.toSecondOfDay() == localTime2.toSecondOfDay();
52 |
53 | // LocalDate
54 | LocalDate localDate = LocalDate.now();
55 | System.out.println(localDate);
56 | System.out.println(codec.toLocalDate(localDate));
57 | assert localDate.equals(codec.toLocalDate(codec.toLocalDate(localDate)));
58 |
59 | // DateTime
60 | DateTime dateTime = DateTime.now();
61 | System.out.println(dateTime);
62 | System.out.println(codec.toLocalDateTime(dateTime));
63 | assert dateTime.equals(codec.toDateTime(codec.toLocalDateTime(dateTime)));
64 |
65 | // LocalDateTime
66 | LocalDateTime localDateTime = LocalDateTime.now();
67 | System.out.println(localDateTime);
68 | System.out.println(codec.toLocalDateTime(localDateTime));
69 | LocalDateTime localDateTime2 = codec.toLocalDateTime(codec.toLocalDateTime(localDateTime));
70 | assert localDateTime.toEpochSecond(ZoneOffset.UTC) == localDateTime2.toEpochSecond(ZoneOffset.UTC);
71 | }
72 |
73 | @Test
74 | public void testOthers() {
75 | // interval
76 | Interval interval = new Interval(0, 365 * 24 * 60 * 60 * 1000L);
77 | String str = codec.toString(interval);
78 | System.out.println(str);
79 | assert interval.equals(codec.toInterval(str));
80 |
81 | // period
82 | Period period = new Period(2019, 8, 1, 4, 17, 30, 40, 300);
83 | String periodStr = codec.toString(period);
84 | System.out.println(periodStr);
85 | assert period.equals(codec.toPeriod(periodStr));
86 |
87 | // DateTimeFormatter
88 | assert codec.toDateTimeFormatter("yyyy-MM-dd") != null;
89 | try {
90 | codec.toString(DateTimeFormat.fullDateTime());
91 | } catch (Exception e) {
92 | assert e instanceof UnsupportedOperationException;
93 | }
94 |
95 | // DateTimeZone
96 | TimeZone zone = TimeZone.getDefault();
97 | TimeZone newZone = codec.toTimeZone(codec.toDateTimeZone(zone));
98 | System.out.println(zone);
99 | System.out.println(newZone);
100 | assert zone.getID().equals(newZone.getID());
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/MathCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.math.BigDecimal;
8 | import java.math.BigInteger;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-08-04 18:29:52
13 | */
14 | public class MathCodecTest {
15 |
16 | private MathCodec codec = new MathCodec();
17 |
18 | @BeforeEach
19 | void setUp() {
20 | codec.setFactory(CodecFactory.Instance);
21 | }
22 |
23 | @Test
24 | public void test() {
25 | BigDecimal decimal = new BigDecimal("199999.222232323134123412312312312312312312312");
26 | BigInteger integer = new BigInteger("999999999999999999999999999999999999999999");
27 |
28 | assert decimal.equals(codec.toBigDecimal(codec.toString(decimal)));
29 | assert integer.equals(codec.toBigInteger(codec.toString(integer)));
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/NetCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.net.Inet4Address;
8 | import java.net.Inet6Address;
9 | import java.net.InetAddress;
10 | import java.net.InetSocketAddress;
11 |
12 | /**
13 | * @author sulin
14 | * @since 2019-08-04 18:58:14
15 | */
16 | public class NetCodecTest {
17 |
18 | private NetCodec codec = new NetCodec();
19 |
20 | @BeforeEach
21 | void setUp() {
22 | codec.setFactory(CodecFactory.Instance);
23 | }
24 |
25 | @Test
26 | public void test() throws Exception {
27 | InetSocketAddress address = new InetSocketAddress("www.bing.com", 80);
28 | assert address.equals(codec.toInetSocketAddress(codec.toString(address)));
29 | assert codec.toInetSocketAddress("www.bing.com").getPort() == 0;
30 |
31 | assert codec.toInetAddress("/127.0.0.1") != null;
32 |
33 | InetAddress inetAddress = InetAddress.getByName("www.bing.com");
34 | assert inetAddress.equals(codec.toInetAddress(codec.toString(inetAddress)));
35 |
36 | Inet4Address inet4Address = (Inet4Address) Inet4Address.getByName("www.bing.com");
37 | assert inet4Address.equals(codec.toInetAddress(codec.toString(inet4Address)));
38 |
39 | Inet6Address inet6Address = (Inet6Address) Inet6Address.getByName("2400:3200:1600::152");
40 | assert inet6Address.equals(codec.toInetAddress(codec.toString(inet6Address)));
41 |
42 | // auto split hostname by /
43 | assert inetAddress.equals(codec.toInetAddress(inetAddress.toString()));
44 |
45 | String uri1 = "http://java.sun.com/j2se/1.3/";
46 | String uri2 = "../../../demo/jfc/SwingSet2/src/SwingSet2.java";
47 | String uri3 = "file:///~/calendar";
48 | String uri4 = "docs/guide/collections/designfaq.html#28";
49 | assert uri1.equals(codec.toString(codec.toURI(uri1)));
50 | assert uri2.equals(codec.toString(codec.toURI(uri2)));
51 | assert uri3.equals(codec.toString(codec.toURI(uri3)));
52 | assert uri4.equals(codec.toString(codec.toURI(uri4)));
53 |
54 | String url = "https://www.javatpoint.com/URL-class";
55 | assert url.equals(codec.toString(codec.toURL(url)));
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/NumberCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | /**
8 | * @author sulin
9 | * @since 2019-08-04 18:58:23
10 | */
11 | public class NumberCodecTest {
12 |
13 | private NumberCodec codec = new NumberCodec();
14 |
15 | @BeforeEach
16 | void setUp() {
17 | codec.setFactory(CodecFactory.Instance);
18 | }
19 |
20 | @Test
21 | public void test() {
22 | String str = "1234567890";
23 | assert str.equals(codec.toString(codec.toLong(str)));
24 |
25 | assert Long.valueOf(100L).equals(codec.toLong(codec.toByte(100L)));
26 | assert Long.valueOf(10000L).equals(codec.toLong(codec.toShort(10000L)));
27 | assert Long.valueOf(100000000L).equals(codec.toLong(codec.toInteger(100000000L)));
28 |
29 | Double d = 1234567890.123456;
30 | Float f = 123.4567F;
31 | assert Math.abs(codec.toDouble(codec.toString(d)) - d) < 0.0001;
32 | assert codec.toDouble(codec.toLong(d)) == 1234567890;
33 | assert Math.abs(codec.toFloat(codec.toDouble(f)) - f) < 0.01; // precision lost
34 | assert Math.abs(codec.toFloat(codec.toString(f)) - f) < 0.01;
35 |
36 | assert codec.toBoolean(codec.toLong(true));
37 | assert !codec.toBoolean(codec.toLong(false));
38 | assert codec.toBoolean(codec.toString(true));
39 |
40 | Character c = 'C';
41 | assert c.equals(codec.toCharacter(codec.toInteger(c)));
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/PrimaryCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | /**
8 | * @author sulin
9 | * @since 2019-08-05 19:49:55
10 | */
11 | class PrimaryCodecTest {
12 |
13 | private PrimaryCodec codec = new PrimaryCodec();
14 |
15 | @BeforeEach
16 | void setUp() {
17 | codec.setFactory(CodecFactory.Instance);
18 | }
19 |
20 | @Test
21 | public void test() {
22 | assert codec.toBoolean(codec.toBoolean(true));
23 | assert codec.toByte(codec.toByte((byte) 1)) == 1;
24 | assert codec.toShort(codec.toShort((short) 1)) == 1;
25 | assert codec.toInt(codec.toInteger(1)) == 1;
26 | assert codec.toLong(codec.toLong(1L)) == 1L;
27 | assert codec.toFloat(codec.toFloat(1.0f)) == 1.0f;
28 | assert codec.toDouble(codec.toDouble(1.0)) == 1.0;
29 | assert codec.toChar(codec.toCharacter('a')) == 'a';
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/ReferenceCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import com.github.smartbuf.reflect.TypeRef;
5 | import com.github.smartbuf.reflect.XTypeUtils;
6 | import org.junit.jupiter.api.BeforeEach;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.lang.ref.PhantomReference;
10 | import java.lang.ref.Reference;
11 | import java.lang.ref.SoftReference;
12 | import java.lang.ref.WeakReference;
13 | import java.util.Objects;
14 | import java.util.Optional;
15 |
16 | /**
17 | * @author sulin
18 | * @since 2019-08-04 18:58:30
19 | */
20 | @SuppressWarnings("ALL")
21 | public class ReferenceCodecTest {
22 |
23 | private ReferenceCodec codec = new ReferenceCodec();
24 |
25 | @BeforeEach
26 | void setUp() {
27 | codec.setFactory(CodecFactory.Instance);
28 | }
29 |
30 | @Test
31 | public void testToReference() {
32 | int i = 1000;
33 | WeakReference ref = (WeakReference) codec.toReference(i, XTypeUtils.toXType(new TypeRef>() {
34 | }.getType()));
35 |
36 | // shouldn't gc
37 | assert ref != null;
38 | assert i == ref.get().intValue();
39 |
40 | SoftReference softRef = (SoftReference) codec.toReference(i, XTypeUtils.toXType(new TypeRef>() {
41 | }.getType()));
42 |
43 | // shouldn't gc
44 | assert softRef != null;
45 | assert i == softRef.get().intValue();
46 |
47 | try {
48 | codec.toReference(i, XTypeUtils.toXType(PhantomReference.class));
49 | } catch (Exception e) {
50 | assert e instanceof IllegalArgumentException;
51 | }
52 |
53 | Reference result = codec.toReference("", XTypeUtils.toXType(new TypeRef>>() {
54 | }.getType()));
55 | assert result.get() instanceof Optional;
56 | assert Objects.equals("", ((Optional) result.get()).get());
57 |
58 | Reference ref2 = codec.toReference(0L, XTypeUtils.toXType(new TypeRef>() {
59 | }.getType()));
60 | assert Objects.equals(0L, ref2.get());
61 | }
62 |
63 | @Test
64 | public void testToObject() {
65 | SoftReference ref = new SoftReference<>(10000L);
66 | assert codec.toObject(ref, XTypeUtils.toXType(Integer.class)) instanceof Integer;
67 | assert codec.toObject(ref, XTypeUtils.toXType(Long.class)) == ref.get();
68 |
69 | SoftReference ref2 = new SoftReference<>("");
70 | Object result = codec.toObject(ref2, XTypeUtils.toXType(new TypeRef>() {
71 | }.getType()));
72 | assert result instanceof Optional;
73 | assert Objects.equals(((Optional) result).get(), "");
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/SqlCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.io.InputStream;
8 | import java.io.Reader;
9 | import java.sql.*;
10 | import java.util.Arrays;
11 |
12 | /**
13 | * @author sulin
14 | * @since 2019-08-04 18:58:39
15 | */
16 | @SuppressWarnings("ALL")
17 | public class SqlCodecTest {
18 |
19 | private SqlCodec codec = new SqlCodec();
20 |
21 | @BeforeEach
22 | void setUp() {
23 | codec.setFactory(CodecFactory.Instance);
24 | }
25 |
26 | @Test
27 | public void test() throws SQLException {
28 | byte[] bytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
29 | Blob blob = codec.toBlob(bytes);
30 | InputStream is = codec.toInputStream(blob);
31 | assert Arrays.equals(CodecFactory.Instance.convert(is, byte[].class), bytes);
32 |
33 | String str = "hello world";
34 | Clob clob = codec.toClob(str);
35 | Reader reader = codec.toReader(clob);
36 | assert str.equals(CodecFactory.Instance.convert(reader, String.class));
37 |
38 | Date date = new Date(System.currentTimeMillis());
39 | Date date2 = codec.toDate(codec.toLong(date));
40 | assert date2.getYear() == date.getYear();
41 | assert date2.getMonth() == date.getMonth();
42 | assert date2.getDay() == date.getDay();
43 |
44 | Time time = new Time(System.currentTimeMillis());
45 | Time time2 = codec.toTime(codec.toLong(time));
46 | assert time.getHours() == time2.getHours();
47 | assert time.getMinutes() == time2.getMinutes();
48 | assert time.getSeconds() == time2.getSeconds();
49 |
50 | Timestamp timestamp = new Timestamp(System.currentTimeMillis());
51 | assert timestamp.equals(codec.toTimestamp(codec.toLong(timestamp)));
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/StringCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import org.junit.jupiter.api.BeforeEach;
5 | import org.junit.jupiter.api.Test;
6 |
7 | /**
8 | * @author sulin
9 | * @since 2019-08-04 18:58:48
10 | */
11 | public class StringCodecTest {
12 |
13 | private StringCodec codec = new StringCodec();
14 |
15 | @BeforeEach
16 | void setUp() {
17 | codec.setFactory(CodecFactory.Instance);
18 | }
19 |
20 | @Test
21 | public void test() {
22 | String str = "hello world";
23 | assert str.equals(codec.toString(codec.toStringBuffer(str)));
24 | assert str.equals(codec.toString(codec.toStringBuilder(str)));
25 | assert str.equals(codec.toString(codec.toCharArray(str)));
26 | assert str.equals(codec.toString(codec.toByteArray(str)));
27 | assert str.equals(codec.toString(codec.toStringCharacterIterator(str)));
28 | try {
29 | codec.toCharacter(str);
30 | } catch (Exception e) {
31 | assert e instanceof UnsupportedOperationException;
32 | }
33 |
34 | String s = "s";
35 | assert s.equals(codec.toString(codec.toCharacter(s)));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/converter/codec/UtilCodecTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.converter.codec;
2 |
3 | import com.github.smartbuf.converter.CodecFactory;
4 | import com.github.smartbuf.reflect.TypeRef;
5 | import com.github.smartbuf.reflect.XType;
6 | import com.github.smartbuf.reflect.XTypeUtils;
7 | import org.junit.jupiter.api.BeforeEach;
8 | import org.junit.jupiter.api.Test;
9 |
10 | import java.util.*;
11 | import java.util.concurrent.atomic.AtomicReference;
12 | import java.util.regex.Pattern;
13 |
14 | /**
15 | * @author sulin
16 | * @since 2019-08-04 18:59:09
17 | */
18 | public class UtilCodecTest {
19 |
20 | private UtilCodec codec = new UtilCodec();
21 |
22 | @BeforeEach
23 | void setUp() {
24 | codec.setFactory(CodecFactory.Instance);
25 | }
26 |
27 | @Test
28 | public void test() {
29 | byte[] bytes = new byte[]{1, 4, 8, 100};
30 | assert Arrays.equals(bytes, codec.toByteArray(codec.toBitSet(bytes)));
31 |
32 | Currency currency = Currency.getInstance(Locale.CHINA);
33 | assert currency.equals(codec.toCurrency(codec.toString(currency)));
34 |
35 | Locale locale = Locale.KOREAN;
36 | assert locale.equals(codec.toLocale(codec.toString(locale)));
37 |
38 | TimeZone timeZone = TimeZone.getDefault();
39 | assert timeZone.equals(codec.toTimeZone(codec.toString(timeZone)));
40 |
41 | Pattern pattern = Pattern.compile(".*");
42 | Pattern pattern1 = codec.toPattern(codec.toString(pattern));
43 | assert pattern.pattern().equals(pattern1.pattern());
44 | }
45 |
46 | @Test
47 | public void testOptional() {
48 | Integer i = 100;
49 | assert i.equals(codec.toInteger(codec.toOptionalInt(i)));
50 | assert codec.toInteger(codec.toOptionalInt(null)) == null;
51 |
52 | Long l = 100000L;
53 | assert l.equals(codec.toLong(codec.toOptionalLong(l)));
54 | assert codec.toLong(codec.toOptionalLong(null)) == null;
55 |
56 | Double d = 1.0;
57 | assert d.equals(codec.toDouble(codec.toOptionalDouble(d)));
58 | assert codec.toDouble(codec.toOptionalDouble(null)) == null;
59 |
60 | XType oType = XTypeUtils.toXType(l.getClass());
61 | XType optionalType = XTypeUtils.toXType(new TypeRef>() {
62 | }.getType());
63 | assert l == codec.toObject(codec.toOptional(l, optionalType), oType);
64 | assert codec.toObject(codec.toOptional(null, optionalType), oType) == null;
65 |
66 | Optional optional = codec.toOptional(l, XTypeUtils.toXType(new TypeRef>() {
67 | }.getType()));
68 | assert optional.isPresent() && optional.get().equals(l.intValue());
69 |
70 | assert Objects.equals(codec.toObject(optional, oType), l);
71 |
72 | Object obj = codec.toObject(Optional.of(1), XTypeUtils.toXType(new TypeRef>() {
73 | }.getType()));
74 | assert obj instanceof AtomicReference;
75 | assert Objects.equals(((AtomicReference) obj).get(), 1L);
76 |
77 | Optional opt2 = codec.toOptional(1, XTypeUtils.toXType(new TypeRef>>() {
78 | }.getType()));
79 | assert opt2.isPresent();
80 | assert opt2.get() instanceof AtomicReference;
81 | assert Objects.equals(1L, ((AtomicReference) opt2.get()).get());
82 | }
83 |
84 | @Test
85 | public void testUUID() {
86 | UUID uuid = UUID.randomUUID();
87 | assert uuid.equals(codec.toUUID(codec.toString(uuid)));
88 |
89 | String uuidStr = codec.toString(UUID.randomUUID()).replaceAll("-", "");
90 | assert uuidStr.equals(codec.toString(codec.toUUID(uuidStr)).replaceAll("-", ""));
91 |
92 | try {
93 | codec.toUUID("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
94 | } catch (Exception e) {
95 | assert e instanceof IllegalArgumentException && e.getCause() instanceof NumberFormatException;
96 | }
97 |
98 | try {
99 | codec.toUUID("");
100 | assert false;
101 | } catch (Exception e) {
102 | assert e instanceof IllegalArgumentException;
103 | }
104 |
105 | try {
106 | codec.toUUID("b8f7f030-e07d-44d3-bded-b6dce4cff-a3");
107 | assert false;
108 | } catch (Exception e) {
109 | assert e instanceof IllegalArgumentException;
110 | }
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/node/NodeTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.node;
2 |
3 | import com.github.smartbuf.node.array.*;
4 | import com.github.smartbuf.node.basic.*;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-09-21 14:10:57
13 | */
14 | public class NodeTest {
15 |
16 | @Test
17 | public void testBasic() {
18 | Node node = StringNode.valueOf("");
19 | assert node.type() == NodeType.STRING;
20 |
21 | node = BooleanNode.valueOf(true);
22 | assert node.type() == NodeType.BOOLEAN;
23 |
24 | node = DoubleNode.valueOf(111.0);
25 | assert node.type() == NodeType.DOUBLE;
26 |
27 | node = FloatNode.valueOf(11.0f);
28 | assert node.type() == NodeType.FLOAT;
29 |
30 | node = VarintNode.valueOf(1);
31 | assert node.type() == NodeType.VARINT;
32 |
33 | node = VarintNode.valueOf(1000);
34 | assert node.type() == NodeType.VARINT;
35 |
36 | node = SymbolNode.valueOf(Thread.State.BLOCKED);
37 | assert node.type() == NodeType.SYMBOL;
38 | }
39 |
40 | @Test
41 | public void testArray() {
42 | Node node = new BooleanArrayNode(new boolean[]{true});
43 | assert node.type() == NodeType.ARRAY_BOOLEAN;
44 | assert node.value() instanceof boolean[];
45 |
46 | node = new ByteArrayNode(new byte[]{1});
47 | assert node.type() == NodeType.ARRAY_BYTE;
48 | assert node.value() instanceof byte[];
49 |
50 | node = new ShortArrayNode(new short[]{1});
51 | assert node.type() == NodeType.ARRAY_SHORT;
52 | assert node.value() instanceof short[];
53 |
54 | node = new IntArrayNode(new int[]{1, 2});
55 | assert node.type() == NodeType.ARRAY_INT;
56 | assert node.value() instanceof int[];
57 |
58 | node = new LongArrayNode(new long[]{1, 2});
59 | assert node.type() == NodeType.ARRAY_LONG;
60 | assert node.value() instanceof long[];
61 |
62 | node = new FloatArrayNode(new float[]{1, 2});
63 | assert node.type() == NodeType.ARRAY_FLOAT;
64 | assert node.value() instanceof float[];
65 |
66 | node = new DoubleArrayNode(new double[]{1, 2});
67 | assert node.type() == NodeType.ARRAY_DOUBLE;
68 | assert node.value() instanceof double[];
69 |
70 | node = new ArrayNode(Arrays.asList(1, 2));
71 | assert node.type() == NodeType.ARRAY;
72 | assert node.value() instanceof List;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/reflect/BeanReaderBenchmark.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import lombok.Data;
4 | import net.sf.cglib.beans.BeanMap;
5 | import org.openjdk.jmh.annotations.*;
6 |
7 | import java.lang.reflect.Method;
8 | import java.util.Date;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | /**
12 | * Get BeanHelper by valueOf:
13 | * Benchmark Mode Cnt Score Error Units
14 | * BeanHelperBenchmark.accessor avgt 6 8.076 ± 0.130 ns/op
15 | * BeanHelperBenchmark.beanHelper avgt 6 27.146 ± 0.349 ns/op
16 | * BeanHelperBenchmark.beanmap avgt 6 137.735 ± 13.050 ns/op
17 | * BeanHelperBenchmark.direct avgt 6 8.362 ± 0.052 ns/op
18 | * BeanHelperBenchmark.methods avgt 6 45.565 ± 0.708 ns/op
19 | *
20 | * Cache BeanHelper(about 4~6ns for valueOf):
21 | * Benchmark Mode Cnt Score Error Units
22 | * BeanHelperBenchmark.accessor avgt 6 8.010 ± 0.055 ns/op
23 | * BeanHelperBenchmark.beanHelper avgt 6 21.527 ± 0.281 ns/op
24 | * BeanHelperBenchmark.beanmap avgt 6 137.474 ± 0.644 ns/op
25 | * BeanHelperBenchmark.direct avgt 6 8.261 ± 0.128 ns/op
26 | * BeanHelperBenchmark.methods avgt 6 43.558 ± 0.405 ns/op
27 | *
28 | * Where is the 20ns?
29 | *
30 | * @author sulin
31 | * @since 2019-10-28 17:57:59
32 | */
33 | @Warmup(iterations = 2, time = 2)
34 | @Fork(2)
35 | @Measurement(iterations = 3, time = 3)
36 | @BenchmarkMode(Mode.AverageTime)
37 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
38 | public class BeanReaderBenchmark {
39 |
40 | private static final User USER = new User();
41 | private static final Method[] GETTERS = new Method[7];
42 | private static final BeanReader reader = BeanReaderBuilder.build(User.class);
43 |
44 | static {
45 | try {
46 | GETTERS[0] = User.class.getDeclaredMethod("getId");
47 | GETTERS[1] = User.class.getDeclaredMethod("getBlocked");
48 | GETTERS[2] = User.class.getDeclaredMethod("getCreateTime");
49 | GETTERS[3] = User.class.getDeclaredMethod("getLoginTimes");
50 | GETTERS[4] = User.class.getDeclaredMethod("getNickname");
51 | GETTERS[5] = User.class.getDeclaredMethod("getPortrait");
52 | GETTERS[6] = User.class.getDeclaredMethod("getScore");
53 | } catch (NoSuchMethodException e) {
54 | e.printStackTrace();
55 | }
56 | }
57 |
58 | @Benchmark
59 | public void beanmap() {
60 | BeanMap beanMap = BeanMap.create(USER);
61 | Object[] arr = new Object[beanMap.size()];
62 | int off = 0;
63 | for (Object key : beanMap.keySet()) {
64 | arr[off++] = beanMap.get(key);
65 | }
66 | }
67 |
68 | @Benchmark
69 | public void methods() throws Exception {
70 | Object[] arr = new Object[GETTERS.length];
71 | for (int i = 0; i < GETTERS.length; i++) {
72 | arr[i] = GETTERS[i].invoke(USER);
73 | }
74 | }
75 |
76 | @Benchmark
77 | public void beanHelper() {
78 | Object[] arr = BeanReaderBuilder.build(User.class).getValues(USER);
79 | }
80 |
81 | @Benchmark
82 | public void accessor() {
83 | Object[] arr = new Object[GETTERS.length];
84 | reader.api.getAll(USER, arr);
85 | }
86 |
87 | @Benchmark
88 | public void direct() {
89 | Object[] arr = new Object[GETTERS.length];
90 | arr[0] = USER.getId();
91 | arr[1] = USER.getBlocked();
92 | arr[2] = USER.getCreateTime();
93 | arr[3] = USER.getNickname();
94 | arr[4] = USER.getPortrait();
95 | arr[5] = USER.getLoginTimes();
96 | arr[6] = USER.getScore();
97 | }
98 |
99 | @Data
100 | public static class User {
101 | private long id = 1385434576456830976L;
102 | private Boolean blocked = false;
103 | private String nickname = "1uOlvFfhZuda";
104 | private String portrait = "OCCCAcnrKtKmbOkzRNYbWLnR";
105 | private float score = 2.7177553E38f;
106 | private int loginTimes = 1543;
107 | private Date createTime = new Date();
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/reflect/BeanReaderBuilderTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import lombok.Data;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.util.Arrays;
7 | import java.util.Objects;
8 |
9 | /**
10 | * @author sulin
11 | * @since 2019-11-08 19:42:15
12 | */
13 | public class BeanReaderBuilderTest {
14 |
15 | @Test
16 | public void test() {
17 | BeanReader reader = BeanReaderBuilder.build(Child.class);
18 |
19 | Child child = new Child();
20 | child._name = "_name";
21 | child.enable = true;
22 | child.name = "name";
23 | child.time = System.currentTimeMillis();
24 |
25 | String[] fieldNames = reader.getFieldNames();
26 | assert fieldNames.length == 4;
27 | assert Arrays.equals(fieldNames, new String[]{"_name", "enable", "name", "time"});
28 |
29 | Object[] arr = reader.getValues(child);
30 | assert Objects.equals(child._name, arr[0]);
31 | assert Objects.equals(child.enable, arr[1]);
32 | assert Objects.equals(child.getName(), arr[2]);
33 | assert Objects.equals(child.getTime(), arr[3]);
34 | }
35 |
36 | @Test
37 | public void testFull() {
38 | Full full = new Full();
39 | full.setV(null);
40 |
41 | BeanReader reader = BeanReaderBuilder.build(Full.class);
42 | assert reader.getFieldNames().length == 24;
43 | }
44 |
45 | @Test
46 | public void testError() {
47 | String oldName = BeanReader.API_NAME;
48 |
49 | BeanReader.API_NAME = "...";
50 | try {
51 | BeanReaderBuilder.build(Full.class);
52 | assert false;
53 | } catch (Exception e) {
54 | assert e instanceof IllegalArgumentException;
55 | }
56 |
57 | BeanReader.API_NAME = oldName;
58 | }
59 |
60 | public static abstract class Parent {
61 |
62 | public String _name;
63 | @Deprecated
64 | public String $name;
65 |
66 | private long timestamp;
67 |
68 | public abstract long getTime();
69 |
70 | public static int getId() {
71 | return 0;
72 | }
73 |
74 | public int getIder() {
75 | return 1;
76 | }
77 |
78 | @Deprecated
79 | public String getDesc() {
80 | return null;
81 | }
82 |
83 | public String getTimestamp() {
84 | return "";
85 | }
86 |
87 | }
88 |
89 | @Data
90 | public static class Child extends Parent {
91 | private boolean enable;
92 | private String name;
93 | private long time;
94 | }
95 |
96 | @Data
97 | public static class Full {
98 | private boolean bool1;
99 | private Boolean bool2;
100 | private float float1;
101 | private Float float2;
102 | private double double1;
103 | private Double double2;
104 | private byte byte1;
105 | private Byte byte2;
106 | private short short1;
107 | private Short short2;
108 | private int int1;
109 | private Integer int2;
110 | private long long1;
111 | private Long long2;
112 | private char char1;
113 | private Character char2;
114 | private boolean[] booleans;
115 | private byte[] bytes;
116 | private short[] shorts;
117 | private int[] ints;
118 | private long[] longs;
119 | private float[] floats;
120 | private double[] doubles;
121 | private char[] chars;
122 | private Void v;
123 |
124 | public String isValid() {
125 | return "true";
126 | }
127 |
128 | public String get_name() {
129 | return null;
130 | }
131 |
132 | public String get$name() {
133 | return null;
134 | }
135 |
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/reflect/GenericModel.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.*;
6 | import java.util.concurrent.atomic.AtomicReference;
7 |
8 | /**
9 | * @author sulin
10 | * @since 2019-07-16 12:04:04
11 | */
12 | @Data
13 | public class GenericModel {
14 |
15 | private T t;
16 | private X x;
17 | private R r;
18 |
19 | private Map, R> rMap;
20 | private List extends Date> dates;
21 | private AtomicReference super ArrayList super Integer>> ref;
22 |
23 | private GenBean> gen1;
24 | private GenBean extends AbstractList> gen2;
25 | private GenBean gen3;
26 |
27 | private GenPojo> pojo;
28 |
29 | public static class GenBean> {
30 | private C c;
31 | }
32 |
33 | public static class GenPojo {
34 | private Z z;
35 | }
36 |
37 | public void test() {
38 | gen1.c.add(null);
39 | gen2.c.add("");
40 | gen3.c.add(null);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/reflect/TypeRefTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * @author sulin
9 | * @since 2019-09-20 14:24:25
10 | */
11 | public class TypeRefTest {
12 |
13 | @Test
14 | public void testRef() {
15 | TypeRef ref = new TypeRef() {
16 | };
17 |
18 | assert ref.getType() != null;
19 |
20 | try {
21 | new TypeRef() {
22 | };
23 | assert false;
24 | } catch (Exception e) {
25 | assert e instanceof IllegalArgumentException;
26 | }
27 | }
28 |
29 | @Test
30 | public void testCompare() {
31 | TypeRef ref = new TypeRef() {
32 | };
33 | }
34 |
35 | @Test
36 | public void test2() {
37 | TypeRef ref1 = new TypeRef>() {
38 | };
39 | TypeRef ref2 = new TypeRef>() {
40 | };
41 | TypeRef ref3 = new TypeRef>() {
42 | };
43 |
44 | assert ref1.getType() != ref2.getType();
45 | assert ref1.getType() != ref3.getType();
46 | assert ref3.getType() != ref2.getType();
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/reflect/TypeTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import com.fasterxml.jackson.core.type.TypeReference;
4 | import lombok.Data;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.lang.ref.Reference;
8 | import java.lang.reflect.*;
9 | import java.util.*;
10 |
11 | /**
12 | * Test type
13 | *
14 | * @author sulin
15 | * @since 2019-07-13 17:20:50
16 | */
17 | public class TypeTest {
18 |
19 | @Test
20 | public void testRawType() {
21 | TypeReference ref = new TypeReference>>() {
22 | };
23 | Type type = ref.getType();
24 | System.out.println(type);
25 |
26 | ParameterizedType pt = (ParameterizedType) type;
27 | System.out.println(pt.getRawType() instanceof Class);
28 | }
29 |
30 | @Test
31 | public void testNormalType() throws NoSuchFieldException {
32 | for (Field field : Model.class.getDeclaredFields()) {
33 | System.out.println(field.getGenericType());
34 | }
35 | GenericArrayType tsType = (GenericArrayType) Model.class.getDeclaredField("ts").getGenericType();
36 | System.out.println(tsType);
37 | }
38 |
39 | @Test
40 | public void testGenericType() throws NoSuchFieldException {
41 | TypeReference typeReference = new TypeReference>>() {
42 | };
43 | Type type = typeReference.getType();
44 | System.out.println(type);
45 |
46 | ParameterizedType pt = (ParameterizedType) type;
47 | Class clz = (Class) pt.getRawType();
48 | for (Field field : clz.getDeclaredFields()) {
49 | Type fType = field.getGenericType();
50 | System.out.println(fType);
51 | }
52 |
53 | Type tsType = clz.getDeclaredField("ts").getGenericType();
54 | GenericArrayType arrayType = (GenericArrayType) tsType;
55 | TypeVariable genArrType = (TypeVariable) arrayType.getGenericComponentType();
56 | System.out.println(genArrType.getGenericDeclaration());
57 | System.out.println(tsType);
58 |
59 | Class decClass = (Class) genArrType.getGenericDeclaration();
60 | for (TypeVariable parameter : decClass.getTypeParameters()) {
61 | System.out.println(parameter.getName());
62 | }
63 | }
64 |
65 | @Test
66 | public void testSuper() {
67 | XType xType = XTypeUtils.toXType(Child.class);
68 | assert xType.getField("k") != null;
69 | assert xType.getField("v") != null;
70 | assert xType.getField("xxx") == null;
71 | }
72 |
73 | @Data
74 | public static class Model {
75 | private long time;
76 | private Map objectMap;
77 | private Map strDateMap;
78 | private Map extends Date, ? super String> wildMap;
79 | private List longs;
80 | private T[] ts;
81 | private Reference ref;
82 | }
83 |
84 | @Data
85 | public static class Bean {
86 | private T[] name;
87 | }
88 |
89 | public static class P {
90 | @Data
91 | public class Item {
92 | private T t;
93 | }
94 | }
95 |
96 | public static class Parent {
97 | private K k;
98 | private V v;
99 | }
100 |
101 | public static class Child extends Parent {
102 | private V v;
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/reflect/XTypeUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.reflect;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.awt.*;
6 | import java.lang.ref.Reference;
7 | import java.lang.reflect.Field;
8 | import java.lang.reflect.Method;
9 | import java.lang.reflect.Type;
10 | import java.lang.reflect.TypeVariable;
11 | import java.util.Date;
12 | import java.util.List;
13 |
14 | /**
15 | * @author sulin
16 | * @since 2019-07-22 14:59:45
17 | */
18 | public class XTypeUtilsTest {
19 |
20 | @Test
21 | public void testTypeVariable() throws Exception {
22 | Field field = TypeVariableBean.class.getDeclaredField("t");
23 | TypeVariable typeVariable = (TypeVariable) field.getGenericType();
24 | Type[] bounds = typeVariable.getBounds();
25 | System.out.println(bounds);
26 |
27 | Method method = TypeVariableBean.class.getDeclaredMethod("hh");
28 | TypeVariable returnType = (TypeVariable) method.getGenericReturnType();
29 | Type[] returnBounds = returnType.getBounds();
30 | System.out.println(returnBounds);
31 | }
32 |
33 | @Test
34 | public void testReference() {
35 | XType type = XTypeUtils.toXType(new TypeRef>() {
36 | }.getType());
37 | System.out.println(type);
38 | }
39 |
40 | @Test
41 | public void testGenModel() {
42 | Type type = new TypeRef>() {
43 | }.getType();
44 |
45 | XType xType = XTypeUtils.toXType(type);
46 | System.out.println(xType);
47 | }
48 |
49 | @Test
50 | public void testCache() {
51 | XType prevXT = null;
52 | for (int i = 0; i < 10; i++) {
53 | Type type = new TypeRef>() {
54 | }.getType();
55 | XType xt = XTypeUtils.toXType(type);
56 | assert prevXT == null || prevXT == xt;
57 | prevXT = xt;
58 | System.out.println(xt);
59 | }
60 | }
61 |
62 | @Test
63 | public void testVariable() {
64 | Type type = new TypeRef>() {
65 | }.getType();
66 |
67 | XType> xt = XTypeUtils.toXType(type);
68 |
69 | assert xt.getRawType() == TypeVariableBean.class;
70 |
71 | XField> tField = xt.getField("t");
72 | XField> listField = xt.getField("list");
73 | assert tField != null && listField != null;
74 |
75 | assert tField.getType().getRawType() == Date.class;
76 |
77 | assert listField.getType().getParameterizedType("E").getRawType() == Date.class;
78 | }
79 |
80 | public static class TypeVariableBean {
81 |
82 | private T t;
83 | private List super Date> list;
84 |
85 | public X hh() {
86 | return null;
87 | }
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/transport/ArrayTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | /**
6 | * @author sulin
7 | * @since 2019-09-29 16:36:47
8 | */
9 | public class ArrayTest {
10 |
11 | @Test
12 | public void test() {
13 | Array array = new Array<>();
14 | assert array.cap() == 0;
15 | assert array.size() == 0;
16 |
17 | array.add(1L);
18 | array.add(2L);
19 | array.add(3L);
20 | array.add(4L);
21 | array.add(5L);
22 |
23 | assert array.size() == 5;
24 |
25 | array.clear();
26 | assert array.size() == 0;
27 | assert array.cap() > 0;
28 | }
29 |
30 | @Test
31 | public void testEquals() {
32 | Array array1 = new Array<>();
33 | Array array2 = new Array<>();
34 |
35 | assert !array1.equals(new Object());
36 | assert array1.equals(array2);
37 |
38 | array1.add(1L);
39 | array1.add(2L);
40 | assert !array1.equals(array2);
41 |
42 | array2.add(1L);
43 | assert !array1.equals(array2);
44 |
45 | array2.add(2L);
46 | assert array1.equals(array2);
47 |
48 | array1.add(3L);
49 | array2.add(4L);
50 | assert !array1.equals(array2);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/transport/IDAllocatorTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 |
6 | /**
7 | * @author sulin
8 | * @since 2019-09-30 18:01:40
9 | */
10 | public class IDAllocatorTest {
11 |
12 | @Test
13 | public void test() {
14 | IDAllocator allocator = new IDAllocator();
15 | Assertions.assertEquals(0, allocator.acquire());
16 | Assertions.assertEquals(1, allocator.acquire());
17 | Assertions.assertEquals(2, allocator.acquire());
18 | Assertions.assertEquals(3, allocator.acquire());
19 | Assertions.assertNotEquals(5, allocator.acquire());
20 |
21 | allocator.release(2);
22 | allocator.release(1);
23 | Assertions.assertEquals(1, allocator.acquire());
24 | Assertions.assertEquals(2, allocator.acquire());
25 |
26 | allocator.release(0);
27 | allocator.release(3);
28 | Assertions.assertEquals(0, allocator.acquire());
29 | Assertions.assertEquals(3, allocator.acquire());
30 |
31 | try {
32 | allocator.release(10);
33 | assert false;
34 | } catch (Exception e) {
35 | assert e instanceof IllegalArgumentException;
36 | }
37 |
38 | assert allocator.acquire() == 5;
39 | assert allocator.acquire() == 6;
40 | assert allocator.acquire() == 7;
41 | assert allocator.acquire() == 8;
42 | assert allocator.acquire() == 9;
43 | assert allocator.acquire() == 10;
44 |
45 | allocator.release(6);
46 | allocator.release(7);
47 | allocator.release(8);
48 | allocator.release(9);
49 | allocator.release(3);
50 | allocator.release(1);
51 |
52 | assert allocator.acquire() == 1;
53 | assert allocator.acquire() == 3;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/transport/IOExpireTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import com.github.smartbuf.utils.CodecUtils;
4 | import com.github.smartbuf.node.basic.ObjectNode;
5 | import com.github.smartbuf.node.basic.SymbolNode;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import java.io.IOException;
9 | import java.util.Objects;
10 |
11 | /**
12 | * @author sulin
13 | * @since 2019-11-07 21:39:28
14 | */
15 | public class IOExpireTest {
16 |
17 | @Test
18 | public void testSymbolExpire() throws IOException {
19 | Output.SYMBOL_LIMIT = 4;
20 |
21 | Output output = new Output(true);
22 | Input input = new Input(true);
23 |
24 | for (int i = 0; i <= Output.SYMBOL_LIMIT + 1; i++) {
25 | SymbolNode node = SymbolNode.valueOf("SYM" + i);
26 |
27 | byte[] data = output.write(node);
28 | Object obj = input.read(data);
29 | assert obj instanceof String;
30 | assert Objects.equals(obj, node.value());
31 | }
32 |
33 | // test only DATA_SYMBOL_EXPIRED
34 | byte[] data = output.write("hello world");
35 | Object object = input.read(data);
36 | assert Objects.equals(object, "hello world");
37 | }
38 |
39 | @Test
40 | public void testStructExpire() throws IOException {
41 | Output.STRUCT_LIMIT = 4;
42 |
43 | Output output = new Output(true);
44 | Input input = new Input(true);
45 |
46 | for (int i = 0; i <= Output.STRUCT_LIMIT + 1; i++) {
47 | ObjectNode node = new ObjectNode(true, new String[]{"id", "name" + i}, new Object[]{i, "name" + i});
48 |
49 | byte[] data = output.write(node);
50 | Object obj = input.read(data);
51 |
52 | ObjectNode newNode = CodecUtils.convert(obj, ObjectNode.class);
53 | assert newNode.keys().length == 2;
54 | assert newNode.values().length == 2;
55 | }
56 |
57 | // test only *_EXPIRED
58 | byte[] data = output.write("hello world");
59 | Object object = input.read(data);
60 | assert Objects.equals(object, "hello world");
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/transport/IOFullTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import com.github.smartbuf.utils.CodecUtils;
4 | import com.github.smartbuf.node.basic.SymbolNode;
5 | import lombok.Data;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import java.io.IOException;
9 | import java.util.Arrays;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 | import java.util.Objects;
13 |
14 | /**
15 | * @author sulin
16 | * @since 2019-10-21 20:40:21
17 | */
18 | public class IOFullTest {
19 |
20 | @Test
21 | public void testOthers() throws IOException {
22 | IOTest.enableCxt = false;
23 |
24 | Bean bean = new Bean();
25 | bean.c = 'a';
26 | bean.chars = "hello".toCharArray();
27 | bean.node = SymbolNode.valueOf("HELLO");
28 | Object result = IOTest.transIO(bean);
29 | Bean newBean = CodecUtils.convert(result, Bean.class);
30 | assert bean.c == newBean.c;
31 | assert Arrays.equals(bean.chars, newBean.chars);
32 | assert Objects.equals(bean.node.value(), newBean.node.value());
33 | }
34 |
35 | @Test
36 | public void testMap() throws IOException {
37 | Map map = new HashMap<>();
38 | map.put("id", 1);
39 | map.put("name", "hello");
40 | IOTest.transIO(map);
41 | }
42 |
43 | @Data
44 | public static class Bean {
45 | private Character c;
46 | private char[] chars;
47 | private SymbolNode node;
48 | private double double1;
49 | private Double double2;
50 | private Thread.State state = Thread.State.BLOCKED;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/transport/OutputTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.transport;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import org.apache.commons.lang3.RandomUtils;
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.io.IOException;
10 | import java.math.BigInteger;
11 | import java.util.Arrays;
12 | import java.util.BitSet;
13 | import java.util.Collection;
14 | import java.util.Date;
15 |
16 | /**
17 | * @author sulin
18 | * @since 2019-11-04 16:33:52
19 | */
20 | public class OutputTest {
21 |
22 | @Test
23 | public void test() throws IOException {
24 | Output output = new Output(true);
25 |
26 | assert output.write(null).length == 2;
27 | assert output.write(BigInteger.valueOf(1000L)).length > 2;
28 | assert output.write(new Bean()).length > 2;
29 |
30 | try {
31 | output.writeData(Byte.MAX_VALUE, 1);
32 | assert false;
33 | } catch (Exception e) {
34 | assert e instanceof IllegalArgumentException;
35 | }
36 | }
37 |
38 | @Test
39 | public void testBuffer() throws IOException {
40 | OutputBuffer buffer = new OutputBuffer(1 << 20);
41 | for (int i = 0; i < 1000; i++) {
42 | buffer.writeShort((short) i);
43 | }
44 | buffer.writeBooleanArray(new boolean[100000]);
45 | }
46 |
47 | @Data
48 | public static class Bean {
49 | private int id = RandomUtils.nextInt();
50 | private String name = "hello";
51 | private Date time = new Date();
52 | private BitSet flags = BitSet.valueOf(RandomUtils.nextBytes(8));
53 | private Collection tags = Arrays.asList(new Tag(1, "tag1"), null, new Tag(3, "tag3"));
54 | }
55 |
56 | @Data
57 | @NoArgsConstructor
58 | @AllArgsConstructor
59 | public static class Tag {
60 | private int code;
61 | private String name;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/utils/ASMUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.objectweb.asm.ClassWriter;
5 | import org.objectweb.asm.MethodVisitor;
6 | import org.objectweb.asm.Opcodes;
7 |
8 | /**
9 | * @author sulin
10 | * @since 2019-11-06 20:16:10
11 | */
12 | public class ASMUtilsTest {
13 |
14 | @Test
15 | public void test() {
16 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
17 | cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Test", null, "java/lang/Object", null);
18 |
19 | MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null);
20 | mv.visitCode();
21 | mv.visitVarInsn(Opcodes.ALOAD, 0);
22 | mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false);
23 |
24 | ASMUtils.addIntInstruction(mv, 1 << 20);
25 |
26 | mv.visitInsn(Opcodes.RETURN);
27 | mv.visitMaxs(0, 0);
28 | mv.visitEnd();
29 |
30 | try {
31 | ASMUtils.addBoxInstruction(null, Void.class);
32 | assert false;
33 | } catch (Exception e) {
34 | assert e instanceof IllegalArgumentException;
35 | }
36 |
37 | try {
38 | ASMUtils.addUnboxInstruction(null, Void.class);
39 | assert false;
40 | } catch (Exception e) {
41 | assert e instanceof IllegalArgumentException;
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/utils/ArrayUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import org.apache.commons.lang3.RandomUtils;
4 | import org.junit.jupiter.api.Test;
5 |
6 | /**
7 | * @author sulin
8 | * @since 2019-10-02 15:18:19
9 | */
10 | public class ArrayUtilsTest {
11 |
12 | @Test
13 | public void testDescFastSort() {
14 | ArrayUtils.descFastSort(new int[0], 0, 0);
15 |
16 | int[] arr = {1};
17 | ArrayUtils.descFastSort(arr, 0, 0);
18 | assert arr[0] == 1;
19 |
20 | arr = new int[]{1, 2};
21 | ArrayUtils.descFastSort(arr, 0, 1);
22 | assert arr[0] == 2;
23 | assert arr[1] == 1;
24 |
25 | arr = new int[]{3, 2, 4, 1, 7};
26 | ArrayUtils.descFastSort(arr, 0, arr.length - 1);
27 | assert arr[0] == 7;
28 | assert arr[1] == 4;
29 | assert arr[2] == 3;
30 | assert arr[3] == 2;
31 | assert arr[4] == 1;
32 |
33 | arr = new int[100];
34 | for (int i = 0; i < 100; i++) {
35 | arr[i] = RandomUtils.nextInt(1, 10000000);
36 | }
37 | ArrayUtils.descFastSort(arr, 0, arr.length - 1);
38 | for (int i = 0; i < 99; i++) {
39 | assert arr[i] >= arr[i + 1];
40 | }
41 | }
42 |
43 | @Test
44 | public void testLongArray() {
45 | ArrayUtils.descFastSort(new long[0], 0, 0);
46 |
47 | long[] arr = {1};
48 | ArrayUtils.descFastSort(arr, 0, 0);
49 | assert arr[0] == 1;
50 |
51 | arr = new long[]{1, 2};
52 | ArrayUtils.descFastSort(arr, 0, 1);
53 | assert arr[0] == 2;
54 | assert arr[1] == 1;
55 |
56 | arr = new long[]{3, 2, 4, 1, 7};
57 | ArrayUtils.descFastSort(arr, 0, arr.length - 1);
58 | assert arr[0] == 7;
59 | assert arr[1] == 4;
60 | assert arr[2] == 3;
61 | assert arr[3] == 2;
62 | assert arr[4] == 1;
63 |
64 | arr = new long[100];
65 | for (int i = 0; i < 100; i++) {
66 | arr[i] = RandomUtils.nextInt(1, 10000000);
67 | }
68 | ArrayUtils.descFastSort(arr, 0, arr.length - 1);
69 | for (int i = 0; i < 99; i++) {
70 | assert arr[i] >= arr[i + 1];
71 | }
72 | }
73 |
74 | @Test
75 | public void testAr() {
76 | Object[] arr = new Object[4];
77 | arr[0] = "1";
78 | assert arr[0] == "1";
79 |
80 | arr = ArrayUtils.put(null, 0, "0");
81 | arr = ArrayUtils.put(arr, 1, "1");
82 | arr = ArrayUtils.put(arr, 2, "2");
83 | arr = ArrayUtils.put(arr, 3, "3");
84 | arr = ArrayUtils.put(arr, 4, "4");
85 |
86 | assert arr[0] == "0";
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/utils/NumberUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.commons.lang3.RandomUtils;
5 | import org.junit.jupiter.api.RepeatedTest;
6 | import org.junit.jupiter.api.Test;
7 |
8 | /**
9 | * @author sulin
10 | * @since 2019-04-27 16:14:07
11 | */
12 | @Slf4j
13 | public class NumberUtilsTest {
14 |
15 | @Test
16 | public void testFloat() {
17 | float f = 1.1f;
18 | log.info("{}: \t{}", f, NumberUtils.floatToBits(f));
19 |
20 | for (int i = 0; i < 1000000; i++) {
21 | float f1 = RandomUtils.nextFloat();
22 | int bits = NumberUtils.floatToBits(f1);
23 | float f2 = NumberUtils.bitsToFloat(bits);
24 | if (f1 != f2) {
25 | log.error("err: {}, {}", f1, f2);
26 | }
27 | }
28 | }
29 |
30 | @Test
31 | public void testDouble() {
32 | double d = 1.1;
33 | log.info("{}: \t{}", d, NumberUtils.doubleToBits(d));
34 |
35 | for (int i = 0; i < 1000000; i++) {
36 | double d1 = RandomUtils.nextDouble();
37 | long bits = NumberUtils.doubleToBits(d1);
38 | double d2 = NumberUtils.bitsToDouble(bits);
39 | if (d1 != d2) {
40 | log.error("err: {}, {}", d1, d2);
41 | }
42 | }
43 | }
44 |
45 | @RepeatedTest(1000)
46 | public void testUint() {
47 | this.testUintOnce(RandomUtils.nextLong());
48 | }
49 |
50 | @Test
51 | public void testUint2() {
52 | this.testUintOnce(8976814520369533952L);
53 | }
54 |
55 | private void testUintOnce(long l) {
56 | long ul = NumberUtils.intToUint(l);
57 | long l2 = NumberUtils.uintToInt(ul);
58 | assert l == l2;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/utils/ReflectUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.lang.reflect.Field;
6 |
7 | /**
8 | * @author sulin
9 | * @since 2019-11-09 19:55:16
10 | */
11 | public class ReflectUtilsTest {
12 |
13 | @Test
14 | public void test() throws NoSuchFieldException {
15 | assert ReflectUtils.findAllValidFields(null).isEmpty();
16 | assert ReflectUtils.findAllValidFields(boolean.class).isEmpty();
17 | assert !ReflectUtils.findAllValidFields(Boolean.class).isEmpty();
18 |
19 | Field field = Bean.class.getDeclaredField("blocked");
20 | assert ReflectUtils.findGetter(Bean.class, field) != null;
21 | assert ReflectUtils.findSetter(Bean.class, field) != null;
22 |
23 | field = Bean.class.getDeclaredField("is_valid");
24 | assert ReflectUtils.findGetter(Bean.class, field) != null;
25 | assert ReflectUtils.findSetter(Bean.class, field) != null;
26 |
27 | field = Bean.class.getDeclaredField("is_visible");
28 | assert ReflectUtils.findGetter(Bean.class, field) != null;
29 | assert ReflectUtils.findSetter(Bean.class, field) != null;
30 |
31 | field = Bean.class.getDeclaredField("is_ok");
32 | assert ReflectUtils.findGetter(Bean.class, field) == null;
33 | assert ReflectUtils.findSetter(Bean.class, field) == null;
34 | }
35 |
36 | public static class Bean {
37 | private boolean blocked;
38 | private boolean is_valid;
39 | private boolean is_visible;
40 | private boolean is_ok;
41 |
42 | public boolean isBlocked() {
43 | return blocked;
44 | }
45 |
46 | public void setBlocked(boolean blocked) {
47 | this.blocked = blocked;
48 | }
49 |
50 | public boolean isIs_valid() {
51 | return is_valid;
52 | }
53 |
54 | public void setIs_valid(boolean is_valid) {
55 | this.is_valid = is_valid;
56 | }
57 |
58 | public boolean isIs_visible() {
59 | return is_visible;
60 | }
61 |
62 | public void setIs_visible(boolean is_visible) {
63 | this.is_visible = is_visible;
64 | }
65 |
66 | @Deprecated
67 | public boolean isIs_ok() {
68 | return is_ok;
69 | }
70 |
71 | public static void setIs_ok(boolean is_ok) {
72 | }
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/utils/TimeUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | /**
6 | * @author sulin
7 | * @since 2019-10-08 21:20:43
8 | */
9 | public class TimeUtilsTest {
10 |
11 | @Test
12 | public void test() throws InterruptedException {
13 | long now = TimeUtils.fastNow();
14 | long uptime = TimeUtils.fastUpTime();
15 | System.out.println(now);
16 | System.out.println(uptime);
17 |
18 | Thread.sleep(1000);
19 |
20 | assert TimeUtils.fastNow() > now;
21 | assert TimeUtils.fastUpTime() > uptime;
22 | }
23 |
24 | @Test
25 | public void testThread() throws InterruptedException {
26 | TimeUtils.TIMER_THREAD.interrupt();
27 |
28 | Thread.sleep(100);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/com/github/smartbuf/utils/UTF8UtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.smartbuf.utils;
2 |
3 | import org.apache.commons.lang3.RandomStringUtils;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.nio.CharBuffer;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Objects;
9 |
10 | /**
11 | * @author sulin
12 | * @since 2019-11-05 19:53:37
13 | */
14 | public class UTF8UtilsTest {
15 |
16 | @Test
17 | public void encode() {
18 | String[] strs = new String[]{
19 | "hello world",
20 | "你好,中国",
21 | "😝😝😝😝😝",
22 | RandomStringUtils.random(64),
23 | RandomStringUtils.randomGraph(64)
24 | };
25 |
26 | for (String str : strs) {
27 | byte[] bytes = UTF8Utils.encode(str);
28 | String newStr = new String(bytes, StandardCharsets.UTF_8);
29 | assert Objects.equals(str, newStr);
30 | }
31 | }
32 |
33 | @Test
34 | public void testSurrogate() {
35 | byte[] bytes = UTF8Utils.encode(CharBuffer.wrap(new char[]{0xDDFF}));
36 | assert bytes[0] == UTF8Utils.REPL;
37 |
38 | bytes = UTF8Utils.encode(CharBuffer.wrap(new char[]{0xDBFF}));
39 | assert bytes[0] == UTF8Utils.REPL;
40 |
41 | bytes = UTF8Utils.encode(CharBuffer.wrap(new char[]{0xDBFF, 0x00ff}));
42 | assert bytes[0] == UTF8Utils.REPL;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | UTF-8
8 | %d{yyyy/MM/dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/test/resources/proto/large.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.github.smartbuf.benchmark.large;
4 |
5 | message Trends {
6 | repeated Trend trends = 1;
7 | }
8 |
9 | message Trend {
10 | int64 id = 1;
11 | string id_str = 2;
12 | string name = 3;
13 | string screen_name = 4;
14 | string location = 5;
15 | string description = 6;
16 | string url = 7;
17 | Entities entities = 8;
18 | bool protect = 9;
19 | int64 followers_count = 10;
20 | int64 fast_followers_count = 11;
21 | int64 normal_followers_count = 12;
22 | int64 friends_count = 13;
23 | int64 listed_count = 14;
24 | string created_at = 15;
25 | int64 favourites_count = 16;
26 | string utc_offset = 17;
27 | string time_zone = 18;
28 | bool geo_enabled = 19;
29 | bool verified = 20;
30 | int64 statuses_count = 21;
31 | int64 media_count = 22;
32 | string lang = 23;
33 | bool contributors_enabled = 24;
34 | bool is_translator = 25;
35 | bool is_translation_enabled = 26;
36 | string profile_background_color = 27;
37 | string profile_background_image_url = 28;
38 | string profile_background_image_url_https = 29;
39 | bool profile_background_tile = 30;
40 | string profile_image_url = 31;
41 | string profile_image_url_https = 32;
42 | string profile_banner_url = 33;
43 | string profile_link_color = 34;
44 | string profile_sidebar_border_color = 35;
45 | string profile_sidebar_fill_color = 36;
46 | string profile_text_color = 37;
47 | bool profile_use_background_image = 38;
48 | bool has_extended_profile = 39;
49 | bool default_profile = 40;
50 | bool default_profile_image = 41;
51 | repeated int64 pinned_tweet_ids = 42;
52 | repeated string pinned_tweet_ids_str = 43;
53 | bool has_custom_timelines = 44;
54 | bool can_dm = 45;
55 | bool can_media_tag = 46;
56 | bool following = 47;
57 | bool follow_request_sent = 48;
58 | bool notifications = 49;
59 | bool muting = 50;
60 | bool blocking = 51;
61 | bool blocked_by = 52;
62 | bool want_retweets = 53;
63 | string advertiser_account_type = 54;
64 | repeated string advertiser_account_service_levels = 55;
65 | string profile_interstitial_type = 56;
66 | string business_profile_state = 57;
67 | string translator_type = 58;
68 | bool followed_by = 59;
69 | bool require_some_consent = 60;
70 | }
71 |
72 | message Entities {
73 | Urls url = 1;
74 | Description description = 2;
75 | }
76 |
77 | message Description {
78 | repeated Url urls = 1;
79 | }
80 |
81 | message Urls {
82 | repeated Url urls = 1;
83 | }
84 |
85 | message Url {
86 | string url = 1;
87 | string expanded_url = 2;
88 | string display_url = 3;
89 | repeated int64 indices = 4;
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/resources/proto/medium.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.github.smartbuf.benchmark.medium;
4 |
5 | message User {
6 | int64 id = 1;
7 | string nickname = 2;
8 | string portrait = 3;
9 | float score = 4;
10 | string mail = 5;
11 | string mobile = 6;
12 | string token = 7;
13 | int32 type = 8;
14 | int32 source = 9;
15 | bool blocked = 10;
16 | int32 loginTimes = 11;
17 | int64 updateTime = 12;
18 | int64 createTime = 13;
19 |
20 | repeated Message msgs = 20;
21 | repeated Tag tags = 21;
22 | }
23 |
24 | message Message {
25 | int64 id = 1;
26 | int64 from = 2;
27 | int64 to = 3;
28 | string msg = 4;
29 | int64 timestamp = 5;
30 | }
31 |
32 | message Tag {
33 | int32 code = 1;
34 | string name = 2;
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/resources/proto/message.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.github.smartbuf.model;
4 |
5 | message Message {
6 | int32 id = 1;
7 | bool enable = 2;
8 | float score1 = 3;
9 | double score2 = 4;
10 | string text = 5;
11 | int64 timestamp = 6;
12 | repeated Receiver receivers = 7;
13 | }
14 |
15 | message Receiver {
16 | int32 userId = 1;
17 | string iconUrl = 2;
18 | string remark = 3;
19 | int32 followNum = 4;
20 | int32 fanNum = 5;
21 | int64 createTime = 6;
22 | int64 updateTime = 7;
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/resources/proto/small.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.github.smartbuf.benchmark.small;
4 |
5 | message User {
6 | int64 id = 1;
7 | bool blocked = 2;
8 | string nickname = 3;
9 | string portrait = 4;
10 | float score = 5;
11 | int32 loginTimes = 6;
12 | int64 createTime = 7;
13 | }
14 |
--------------------------------------------------------------------------------
/src/test/resources/proto/tiny.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package com.github.smartbuf.benchmark.tiny;
4 |
5 | message User {
6 | int32 id = 1;
7 | string name = 2;
8 | int64 time = 3;
9 | }
10 |
--------------------------------------------------------------------------------