convert优化features
This commit is contained in:
39
src/main/java/org/redkale/annotation/Scheduled.java
Normal file
39
src/main/java/org/redkale/annotation/Scheduled.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 定时任务标记,只能作用于Service的方法上, 功能类似Spring里的Scheduled注解
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @since 2.8.0
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Scheduled {
|
||||
|
||||
String cron() default "";
|
||||
|
||||
String zone() default "";
|
||||
|
||||
long fixedDelay() default -1;
|
||||
|
||||
String fixedDelayString() default "";
|
||||
|
||||
long fixedRate() default -1;
|
||||
|
||||
String fixedRateString() default "";
|
||||
|
||||
long initialDelay() default -1;
|
||||
|
||||
String initialDelayString() default "";
|
||||
|
||||
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
|
||||
}
|
||||
@@ -338,7 +338,7 @@ public final class ApiDocCommand {
|
||||
swaggerOperatMap.put("deprecated", true);
|
||||
}
|
||||
Map<String, Object> respSchemaMap = new LinkedHashMap<>();
|
||||
JsonFactory returnFactory = Rest.createJsonFactory(false, method.getAnnotationsByType(RestConvert.class), method.getAnnotationsByType(RestConvertCoder.class));
|
||||
JsonFactory returnFactory = Rest.createJsonFactory(0, method.getAnnotationsByType(RestConvert.class), method.getAnnotationsByType(RestConvertCoder.class));
|
||||
simpleSchemaType(returnFactory, node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
|
||||
|
||||
Map<String, Object> respMap = new LinkedHashMap<>();
|
||||
@@ -762,6 +762,6 @@ public final class ApiDocCommand {
|
||||
return example;
|
||||
}
|
||||
|
||||
private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false).nullable(false);
|
||||
private static final JsonFactory exampleFactory = JsonFactory.create().features(0);
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
public abstract class BinaryConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
|
||||
|
||||
protected BinaryConvert(ConvertFactory<R, W> factory) {
|
||||
super(factory);
|
||||
protected BinaryConvert(ConvertFactory<R, W> factory, int features) {
|
||||
super(factory, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,8 +24,11 @@ public abstract class Convert<R extends Reader, W extends Writer> {
|
||||
|
||||
protected final ConvertFactory<R, W> factory;
|
||||
|
||||
protected Convert(ConvertFactory<R, W> factory) {
|
||||
protected final int features;
|
||||
|
||||
protected Convert(ConvertFactory<R, W> factory, int features) {
|
||||
this.factory = factory;
|
||||
this.features = features;
|
||||
}
|
||||
|
||||
public ConvertFactory<R, W> getFactory() {
|
||||
|
||||
@@ -36,6 +36,12 @@ import org.redkale.util.*;
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
//值为true时 String类型值为"",Boolean类型值为false时不会输出,默认为false
|
||||
public static final int FEATURE_TINY = 1 << 1;
|
||||
|
||||
//值为true时 字段值为null时会输出,默认为false
|
||||
public static final int FEATURE_NULLABLE = 1 << 2;
|
||||
|
||||
private static final AtomicBoolean loaderInited = new AtomicBoolean();
|
||||
|
||||
private static Convert defProtobufConvert;
|
||||
@@ -44,9 +50,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
protected Convert<R, W> convert;
|
||||
|
||||
protected boolean tiny; //值为true时 String类型值为"",Boolean类型值为false时不会输出,默认为false
|
||||
|
||||
protected boolean nullable; ///值为true时 字段值为null时会输出,默认为false
|
||||
//配置属性集合, 1<<1至1<<10为系统内置
|
||||
protected int features;
|
||||
|
||||
private final Encodeable<W, ?> anyEncoder = new AnyEncoder(this);
|
||||
|
||||
@@ -74,9 +79,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
private boolean skipAllIgnore = false;
|
||||
|
||||
protected ConvertFactory(ConvertFactory<R, W> parent, boolean tiny, boolean nullable) {
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
protected ConvertFactory(ConvertFactory<R, W> parent, int features) {
|
||||
this.features = features;
|
||||
this.parent = parent;
|
||||
if (parent == null) {
|
||||
//---------------------------------------------------------
|
||||
@@ -209,6 +213,17 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
}
|
||||
}
|
||||
|
||||
public final int features() {
|
||||
return this.features;
|
||||
}
|
||||
|
||||
public ConvertFactory features(int features) {
|
||||
if (features > -1) {
|
||||
this.features = features;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConvertFactory parent() {
|
||||
return this.parent;
|
||||
}
|
||||
@@ -242,8 +257,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
return type == ConvertType.PROTOBUF ? defProtobufConvert : null;
|
||||
}
|
||||
|
||||
protected static boolean getSystemPropertyBoolean(String key, String parentkey, boolean defvalue) {
|
||||
return Boolean.parseBoolean(System.getProperty(key, System.getProperty(parentkey, String.valueOf(defvalue))));
|
||||
protected static int getSystemPropertyInt(String key, String parentkey, boolean defvalue, int feature) {
|
||||
return Boolean.parseBoolean(System.getProperty(key, System.getProperty(parentkey, String.valueOf(defvalue)))) ? feature : 0;
|
||||
}
|
||||
|
||||
public abstract ConvertType getConvertType();
|
||||
@@ -254,7 +269,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
|
||||
public abstract ConvertFactory createChild();
|
||||
|
||||
public abstract ConvertFactory createChild(boolean tiny, boolean nullable);
|
||||
public abstract ConvertFactory createChild(int features);
|
||||
|
||||
protected SimpledCoder createEnumSimpledCoder(Class enumClass) {
|
||||
return new EnumSimpledCoder(this, enumClass);
|
||||
@@ -333,13 +348,29 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|
||||
return convert;
|
||||
}
|
||||
|
||||
public static boolean tinyFeature(int features) {
|
||||
return (features & FEATURE_TINY) > 0;
|
||||
}
|
||||
|
||||
public static boolean nullableFeature(int features) {
|
||||
return (features & FEATURE_NULLABLE) > 0;
|
||||
}
|
||||
|
||||
public ConvertFactory tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
if (tiny) {
|
||||
this.features |= FEATURE_TINY;
|
||||
} else {
|
||||
this.features = this.features & ~FEATURE_TINY;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConvertFactory nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
if (nullable) {
|
||||
this.features |= FEATURE_NULLABLE;
|
||||
} else {
|
||||
this.features = this.features & ~FEATURE_NULLABLE;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
public abstract class TextConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
|
||||
|
||||
protected TextConvert(ConvertFactory<R, W> factory) {
|
||||
super(factory);
|
||||
protected TextConvert(ConvertFactory<R, W> factory, int features) {
|
||||
super(factory, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -35,6 +35,9 @@ public abstract class Writer {
|
||||
//对某个对象进行动态扩展字段值处理
|
||||
protected Function<Object, ConvertField[]> objExtFunc;
|
||||
|
||||
//配置项
|
||||
protected int features;
|
||||
|
||||
/**
|
||||
* 设置specificObjectType
|
||||
*
|
||||
@@ -69,18 +72,27 @@ public abstract class Writer {
|
||||
}
|
||||
|
||||
/**
|
||||
* 当tiny=true时, 字符串为空、boolean为false的字段值都会被跳过, 不会输出。
|
||||
* 获取配置属性
|
||||
*
|
||||
* @return 是否简化
|
||||
*/
|
||||
public abstract boolean tiny();
|
||||
public final int features() {
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当nullable=true时, 字段值为null时会输出该字段
|
||||
*
|
||||
* @return 是否简化
|
||||
*/
|
||||
public abstract boolean nullable();
|
||||
public Writer features(int features) {
|
||||
if (features > -1) {
|
||||
this.features = features;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected final boolean tiny() {
|
||||
return ConvertFactory.tinyFeature(features);
|
||||
}
|
||||
|
||||
protected final boolean nullable() {
|
||||
return ConvertFactory.nullableFeature(features);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出null值
|
||||
|
||||
@@ -26,13 +26,12 @@ public class BsonByteBufferWriter extends BsonWriter {
|
||||
private int index;
|
||||
|
||||
public BsonByteBufferWriter(Supplier<ByteBuffer> supplier) {
|
||||
this(false, false, supplier);
|
||||
this(0, supplier);
|
||||
}
|
||||
|
||||
protected BsonByteBufferWriter(boolean tiny, boolean nullable, Supplier<ByteBuffer> supplier) {
|
||||
protected BsonByteBufferWriter(int features, Supplier<ByteBuffer> supplier) {
|
||||
super((byte[]) null);
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
this.features = features;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@@ -72,14 +71,8 @@ public class BsonByteBufferWriter extends BsonWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonByteBufferWriter tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonByteBufferWriter nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
public BsonByteBufferWriter features(int features) {
|
||||
this.features = features;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,8 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
private final ThreadLocal<BsonReader> readerPool = ThreadLocal.withInitial(BsonReader::new);
|
||||
|
||||
private final boolean tiny;
|
||||
|
||||
private final boolean nullable;
|
||||
|
||||
protected BsonConvert(ConvertFactory<BsonReader, BsonWriter> factory, boolean tiny, boolean nullable) {
|
||||
super(factory);
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
protected BsonConvert(ConvertFactory<BsonReader, BsonWriter> factory, int features) {
|
||||
super(factory, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,7 +76,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
@Override
|
||||
public BsonConvert newConvert(final BiFunction<Attribute, Object, Object> fieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
return new BsonConvert(getFactory(), tiny, nullable) {
|
||||
return new BsonConvert(getFactory(), features) {
|
||||
@Override
|
||||
protected <S extends BsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, fieldFunc, mapFieldFunc, objExtFunc);
|
||||
@@ -120,11 +114,11 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
|
||||
//------------------------------ writer -----------------------------------------------------------
|
||||
public BsonByteBufferWriter pollWriter(final Supplier<ByteBuffer> supplier) {
|
||||
return configWrite(new BsonByteBufferWriter(tiny, nullable, supplier));
|
||||
return configWrite(new BsonByteBufferWriter(features, supplier));
|
||||
}
|
||||
|
||||
protected BsonWriter pollWriter(final OutputStream out) {
|
||||
return configWrite(new BsonStreamWriter(tiny, nullable, out));
|
||||
return configWrite(new BsonStreamWriter(features, out));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,7 +129,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
} else {
|
||||
writerPool.set(null);
|
||||
}
|
||||
return configWrite(writer.tiny(tiny).nullable(nullable));
|
||||
return configWrite(writer.features(features));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,7 +234,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
@Override
|
||||
public void convertToBytes(final ByteArray array, final Type type, final Object value) {
|
||||
Objects.requireNonNull(array);
|
||||
final BsonWriter writer = configWrite(new BsonWriter(array).tiny(tiny).nullable(nullable));
|
||||
final BsonWriter writer = configWrite(new BsonWriter(array).features(features));
|
||||
if (value == null) {
|
||||
writer.writeNull();
|
||||
} else {
|
||||
@@ -286,7 +280,7 @@ public class BsonConvert extends BinaryConvert<BsonReader, BsonWriter> {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
final BsonWriter writer = writerPool.get().tiny(tiny).nullable(nullable);
|
||||
final BsonWriter writer = writerPool.get().features(features);
|
||||
factory.loadEncoder(type == null ? value.getClass() : type).convertTo(writer, value);
|
||||
return writer;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,9 @@ import org.redkale.util.TypeToken;
|
||||
public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
||||
|
||||
private static final BsonFactory instance = new BsonFactory(null,
|
||||
getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true),
|
||||
getSystemPropertyBoolean("redkale.convert.bson.nullable", "redkale.convert.nullable", false));
|
||||
getSystemPropertyInt("redkale.convert.bson.tiny", "redkale.convert.tiny", true, FEATURE_TINY)
|
||||
| getSystemPropertyInt("redkale.convert.bson.nullable", "redkale.convert.nullable", false, FEATURE_NULLABLE)
|
||||
);
|
||||
|
||||
static final Decodeable objectDecoder = instance.loadDecoder(Object.class);
|
||||
|
||||
@@ -50,28 +51,28 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
||||
//instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
|
||||
}
|
||||
|
||||
private BsonFactory(BsonFactory parent, boolean tiny, boolean nullable) {
|
||||
super(parent, tiny, nullable);
|
||||
private BsonFactory(BsonFactory parent, int features) {
|
||||
super(parent, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
super.tiny(tiny);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean tiny() {
|
||||
return this.tiny;
|
||||
return (this.features & FEATURE_TINY) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
super.nullable(nullable);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean nullable() {
|
||||
return this.nullable;
|
||||
return (this.features & FEATURE_NULLABLE) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,26 +86,25 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
|
||||
}
|
||||
|
||||
public static BsonFactory create() {
|
||||
return new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true),
|
||||
getSystemPropertyBoolean("redkale.convert.bson.nullable", "redkale.convert.nullable", false));
|
||||
return new BsonFactory(null, instance.features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BsonConvert getConvert() {
|
||||
if (convert == null) {
|
||||
convert = new BsonConvert(this, tiny, nullable);
|
||||
convert = new BsonConvert(this, features);
|
||||
}
|
||||
return (BsonConvert) convert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory createChild() {
|
||||
return new BsonFactory(this, this.tiny, this.nullable);
|
||||
return new BsonFactory(this, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BsonFactory createChild(boolean tiny, boolean nullable) {
|
||||
return new BsonFactory(this, tiny, nullable);
|
||||
public BsonFactory createChild(int features) {
|
||||
return new BsonFactory(this, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,8 @@ class BsonStreamWriter extends BsonByteBufferWriter {
|
||||
|
||||
private OutputStream out;
|
||||
|
||||
protected BsonStreamWriter(boolean tiny, boolean nullable, OutputStream out) {
|
||||
super(tiny, nullable, null);
|
||||
protected BsonStreamWriter(int features, OutputStream out) {
|
||||
super(features, null);
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@ public class BsonWriter extends Writer implements ByteTuple {
|
||||
|
||||
protected int count;
|
||||
|
||||
protected boolean tiny = BsonFactory.root().tiny();
|
||||
|
||||
protected boolean nullable = BsonFactory.root().nullable();
|
||||
|
||||
public static ObjectPool<BsonWriter> createPool(int max) {
|
||||
return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());
|
||||
}
|
||||
@@ -86,6 +82,7 @@ public class BsonWriter extends Writer implements ByteTuple {
|
||||
|
||||
public BsonWriter() {
|
||||
this(defaultSize);
|
||||
this.features = BsonFactory.root().features();
|
||||
}
|
||||
|
||||
public BsonWriter(int size) {
|
||||
@@ -97,23 +94,8 @@ public class BsonWriter extends Writer implements ByteTuple {
|
||||
this.count = array.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean tiny() {
|
||||
return tiny;
|
||||
}
|
||||
|
||||
public BsonWriter tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean nullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public BsonWriter nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
public BsonWriter features(int features) {
|
||||
super.features(features);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,23 +34,16 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
|
||||
private int index;
|
||||
|
||||
public JsonByteBufferWriter(boolean tiny, boolean nullable, Supplier<ByteBuffer> supplier) {
|
||||
this(tiny, nullable, null, supplier);
|
||||
public JsonByteBufferWriter(int features, Supplier<ByteBuffer> supplier) {
|
||||
this(features, null, supplier);
|
||||
}
|
||||
|
||||
public JsonByteBufferWriter(boolean tiny, boolean nullable, Charset charset, Supplier<ByteBuffer> supplier) {
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
public JsonByteBufferWriter(int features, Charset charset, Supplier<ByteBuffer> supplier) {
|
||||
this.features = features;
|
||||
this.charset = charset;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonByteBufferWriter tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean recycle() {
|
||||
super.recycle();
|
||||
@@ -575,7 +568,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
if (value == null || (tiny() && value.isEmpty())) {
|
||||
expand(1);
|
||||
this.buffers[index].put((byte) '}');
|
||||
} else {
|
||||
@@ -634,7 +627,7 @@ public class JsonByteBufferWriter extends JsonWriter {
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
if (value == null || (tiny() && value.isEmpty())) {
|
||||
int expandsize = expand(2);
|
||||
if (expandsize == 0) { // 只需要一个buffer
|
||||
ByteBuffer bb = this.buffers[index];
|
||||
|
||||
@@ -55,9 +55,8 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
this.count = array.length();
|
||||
}
|
||||
|
||||
public JsonBytesWriter(boolean tiny, boolean nullable, ByteArray array) {
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
public JsonBytesWriter(int features, ByteArray array) {
|
||||
this.features = features;
|
||||
this.content = array.content();
|
||||
this.count = array.length();
|
||||
}
|
||||
@@ -282,7 +281,7 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
if (value == null || (tiny() && value.isEmpty())) {
|
||||
expand(1);
|
||||
content[count++] = '}';
|
||||
} else {
|
||||
@@ -312,7 +311,7 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
|
||||
writeTo('}');
|
||||
return;
|
||||
}
|
||||
if (value == null || (tiny && value.isEmpty())) {
|
||||
if (value == null || (tiny() && value.isEmpty())) {
|
||||
expand(2);
|
||||
content[count++] = '{';
|
||||
content[count++] = '}';
|
||||
|
||||
@@ -40,18 +40,13 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
private final ThreadLocal<JsonReader> readerPool = ThreadLocal.withInitial(JsonReader::new);
|
||||
|
||||
private final boolean tiny;
|
||||
|
||||
private final boolean nullable;
|
||||
|
||||
private Encodeable lastConvertEncodeable;
|
||||
|
||||
private Decodeable lastConvertDecodeable;
|
||||
|
||||
protected JsonConvert(JsonFactory factory, boolean tiny, boolean nullable) {
|
||||
super(factory);
|
||||
this.tiny = tiny;
|
||||
this.nullable = nullable;
|
||||
protected JsonConvert(JsonFactory factory, int features) {
|
||||
super(factory, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,7 +75,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
@Override
|
||||
public JsonConvert newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
|
||||
return new JsonConvert(getFactory(), tiny, nullable) {
|
||||
return new JsonConvert(getFactory(), features) {
|
||||
@Override
|
||||
protected <S extends JsonWriter> S configWrite(S writer) {
|
||||
return fieldFunc(writer, objFieldFunc, mapFieldFunc, objExtFunc);
|
||||
@@ -115,7 +110,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
} else {
|
||||
bytesWriterPool.set(null);
|
||||
}
|
||||
return configWrite((JsonBytesWriter) writer.tiny(tiny).nullable(nullable));
|
||||
return configWrite((JsonBytesWriter) writer.features(features));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,7 +130,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
} else {
|
||||
bytesWriterPool.set(null);
|
||||
}
|
||||
return configWrite((JsonBytesWriter) writer.tiny(tiny).nullable(nullable));
|
||||
return configWrite((JsonBytesWriter) writer.features(features));
|
||||
}
|
||||
|
||||
private void offerJsonBytesWriter(final JsonBytesWriter writer) {
|
||||
@@ -395,7 +390,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
@Override
|
||||
public void convertToBytes(final ByteArray array, final Type type, final Object value) {
|
||||
Objects.requireNonNull(array);
|
||||
JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, nullable, array));
|
||||
JsonBytesWriter writer = configWrite(new JsonBytesWriter(features, array));
|
||||
if (value == null) {
|
||||
writer.writeNull();
|
||||
} else {
|
||||
@@ -415,10 +410,10 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
|
||||
public void convertTo(final OutputStream out, final Type type, final Object value) {
|
||||
if (value == null) {
|
||||
configWrite(new JsonStreamWriter(tiny, nullable, out)).writeNull();
|
||||
configWrite(new JsonStreamWriter(features, out)).writeNull();
|
||||
} else {
|
||||
final Type t = type == null ? value.getClass() : type;
|
||||
JsonStreamWriter writer = configWrite(new JsonStreamWriter(tiny, nullable, out));
|
||||
JsonStreamWriter writer = configWrite(new JsonStreamWriter(features, out));
|
||||
Encodeable encoder = this.lastConvertEncodeable;
|
||||
if (encoder == null || encoder.getType() != t) {
|
||||
encoder = factory.loadEncoder(t);
|
||||
@@ -434,7 +429,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
|
||||
@Override
|
||||
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
|
||||
Objects.requireNonNull(supplier);
|
||||
JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, nullable, supplier));
|
||||
JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(features, supplier));
|
||||
if (value == null) {
|
||||
out.writeNull();
|
||||
} else {
|
||||
|
||||
@@ -386,7 +386,7 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
final Map<String, AccessibleObject> mixedNames = mixedNames0;
|
||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName()
|
||||
+ "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.tiny() + "_" + factory.nullable() + "_" + Utility.md5Hex(memberb.toString()); //tiny必须要加上, 同一个类会有多个字段定制Convert
|
||||
+ "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.features() + "_" + Utility.md5Hex(memberb.toString()); //tiny必须要加上, 同一个类会有多个字段定制Convert
|
||||
try {
|
||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||
Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz;
|
||||
@@ -511,8 +511,10 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
|
||||
int maxLocals = 4;
|
||||
int elementIndex = -1;
|
||||
final boolean tiny = ConvertFactory.tinyFeature(factory.features());
|
||||
final boolean nullable = ConvertFactory.nullableFeature(factory.features());
|
||||
final Class firstType = readGetSetFieldType(members.get(0));
|
||||
final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !factory.tiny() || factory.nullable()); //byte/short/char/int/float/long/double
|
||||
final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !tiny || nullable); //byte/short/char/int/float/long/double
|
||||
|
||||
if (onlyOneLatin1FieldObjectFlag) {
|
||||
//out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++;
|
||||
@@ -670,16 +672,16 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
}
|
||||
}
|
||||
Label msgnotemptyif = null;
|
||||
if (!fieldtype.isPrimitive() && !factory.nullable()) { //if (message != null) { start
|
||||
if (!fieldtype.isPrimitive() && !nullable) { //if (message != null) { start
|
||||
mv.visitVarInsn(loadid, maxLocals);
|
||||
msgnotemptyif = new Label();
|
||||
mv.visitJumpInsn(IFNULL, msgnotemptyif);
|
||||
if (factory.tiny() && fieldtype == String.class) {
|
||||
if (tiny && fieldtype == String.class) {
|
||||
mv.visitVarInsn(loadid, maxLocals);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "isEmpty", "()Z", false);
|
||||
mv.visitJumpInsn(IFNE, msgnotemptyif);
|
||||
}
|
||||
} else if (fieldtype == boolean.class && factory.tiny()) {
|
||||
} else if (fieldtype == boolean.class && tiny) {
|
||||
mv.visitVarInsn(loadid, maxLocals);
|
||||
msgnotemptyif = new Label();
|
||||
mv.visitJumpInsn(IFEQ, msgnotemptyif);
|
||||
@@ -794,10 +796,10 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|
||||
mv.visitVarInsn(loadid, maxLocals);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, encodeableName, "convertTo", "(" + writerDesc + "Ljava/lang/Object;)V", true);
|
||||
}
|
||||
if (!fieldtype.isPrimitive() && !factory.nullable()) { //if (message != null) } end
|
||||
if (!fieldtype.isPrimitive() && !nullable) { //if (message != null) } end
|
||||
mv.visitLabel(msgnotemptyif);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
} else if (fieldtype == boolean.class && factory.tiny()) {
|
||||
} else if (fieldtype == boolean.class && tiny) {
|
||||
mv.visitLabel(msgnotemptyif);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,9 @@ import org.redkale.util.Uint128;
|
||||
public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
|
||||
private static final JsonFactory instance = new JsonFactory(null,
|
||||
getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", false),
|
||||
getSystemPropertyBoolean("redkale.convert.json.nullable", "redkale.convert.nullable", false));
|
||||
getSystemPropertyInt("redkale.convert.json.tiny", "redkale.convert.tiny", false, FEATURE_TINY)
|
||||
| getSystemPropertyInt("redkale.convert.json.nullable", "redkale.convert.nullable", false, FEATURE_NULLABLE)
|
||||
);
|
||||
|
||||
static {
|
||||
instance.register(Serializable.class, instance.loadEncoder(Object.class));
|
||||
@@ -35,8 +36,8 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
//instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class));
|
||||
}
|
||||
|
||||
private JsonFactory(JsonFactory parent, boolean tiny, boolean nullable) {
|
||||
super(parent, tiny, nullable);
|
||||
private JsonFactory(JsonFactory parent, int features) {
|
||||
super(parent, features);
|
||||
if (parent == null) {
|
||||
this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance);
|
||||
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
|
||||
@@ -55,15 +56,8 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
public JsonFactory features(int features) {
|
||||
this.features = features;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -78,9 +72,8 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
}
|
||||
|
||||
public static JsonFactory create() {
|
||||
return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", false),
|
||||
getSystemPropertyBoolean("redkale.convert.json.nullable", "redkale.convert.nullable", false));
|
||||
}
|
||||
return new JsonFactory(null, instance.features());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <E> Encodeable<JsonWriter, E> createDyncEncoder(Type type) {
|
||||
@@ -97,30 +90,22 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
|
||||
return new JsonMultiImplDecoder(this, types);
|
||||
}
|
||||
|
||||
protected boolean tiny() {
|
||||
return this.tiny;
|
||||
}
|
||||
|
||||
protected boolean nullable() {
|
||||
return this.nullable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final JsonConvert getConvert() {
|
||||
if (convert == null) {
|
||||
convert = new JsonConvert(this, tiny, nullable);
|
||||
convert = new JsonConvert(this, features);
|
||||
}
|
||||
return (JsonConvert) convert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory createChild() {
|
||||
return new JsonFactory(this, this.tiny, this.nullable);
|
||||
return new JsonFactory(this, this.features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonFactory createChild(boolean tiny, boolean nullable) {
|
||||
return new JsonFactory(this, tiny, nullable);
|
||||
public JsonFactory createChild(int features) {
|
||||
return new JsonFactory(this, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,12 +21,12 @@ class JsonStreamWriter extends JsonByteBufferWriter {
|
||||
|
||||
private OutputStream out;
|
||||
|
||||
protected JsonStreamWriter(boolean tiny, boolean nullable, OutputStream out) {
|
||||
this(tiny, nullable, null, out);
|
||||
protected JsonStreamWriter(int features, OutputStream out) {
|
||||
this(features, null, out);
|
||||
}
|
||||
|
||||
protected JsonStreamWriter(boolean tiny, boolean nullable, Charset charset, OutputStream out) {
|
||||
super(tiny, nullable, charset, null);
|
||||
protected JsonStreamWriter(int features, Charset charset, OutputStream out) {
|
||||
super(features, charset, null);
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,17 +21,12 @@ public abstract class JsonWriter extends Writer {
|
||||
|
||||
protected static final int defaultSize = Integer.getInteger("redkale.convert.json.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024));
|
||||
|
||||
protected boolean tiny = JsonFactory.root().tiny();
|
||||
|
||||
protected boolean nullable = JsonFactory.root().nullable();
|
||||
|
||||
@Override
|
||||
public boolean tiny() {
|
||||
return tiny;
|
||||
protected JsonWriter() {
|
||||
this.features = JsonFactory.root().features();
|
||||
}
|
||||
|
||||
public JsonWriter tiny(boolean tiny) {
|
||||
this.tiny = tiny;
|
||||
public JsonWriter features(int features) {
|
||||
super.features(features);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -40,16 +35,6 @@ public abstract class JsonWriter extends Writer {
|
||||
return this.objExtFunc == null && this.objFieldFunc == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public JsonWriter nullable(boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
public abstract void writeTo(final char ch); //只能是 0 - 127 的字符
|
||||
|
||||
|
||||
@@ -172,14 +172,17 @@ public final class Rest {
|
||||
}
|
||||
|
||||
public static JsonFactory createJsonFactory(RestConvert[] converts, RestConvertCoder[] coders) {
|
||||
return createJsonFactory(true, converts, coders);
|
||||
return createJsonFactory(-1, converts, coders);
|
||||
}
|
||||
|
||||
public static JsonFactory createJsonFactory(boolean tiny, RestConvert[] converts, RestConvertCoder[] coders) {
|
||||
public static JsonFactory createJsonFactory(int features, RestConvert[] converts, RestConvertCoder[] coders) {
|
||||
if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) {
|
||||
return JsonFactory.root();
|
||||
}
|
||||
final JsonFactory childFactory = JsonFactory.create().tiny(tiny);
|
||||
final JsonFactory childFactory = JsonFactory.create();
|
||||
if (features > -1) {
|
||||
childFactory.features(features);
|
||||
}
|
||||
List<Class> types = new ArrayList<>();
|
||||
Set<Class> reloadTypes = new HashSet<>();
|
||||
if (coders != null) {
|
||||
@@ -208,8 +211,8 @@ public final class Rest {
|
||||
childFactory.reloadCoder(rc.type());
|
||||
}
|
||||
types.add(rc.type());
|
||||
if (tiny) {
|
||||
childFactory.tiny(rc.tiny());
|
||||
if (rc.features() > -1) {
|
||||
childFactory.features(rc.features());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2287,7 +2290,7 @@ public final class Rest {
|
||||
//设置 RestConvert
|
||||
for (RestConvert rc : rcs) {
|
||||
AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertDesc);
|
||||
av2.visit("tiny", rc.tiny());
|
||||
av2.visit("features", rc.features());
|
||||
av2.visit("skipIgnore", rc.skipIgnore());
|
||||
av2.visit("type", Type.getType(Type.getDescriptor(rc.type())));
|
||||
AnnotationVisitor av3 = av2.visitArray("onlyColumns");
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能依附在Service实现类的public方法上, 当方法的返回值以JSON输出时对指定类型的转换设定。 <br>
|
||||
@@ -26,11 +26,11 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
public @interface RestConvert {
|
||||
|
||||
/**
|
||||
* 是否输出空字符串,0数值
|
||||
* 配置项
|
||||
*
|
||||
* @return boolean
|
||||
* @return int
|
||||
*/
|
||||
boolean tiny() default true;
|
||||
int features() default -1;
|
||||
|
||||
/**
|
||||
* 是否忽略ConvertColumn.ignore=true的设置, 优先级最高
|
||||
|
||||
18
src/main/java/org/redkale/source/CacheEventListener.java
Normal file
18
src/main/java/org/redkale/source/CacheEventListener.java
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.source;
|
||||
|
||||
/**
|
||||
* CacheSource订阅频道的消费监听器
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public interface CacheEventListener<T> {
|
||||
|
||||
public void onMessage(String topic, T message);
|
||||
}
|
||||
@@ -161,6 +161,26 @@ public final class CacheMemorySource extends AbstractCacheSource {
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
|
||||
//------------------------ 订阅发布 SUB/PUB ------------------------
|
||||
@Override
|
||||
public CompletableFuture<List<String>> pubsubChannelsAsync(@Nullable String pattern){
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> subscribeAsync(CacheEventListener<byte[]> consumer, String... topics) {
|
||||
Objects.requireNonNull(consumer);
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Integer> publishAsync(String topic, byte[] message) {
|
||||
Objects.requireNonNull(topic);
|
||||
Objects.requireNonNull(message);
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
//------------------------ 字符串 String ------------------------
|
||||
@Override
|
||||
public CompletableFuture<Void> msetAsync(Serializable... keyVals) {
|
||||
return runFuture(() -> {
|
||||
|
||||
@@ -10,8 +10,9 @@ import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.redkale.annotation.Component;
|
||||
import org.redkale.annotation.*;
|
||||
import org.redkale.convert.Convert;
|
||||
import org.redkale.convert.json.JsonConvert;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
@@ -36,6 +37,79 @@ public interface CacheSource extends Resourcable {
|
||||
return isOpenAsync().join();
|
||||
}
|
||||
|
||||
//------------------------ 订阅发布 SUB/PUB ------------------------
|
||||
default List<String> pubsubChannels(@Nullable String pattern) {
|
||||
return pubsubChannelsAsync(pattern).join();
|
||||
}
|
||||
|
||||
public CompletableFuture<List<String>> pubsubChannelsAsync(@Nullable String pattern);
|
||||
|
||||
//------------------------ 订阅 SUB ------------------------
|
||||
default <T> void subscribe(Type messageType, CacheEventListener<T> listener, String... topics) {
|
||||
subscribe(JsonConvert.root(), messageType, listener, topics);
|
||||
}
|
||||
|
||||
default <T> void subscribe(Convert convert, Type messageType, CacheEventListener<T> listener, String... topics) {
|
||||
final Convert c = convert == null ? JsonConvert.root() : convert;
|
||||
subscribe((t, bs) -> listener.onMessage(t, bs == null ? null : (T) c.convertFrom(messageType, bs)), topics);
|
||||
}
|
||||
|
||||
default void subscribe(CacheEventListener<byte[]> listener, String... topics) {
|
||||
subscribeAsync(listener, topics).join();
|
||||
}
|
||||
|
||||
default <T> CompletableFuture<Void> subscribeAsync(Type messageType, CacheEventListener<T> listener, String... topics) {
|
||||
return subscribeAsync(JsonConvert.root(), messageType, listener, topics);
|
||||
}
|
||||
|
||||
default <T> CompletableFuture<Void> subscribeAsync(Convert convert, Type messageType, CacheEventListener<T> listener, String... topics) {
|
||||
final Convert c = convert == null ? JsonConvert.root() : convert;
|
||||
return subscribeAsync((t, bs) -> listener.onMessage(t, bs == null ? null : (T) c.convertFrom(messageType, bs)), topics);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> subscribeAsync(CacheEventListener<byte[]> listener, String... topics);
|
||||
|
||||
//------------------------ 发布 PUB ------------------------
|
||||
default <T> int publish(String topic, T message) {
|
||||
return publish(topic, JsonConvert.root(), message.getClass(), message);
|
||||
}
|
||||
|
||||
default <T> int publish(String topic, Convert convert, T message) {
|
||||
return publish(topic, convert, message.getClass(), message);
|
||||
}
|
||||
|
||||
default <T> int publish(String topic, Type messageType, T message) {
|
||||
return publish(topic, JsonConvert.root(), messageType, message);
|
||||
}
|
||||
|
||||
default <T> int publish(String topic, Convert convert, Type messageType, T message) {
|
||||
final Convert c = convert == null ? JsonConvert.root() : convert;
|
||||
return publish(topic, c.convertToBytes(messageType, message));
|
||||
}
|
||||
|
||||
default int publish(String topic, byte[] message) {
|
||||
return publishAsync(topic, message).join();
|
||||
}
|
||||
|
||||
default <T> CompletableFuture<Integer> publishAsync(String topic, T message) {
|
||||
return publishAsync(topic, JsonConvert.root(), message.getClass(), message);
|
||||
}
|
||||
|
||||
default <T> CompletableFuture<Integer> publishAsync(String topic, Convert convert, T message) {
|
||||
return publishAsync(topic, convert, message.getClass(), message);
|
||||
}
|
||||
|
||||
default <T> CompletableFuture<Integer> publishAsync(String topic, Type messageType, T message) {
|
||||
return publishAsync(topic, JsonConvert.root(), messageType, message);
|
||||
}
|
||||
|
||||
default <T> CompletableFuture<Integer> publishAsync(String topic, Convert convert, Type messageType, T message) {
|
||||
final Convert c = convert == null ? JsonConvert.root() : convert;
|
||||
return publishAsync(topic, c.convertToBytes(messageType, message));
|
||||
}
|
||||
|
||||
public CompletableFuture<Integer> publishAsync(String topic, byte[] message);
|
||||
|
||||
//------------------------ 字符串 String ------------------------
|
||||
default long incr(String key) {
|
||||
return incrAsync(key).join();
|
||||
|
||||
643
src/main/java/org/redkale/util/CronExpression.java
Normal file
643
src/main/java/org/redkale/util/CronExpression.java
Normal file
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
package org.redkale.util;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.*;
|
||||
import java.util.*;
|
||||
import org.redkale.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* cron定时表达式解析器 <br> 代码复制于org.springframework.scheduling.support.CronExpression
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class CronExpression {
|
||||
|
||||
static final int MAX_ATTEMPTS = 366;
|
||||
|
||||
private static final String[] MACROS = new String[]{
|
||||
"@yearly", "0 0 0 1 1 *",
|
||||
"@annually", "0 0 0 1 1 *",
|
||||
"@monthly", "0 0 0 1 * *",
|
||||
"@weekly", "0 0 0 * * 0",
|
||||
"@daily", "0 0 0 * * *",
|
||||
"@midnight", "0 0 0 * * *",
|
||||
"@hourly", "0 0 * * * *"
|
||||
};
|
||||
|
||||
private final CronField[] fields;
|
||||
|
||||
private final String expression;
|
||||
|
||||
private CronExpression(CronField seconds, CronField minutes, CronField hours,
|
||||
CronField daysOfMonth, CronField months, CronField daysOfWeek, String expression) {
|
||||
this.fields = new CronField[]{daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public static CronExpression parse(String expression) {
|
||||
if (Utility.isBlank(expression)) {
|
||||
throw new RedkaleException("Expression string must not be empty");
|
||||
}
|
||||
expression = resolveMacros(expression);
|
||||
String[] fields = expression.split("\\s+");
|
||||
if (fields.length != 6) {
|
||||
throw new RedkaleException(String.format("Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
|
||||
}
|
||||
try {
|
||||
CronField seconds = CronField.parseSeconds(fields[0]);
|
||||
CronField minutes = CronField.parseMinutes(fields[1]);
|
||||
CronField hours = CronField.parseHours(fields[2]);
|
||||
CronField daysOfMonth = CronField.parseDaysOfMonth(fields[3]);
|
||||
CronField months = CronField.parseMonth(fields[4]);
|
||||
CronField daysOfWeek = CronField.parseDaysOfWeek(fields[5]);
|
||||
return new CronExpression(seconds, minutes, hours, daysOfMonth, months, daysOfWeek, expression);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String msg = ex.getMessage() + " in cron expression \"" + expression + "\"";
|
||||
throw new RedkaleException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static String resolveMacros(String expression) {
|
||||
expression = expression.trim();
|
||||
for (int i = 0; i < MACROS.length; i = i + 2) {
|
||||
if (MACROS[i].equalsIgnoreCase(expression)) {
|
||||
return MACROS[i + 1];
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends Temporal & Comparable<? super T>> T next(T temporal) {
|
||||
return nextOrSame(ChronoUnit.NANOS.addTo(temporal, 1));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
for (int i = 0; i < MAX_ATTEMPTS; i++) {
|
||||
T result = nextOrSameInternal(temporal);
|
||||
if (result == null || result.equals(temporal)) {
|
||||
return result;
|
||||
}
|
||||
temporal = result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T extends Temporal & Comparable<? super T>> T nextOrSameInternal(T temporal) {
|
||||
for (CronField field : this.fields) {
|
||||
temporal = field.nextOrSame(temporal);
|
||||
if (temporal == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return temporal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof CronExpression)) {
|
||||
return false;
|
||||
}
|
||||
CronExpression that = (CronExpression) other;
|
||||
return Arrays.equals(this.fields, that.fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(this.fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
abstract static class CronField {
|
||||
|
||||
private static final String[] MONTHS = new String[]{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP",
|
||||
"OCT", "NOV", "DEC"};
|
||||
|
||||
private static final String[] DAYS = new String[]{"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
|
||||
|
||||
private final Type type;
|
||||
|
||||
protected CronField(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static CronField zeroNanos() {
|
||||
return BitsCronField.zeroNanos();
|
||||
}
|
||||
|
||||
public static CronField parseSeconds(String value) {
|
||||
return BitsCronField.parseSeconds(value);
|
||||
}
|
||||
|
||||
public static CronField parseMinutes(String value) {
|
||||
return BitsCronField.parseMinutes(value);
|
||||
}
|
||||
|
||||
public static CronField parseHours(String value) {
|
||||
return BitsCronField.parseHours(value);
|
||||
}
|
||||
|
||||
public static CronField parseDaysOfMonth(String value) {
|
||||
return BitsCronField.parseDaysOfMonth(value);
|
||||
}
|
||||
|
||||
public static CronField parseMonth(String value) {
|
||||
value = replaceOrdinals(value, MONTHS);
|
||||
return BitsCronField.parseMonth(value);
|
||||
}
|
||||
|
||||
public static CronField parseDaysOfWeek(String value) {
|
||||
value = replaceOrdinals(value, DAYS);
|
||||
return BitsCronField.parseDaysOfWeek(value);
|
||||
}
|
||||
|
||||
private static String replaceOrdinals(String value, String[] list) {
|
||||
value = value.toUpperCase();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
String replacement = Integer.toString(i + 1);
|
||||
value = replace(value, list[i], replacement);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String replace(String inString, String oldPattern, @Nullable String newPattern) {
|
||||
if (Utility.isEmpty(inString) || Utility.isEmpty(oldPattern) || newPattern == null) {
|
||||
return inString;
|
||||
}
|
||||
int index = inString.indexOf(oldPattern);
|
||||
if (index == -1) {
|
||||
// no occurrence -> can return input as-is
|
||||
return inString;
|
||||
}
|
||||
|
||||
int capacity = inString.length();
|
||||
if (newPattern.length() > oldPattern.length()) {
|
||||
capacity += 16;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(capacity);
|
||||
|
||||
int pos = 0; // our position in the old string
|
||||
int patLen = oldPattern.length();
|
||||
while (index >= 0) {
|
||||
sb.append(inString, pos, index);
|
||||
sb.append(newPattern);
|
||||
pos = index + patLen;
|
||||
index = inString.indexOf(oldPattern, pos);
|
||||
}
|
||||
|
||||
// append any characters to the right of a match
|
||||
sb.append(inString, pos, inString.length());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String[] delimitedListToStringArray(@Nullable String str, @Nullable String delimiter) {
|
||||
return delimitedListToStringArray(str, delimiter, null);
|
||||
}
|
||||
|
||||
private static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {
|
||||
|
||||
if (str == null) {
|
||||
return new String[0];
|
||||
}
|
||||
if (delimiter == null) {
|
||||
return new String[]{str};
|
||||
}
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
if (delimiter.isEmpty()) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
result.add(deleteAny(str.substring(i, i + 1), charsToDelete));
|
||||
}
|
||||
} else {
|
||||
int pos = 0;
|
||||
int delPos;
|
||||
while ((delPos = str.indexOf(delimiter, pos)) != -1) {
|
||||
result.add(deleteAny(str.substring(pos, delPos), charsToDelete));
|
||||
pos = delPos + delimiter.length();
|
||||
}
|
||||
if (str.length() > 0 && pos <= str.length()) {
|
||||
// Add rest of String, but not in case of empty input.
|
||||
result.add(deleteAny(str.substring(pos), charsToDelete));
|
||||
}
|
||||
}
|
||||
return result.toArray(new String[result.size()]);
|
||||
}
|
||||
|
||||
private static String deleteAny(String inString, @Nullable String charsToDelete) {
|
||||
if (Utility.isEmpty(inString) || Utility.isEmpty(charsToDelete)) {
|
||||
return inString;
|
||||
}
|
||||
int lastCharIndex = 0;
|
||||
char[] result = new char[inString.length()];
|
||||
for (int i = 0; i < inString.length(); i++) {
|
||||
char c = inString.charAt(i);
|
||||
if (charsToDelete.indexOf(c) == -1) {
|
||||
result[lastCharIndex++] = c;
|
||||
}
|
||||
}
|
||||
if (lastCharIndex == inString.length()) {
|
||||
return inString;
|
||||
}
|
||||
return new String(result, 0, lastCharIndex);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal);
|
||||
|
||||
protected Type type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static <T extends Temporal & Comparable<? super T>> T cast(Temporal temporal) {
|
||||
return (T) temporal;
|
||||
}
|
||||
|
||||
protected enum Type {
|
||||
NANO(ChronoField.NANO_OF_SECOND, ChronoUnit.SECONDS),
|
||||
SECOND(ChronoField.SECOND_OF_MINUTE, ChronoUnit.MINUTES, ChronoField.NANO_OF_SECOND),
|
||||
MINUTE(ChronoField.MINUTE_OF_HOUR, ChronoUnit.HOURS, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
HOUR(ChronoField.HOUR_OF_DAY, ChronoUnit.DAYS, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
DAY_OF_MONTH(ChronoField.DAY_OF_MONTH, ChronoUnit.MONTHS, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
MONTH(ChronoField.MONTH_OF_YEAR, ChronoUnit.YEARS, ChronoField.DAY_OF_MONTH, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND),
|
||||
DAY_OF_WEEK(ChronoField.DAY_OF_WEEK, ChronoUnit.WEEKS, ChronoField.HOUR_OF_DAY, ChronoField.MINUTE_OF_HOUR, ChronoField.SECOND_OF_MINUTE, ChronoField.NANO_OF_SECOND);
|
||||
|
||||
private final ChronoField field;
|
||||
|
||||
private final ChronoUnit higherOrder;
|
||||
|
||||
private final ChronoField[] lowerOrders;
|
||||
|
||||
Type(ChronoField field, ChronoUnit higherOrder, ChronoField... lowerOrders) {
|
||||
this.field = field;
|
||||
this.higherOrder = higherOrder;
|
||||
this.lowerOrders = lowerOrders;
|
||||
}
|
||||
|
||||
public int get(Temporal date) {
|
||||
return date.get(this.field);
|
||||
}
|
||||
|
||||
public ValueRange range() {
|
||||
return this.field.range();
|
||||
}
|
||||
|
||||
public int checkValidValue(int value) {
|
||||
if (this == DAY_OF_WEEK && value == 0) {
|
||||
return value;
|
||||
} else {
|
||||
try {
|
||||
return this.field.checkValidIntValue(value);
|
||||
} catch (DateTimeException ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Temporal & Comparable<? super T>> T elapseUntil(T temporal, int goal) {
|
||||
int current = get(temporal);
|
||||
ValueRange range = temporal.range(this.field);
|
||||
if (current < goal) {
|
||||
if (range.isValidIntValue(goal)) {
|
||||
return cast(temporal.with(this.field, goal));
|
||||
} else {
|
||||
// goal is invalid, eg. 29th Feb, so roll forward
|
||||
long amount = range.getMaximum() - current + 1;
|
||||
return this.field.getBaseUnit().addTo(temporal, amount);
|
||||
}
|
||||
} else {
|
||||
long amount = goal + range.getMaximum() - current + 1 - range.getMinimum();
|
||||
return this.field.getBaseUnit().addTo(temporal, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Temporal & Comparable<? super T>> T rollForward(T temporal) {
|
||||
T result = this.higherOrder.addTo(temporal, 1);
|
||||
ValueRange range = result.range(this.field);
|
||||
return this.field.adjustInto(result, range.getMinimum());
|
||||
}
|
||||
|
||||
public <T extends Temporal> T reset(T temporal) {
|
||||
for (ChronoField lowerOrder : this.lowerOrders) {
|
||||
if (temporal.isSupported(lowerOrder)) {
|
||||
temporal = lowerOrder.adjustInto(temporal, temporal.range(lowerOrder).getMinimum());
|
||||
}
|
||||
}
|
||||
return temporal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.field.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class BitsCronField extends CronField {
|
||||
|
||||
private static final long MASK = 0xFFFFFFFFFFFFFFFFL;
|
||||
|
||||
@Nullable
|
||||
private static BitsCronField zeroNanos = null;
|
||||
|
||||
// we store at most 60 bits, for seconds and minutes, so a 64-bit long suffices
|
||||
private long bits;
|
||||
|
||||
private BitsCronField(Type type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public static BitsCronField zeroNanos() {
|
||||
if (zeroNanos == null) {
|
||||
BitsCronField field = new BitsCronField(Type.NANO);
|
||||
field.setBit(0);
|
||||
zeroNanos = field;
|
||||
}
|
||||
return zeroNanos;
|
||||
}
|
||||
|
||||
public static BitsCronField parseSeconds(String value) {
|
||||
return parseField(value, Type.SECOND);
|
||||
}
|
||||
|
||||
public static BitsCronField parseMinutes(String value) {
|
||||
return BitsCronField.parseField(value, Type.MINUTE);
|
||||
}
|
||||
|
||||
public static BitsCronField parseHours(String value) {
|
||||
return BitsCronField.parseField(value, Type.HOUR);
|
||||
}
|
||||
|
||||
public static BitsCronField parseDaysOfMonth(String value) {
|
||||
return parseDate(value, Type.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
public static BitsCronField parseMonth(String value) {
|
||||
return BitsCronField.parseField(value, Type.MONTH);
|
||||
}
|
||||
|
||||
public static BitsCronField parseDaysOfWeek(String value) {
|
||||
BitsCronField result = parseDate(value, Type.DAY_OF_WEEK);
|
||||
if (result.getBit(0)) {
|
||||
// cron supports 0 for Sunday; we use 7 like java.time
|
||||
result.setBit(7);
|
||||
result.clearBit(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BitsCronField parseDate(String value, BitsCronField.Type type) {
|
||||
if (value.equals("?")) {
|
||||
value = "*";
|
||||
}
|
||||
return BitsCronField.parseField(value, type);
|
||||
}
|
||||
|
||||
private static BitsCronField parseField(String value, Type type) {
|
||||
if (Utility.isBlank(value)) {
|
||||
throw new RedkaleException("Value must not be empty");
|
||||
}
|
||||
if (type == null) {
|
||||
throw new RedkaleException("Type must not be null");
|
||||
}
|
||||
try {
|
||||
BitsCronField result = new BitsCronField(type);
|
||||
String[] fields = CronField.delimitedListToStringArray(value, ",");
|
||||
for (String field : fields) {
|
||||
int slashPos = field.indexOf('/');
|
||||
if (slashPos == -1) {
|
||||
ValueRange range = parseRange(field, type);
|
||||
result.setBits(range);
|
||||
} else {
|
||||
String rangeStr = field.substring(0, slashPos);
|
||||
String deltaStr = field.substring(slashPos + 1);
|
||||
ValueRange range = parseRange(rangeStr, type);
|
||||
if (rangeStr.indexOf('-') == -1) {
|
||||
range = ValueRange.of(range.getMinimum(), type.range().getMaximum());
|
||||
}
|
||||
int delta = Integer.parseInt(deltaStr);
|
||||
if (delta <= 0) {
|
||||
throw new IllegalArgumentException("Incrementer delta must be 1 or higher");
|
||||
}
|
||||
result.setBits(range, delta);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (DateTimeException | IllegalArgumentException ex) {
|
||||
String msg = ex.getMessage() + " '" + value + "'";
|
||||
throw new IllegalArgumentException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static ValueRange parseRange(String value, Type type) {
|
||||
if (value.equals("*")) {
|
||||
return type.range();
|
||||
} else {
|
||||
int hyphenPos = value.indexOf('-');
|
||||
if (hyphenPos == -1) {
|
||||
int result = type.checkValidValue(Integer.parseInt(value));
|
||||
return ValueRange.of(result, result);
|
||||
} else {
|
||||
int min = Integer.parseInt(value, 0, hyphenPos, 10);
|
||||
int max = Integer.parseInt(value, hyphenPos + 1, value.length(), 10);
|
||||
min = type.checkValidValue(min);
|
||||
max = type.checkValidValue(max);
|
||||
if (type == Type.DAY_OF_WEEK && min == 7) {
|
||||
// If used as a minimum in a range, Sunday means 0 (not 7)
|
||||
min = 0;
|
||||
}
|
||||
return ValueRange.of(min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
int current = type().get(temporal);
|
||||
int next = nextSetBit(current);
|
||||
if (next == -1) {
|
||||
temporal = type().rollForward(temporal);
|
||||
next = nextSetBit(0);
|
||||
}
|
||||
if (next == current) {
|
||||
return temporal;
|
||||
} else {
|
||||
int count = 0;
|
||||
current = type().get(temporal);
|
||||
while (current != next && count++ < CronExpression.MAX_ATTEMPTS) {
|
||||
temporal = type().elapseUntil(temporal, next);
|
||||
current = type().get(temporal);
|
||||
next = nextSetBit(current);
|
||||
if (next == -1) {
|
||||
temporal = type().rollForward(temporal);
|
||||
next = nextSetBit(0);
|
||||
}
|
||||
}
|
||||
if (count >= CronExpression.MAX_ATTEMPTS) {
|
||||
return null;
|
||||
}
|
||||
return type().reset(temporal);
|
||||
}
|
||||
}
|
||||
|
||||
boolean getBit(int index) {
|
||||
return (this.bits & (1L << index)) != 0;
|
||||
}
|
||||
|
||||
private int nextSetBit(int fromIndex) {
|
||||
long result = this.bits & (MASK << fromIndex);
|
||||
if (result != 0) {
|
||||
return Long.numberOfTrailingZeros(result);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setBits(ValueRange range) {
|
||||
if (range.getMinimum() == range.getMaximum()) {
|
||||
setBit((int) range.getMinimum());
|
||||
} else {
|
||||
long minMask = MASK << range.getMinimum();
|
||||
long maxMask = MASK >>> -(range.getMaximum() + 1);
|
||||
this.bits |= (minMask & maxMask);
|
||||
}
|
||||
}
|
||||
|
||||
private void setBits(ValueRange range, int delta) {
|
||||
if (delta == 1) {
|
||||
setBits(range);
|
||||
} else {
|
||||
for (int i = (int) range.getMinimum(); i <= range.getMaximum(); i += delta) {
|
||||
setBit(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setBit(int index) {
|
||||
this.bits |= (1L << index);
|
||||
}
|
||||
|
||||
private void clearBit(int index) {
|
||||
this.bits &= ~(1L << index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(this.bits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof BitsCronField)) {
|
||||
return false;
|
||||
}
|
||||
BitsCronField other = (BitsCronField) o;
|
||||
return type() == other.type() && this.bits == other.bits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(type().toString());
|
||||
builder.append(" {");
|
||||
int i = nextSetBit(0);
|
||||
if (i != -1) {
|
||||
builder.append(i);
|
||||
i = nextSetBit(i + 1);
|
||||
while (i != -1) {
|
||||
builder.append(", ");
|
||||
builder.append(i);
|
||||
i = nextSetBit(i + 1);
|
||||
}
|
||||
}
|
||||
builder.append('}');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CompositeCronField extends CronField {
|
||||
|
||||
private final CronField[] fields;
|
||||
|
||||
private final String value;
|
||||
|
||||
private CompositeCronField(Type type, CronField[] fields, String value) {
|
||||
super(type);
|
||||
this.fields = fields;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static CronField compose(CronField[] fields, Type type, String value) {
|
||||
if (fields == null || fields.length < 1) {
|
||||
throw new RedkaleException("Fields must not be empty");
|
||||
}
|
||||
if (Utility.isBlank(value)) {
|
||||
throw new RedkaleException("Value must not be empty");
|
||||
}
|
||||
if (fields.length == 1) {
|
||||
return fields[0];
|
||||
} else {
|
||||
return new CompositeCronField(type, fields, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends Temporal & Comparable<? super T>> T nextOrSame(T temporal) {
|
||||
T result = null;
|
||||
for (CronField field : this.fields) {
|
||||
T candidate = field.nextOrSame(temporal);
|
||||
if (result == null
|
||||
|| candidate != null && candidate.compareTo(result) < 0) {
|
||||
result = candidate;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof CompositeCronField)) {
|
||||
return false;
|
||||
}
|
||||
CompositeCronField other = (CompositeCronField) o;
|
||||
return type() == other.type() && this.value.equals(other.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type() + " '" + this.value + "'";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ package org.redkale.test.convert;
|
||||
|
||||
import java.util.*;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.redkale.convert.ConvertFactory;
|
||||
import org.redkale.convert.json.*;
|
||||
|
||||
/**
|
||||
@@ -23,7 +24,7 @@ public class Json5Test {
|
||||
|
||||
@Test
|
||||
public void run1() throws Exception {
|
||||
JsonFactory factory = JsonFactory.root().tiny(true).nullable(true);
|
||||
JsonFactory factory = JsonFactory.root().features(ConvertFactory.FEATURE_TINY | ConvertFactory.FEATURE_NULLABLE);
|
||||
final JsonConvert convert = factory.getConvert();
|
||||
Json5Bean bean = new Json5Bean();
|
||||
bean.id = 60;
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.redkale.convert.ConvertFactory;
|
||||
import org.redkale.convert.json.*;
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,7 @@ public class JsonMainTest {
|
||||
|
||||
@Test
|
||||
public void run1() throws Throwable {
|
||||
JsonFactory factory = JsonFactory.root().tiny(true);
|
||||
JsonFactory factory = JsonFactory.root().features(ConvertFactory.FEATURE_TINY);
|
||||
final JsonConvert convert = JsonConvert.root();
|
||||
String json = "{\"access_token\":\"null\",\"priv\":null, vvv:nulla,\"priv2\":\"nulla\",\"expires_in\":7200, \"aa\":\"\"}";
|
||||
Map<String, String> map = convert.convertFrom(JsonConvert.TYPE_MAP_STRING_STRING, json);
|
||||
@@ -53,7 +54,7 @@ public class JsonMainTest {
|
||||
SimpleChildEntity entry = SimpleChildEntity.create();
|
||||
String json = convert.convertTo(SimpleEntity.class, entry);
|
||||
System.out.println("长度: " + json.length());
|
||||
JsonByteBufferWriter writer = new JsonByteBufferWriter(false, false, () -> ByteBuffer.allocate(1)) {
|
||||
JsonByteBufferWriter writer = new JsonByteBufferWriter(0, () -> ByteBuffer.allocate(1)) {
|
||||
};
|
||||
convert.convertTo(writer, SimpleEntity.class, entry);
|
||||
ByteBuffer[] buffers = writer.toBuffers();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package org.redkale.test.convert;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.redkale.convert.ConvertFactory;
|
||||
import org.redkale.convert.json.*;
|
||||
|
||||
/**
|
||||
@@ -24,17 +25,21 @@ public class TinyTest {
|
||||
TinyRecord record = new TinyRecord();
|
||||
record.id = 5;
|
||||
{
|
||||
JsonFactory factory = JsonFactory.create().tiny(true);
|
||||
JsonFactory factory = JsonFactory.create().features(ConvertFactory.FEATURE_TINY);
|
||||
JsonConvert convert = factory.getConvert();
|
||||
String json = "{\"id\":5}";
|
||||
if (!main) Assertions.assertEquals(json, convert.convertTo(record));
|
||||
if (!main) {
|
||||
Assertions.assertEquals(json, convert.convertTo(record));
|
||||
}
|
||||
System.out.println(convert.convertTo(record));
|
||||
}
|
||||
{
|
||||
JsonFactory factory = JsonFactory.create().tiny(false);
|
||||
JsonFactory factory = JsonFactory.create().features(0);
|
||||
JsonConvert convert = factory.getConvert();
|
||||
String json = "{\"id\":5,\"name\":\"\"}";
|
||||
if (!main) Assertions.assertEquals(json, convert.convertTo(record));
|
||||
if (!main) {
|
||||
Assertions.assertEquals(json, convert.convertTo(record));
|
||||
}
|
||||
System.out.println(convert.convertTo(record));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user