Solon v4.0.4

snack4 - Options (选项)主要接口参考

</> markdown
2026年8月3日 下午3:10:39
public final class Options {
    //默认类型的key
    public static final String DEF_TYPE_PROPERTY_NAME = "@type";
    //默认时区
    public static final ZoneId DEF_ZONE = ZoneId.systemDefault();
    public static final TimeZone DEF_TIME_ZONE = TimeZone.getDefault();
    //默认偏移时区
    public static final ZoneOffset DEF_OFFSET = OffsetDateTime.now().getOffset();
    //默认地区
    public static final Locale DEF_LOCALE = Locale.getDefault();
    //默认时间格式器
    public static final String DEF_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    //默认特性
    public static final int DEF_FEATURES = 0;

    //默认选项(私有)
    public static final Options DEF_OPTIONS = new Options(true);
    public static final String DEF_UNSUPPORTED_HINT = "Read-only mode does not support modification.";

    //编码仓库
    private final CodecLib codecLib = CodecLib.newInstance();
    //特性开关(使用位掩码存储)
    private long featuresValue = DEF_FEATURES;
    //时间格式
    private String dateFormat = DEF_DATETIME_FORMAT;
    //书写缩进
    private String writeIndent = "  ";
    //类型属性名
    private String typePropertyName = DEF_TYPE_PROPERTY_NAME;
    //类加载器
    private ClassLoader classLoader;
    //地区
    private Locale locale = DEF_LOCALE;
    //时区
    private ZoneId zoneId = DEF_ZONE;
    private TimeZone timeZone = DEF_TIME_ZONE;

    private Supplier<Map> mapFactory = LinkedHashMap::new;
    private Supplier<List> listFactory = ArrayList::new;

    //JSON 嵌套深度上限
    private int maxNestingDepth = 1000;

    private boolean readonly;

    private Options(boolean readonly) {
        this.readonly = readonly;
    }

    /**
     * 转为只读
     */
    public Options readonly() {
        this.readonly = true;
        return this;
    }

    /**
     * 克隆一个新的选项(非只读)
     */
    public Options copy() {
        Options tmp = new Options(false);

        // 复制基础属性
        tmp.featuresValue = this.featuresValue;
        tmp.dateFormat = this.dateFormat;
        tmp.writeIndent = this.writeIndent;
        tmp.typePropertyName = this.typePropertyName;
        tmp.classLoader = this.classLoader;
        tmp.locale = this.locale;
        tmp.zoneId = this.zoneId;
        tmp.timeZone = this.timeZone;
        tmp.mapFactory = this.mapFactory;
        tmp.listFactory = this.listFactory;
        tmp.maxNestingDepth = this.maxNestingDepth;

        // 将旧 options 的特有编解码器填充到新 options 的 codecLib 中
        tmp.codecLib.fill(this.codecLib);

        return tmp;
    }

    /**
     * 用于链式构建
     */
    public Options then(Consumer<Options> consumer) {
        consumer.accept(this);
        return this;
    }

    /**
     * 加载类
     */
    public Class<?> loadClass(String className) throws SnackException {
        return loadClass(className, true);
    }

    /**
     * 加载类(throwOnError=false 时,找不到类返回 null)
     */
    public Class<?> loadClass(String className, boolean throwOnError) {
        try {
            ClassLoader loader = classLoader;
            if (loader == null) {
                loader = Thread.currentThread().getContextClassLoader();
            }

            if (loader != null) {
                // 统一不触发静态初始化,行为一致
                return Class.forName(className, false, loader);
            } else {
                return Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            if (throwOnError) {
                throw new SnackException("Failed to load class: " + className, e);
            } else {
                return null;
            }
        }
    }

    /**
     * 是否启用指定特性
     */
    public boolean hasFeature(Feature feature) {
        return Feature.hasFeature(this.featuresValue, feature);
    }

    public long getFeatures() {
        return featuresValue;
    }

    public Locale getLocale() {
        return locale;
    }

    public ZoneId getZoneId() {
        return zoneId;
    }

    /**
     * @deprecated 4.0 请使用 {@link #getZoneId()}
     */
    @Deprecated
    public TimeZone getTimeZone() {
        return timeZone;
    }

    /**
     * 获取日期格式
     */
    public String getDateFormat() {
        return dateFormat;
    }

    public String getTypePropertyName() {
        return typePropertyName;
    }

    /**
     * 获取解码器
     */
    public ObjectDecoder<?> getDecoder(Class<?> clazz) {
        return codecLib.getDecoder(clazz);
    }

    /**
     * 获取编码器
     */
    public ObjectEncoder<?> getEncoder(Object value) {
        return codecLib.getEncoder(value);
    }

    /**
     * 获取创建器
     */
    public ObjectCreator<?> getCreator(Class<?> clazz) {
        return codecLib.getCreator(clazz);
    }

    /**
     * 获取缩进字符串
     */
    public String getWriteIndent() {
        return writeIndent;
    }

    /**
     * 获取 JSON 嵌套深度上限
     */
    public int getMaxNestingDepth() {
        return maxNestingDepth;
    }

    public <T> Map<String, T> createMap() {
        return mapFactory.get();
    }

    public <T> List<T> createList() {
        return listFactory.get();
    }

    /// /////////////

    /**
     * 设置 JSON 嵌套深度上限
     */
    public Options maxNestingDepth(int maxNestingDepth) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.maxNestingDepth = maxNestingDepth;
        return this;
    }

    /**
     * 设置日期格式
     */
    public Options dateFormat(String format) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.dateFormat = format;
        return this;
    }

    /**
     * 设置地区
     */
    public Options locale(Locale locale) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.locale = locale;
        return this;
    }

    /**
     * 设置时区
     */
    public Options timeZone(TimeZone timeZone) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.zoneId = timeZone.toZoneId();
        this.timeZone = timeZone;
        return this;
    }

    /**
     * 设置时区
     */
    public Options timeZone(ZoneId zoneId) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.zoneId = zoneId;
        this.timeZone = TimeZone.getTimeZone(zoneId);
        return this;
    }

    /**
     * 设置缩进字符串
     */
    public Options writeIndent(String indent) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.writeIndent = indent;
        return this;
    }

    /**
     * 设置类加载器
     */
    public Options classLoader(ClassLoader classLoader) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.classLoader = classLoader;
        return this;
    }

    /**
     * 添加特性
     */
    public Options addFeatures(Feature... features) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.featuresValue = Feature.addFeatures(this.featuresValue, features);
        return this;
    }

    public Options setFeatures(Feature... features) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.featuresValue = Feature.addFeatures(0L, features);
        return this;
    }

    /**
     * 移除特性
     */
    public Options removeFeatures(Feature... features) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.featuresValue = Feature.removeFeatures(this.featuresValue, features);
        return this;
    }

    /**
     * 注册自定义解码器
     */
    public <T> Options addDecoder(Class<T> type, ObjectDecoder<T> decoder) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        codecLib.addDecoder(type, decoder);
        return this;
    }

    /**
     * 注册自定义解码器
     */
    public <T> Options addDecoder(ObjectPatternDecoder<T> decoder) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        codecLib.addDecoder(decoder);
        return this;
    }

    /**
     * 注册自定义编码器
     */
    public <T> Options addEncoder(Class<T> type, ObjectEncoder<T> encoder) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        codecLib.addEncoder(type, encoder);
        return this;
    }

    /**
     * 注册自定义编码器
     */
    public <T> Options addEncoder(ObjectPatternEncoder<T> encoder) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        codecLib.addEncoder(encoder);
        return this;
    }

    /**
     * 注册自定义创建器
     */
    public <T> Options addCreator(Class<T> type, ObjectCreator<T> creator) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        codecLib.addCreator(type, creator);
        return this;
    }

    /**
     * 注册自定义创建器
     */
    public <T> Options addCreator(ObjectPatternCreator<T> creator) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        codecLib.addCreator(creator);
        return this;
    }

    //////////////////
    // 类型安全检测(双层配置:全局 + 实例)
    //////////////////

    /**
     * 注册自定义检测器(类型安全检测器)
     */
    public Options addChecker(TypeChecker checker) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        if (checker != null) {
            codecLib.addChecker(checker);
        }
        return this;
    }

    /**
     * 判断类名是否应被拦截(供解码器在动态类加载前调用)
     *
     * @param className 完整类名
     * @return true 表示拦截(拒绝加载),false 表示放行
     */
    public boolean isTypeBlocked(String className) {
        // 协议注入防护(含 ":" 或 "!" 的类名一律拒绝,不可关闭)
        if (className == null || className.contains(":") || className.contains("!")) {
            return true;
        }

        return codecLib.isTypeBlocked(className);
    }

    public Options mapFactory(Supplier<Map> mapFactory) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.mapFactory = mapFactory;
        return this;
    }

    public Options listFactory(Supplier<List> listFactory) {
        if (readonly) {
            throw new UnsupportedOperationException(DEF_UNSUPPORTED_HINT);
        }

        this.listFactory = listFactory;
        return this;
    }

    public static Options of(Feature... features) {
        Options tmp = new Options(false);
        for (Feature f : features) {
            tmp.addFeatures(f);
        }
        return tmp;
    }
}