All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wgzhao.datax.common.util.Configuration Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package com.wgzhao.datax.common.util;

import com.wgzhao.datax.common.exception.CommonErrorCode;
import com.wgzhao.datax.common.exception.DataXException;
import com.wgzhao.datax.common.spi.ErrorCode;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Configuration 提供多级JSON配置信息无损存储 
* 实例代码:
* 获取job的配置信息
* Configuration configuration = Configuration.from(new File("Config.json"));
* String jobContainerClass = * configuration.getString("core.container.job.class");
* 设置多级List
* configuration.set("job.reader.parameter.jdbcUrl", Arrays.asList(new String[] * {"jdbc", "jdbc"})); * 合并Configuration:
* configuration.merge(another); * Configuration 存在两种较好地实现方式
* 第一种是将JSON配置信息中所有的Key全部打平,用a.b.c的级联方式作为Map的Key,内部使用一个Map保存信息
* 第二种是将JSON的对象直接使用结构化树形结构保存
* 目前使用的第二种实现方式,使用第一种的问题在于:
* 1. 插入新对象,比较难处理,例如a.b.c="bazhen",此时如果需要插入a="bazhen",也即是根目录下第一层所有类型全部要废弃 * ,使用"bazhen"作为value,第一种方式使用字符串表示key,难以处理这类问题。
* 2. 返回树形结构,例如 a.b.c.d = "bazhen",如果返回"a"下的所有元素,实际上是一个Map,需要合并处理
* 3. 输出JSON,将上述对象转为JSON,要把上述Map的多级key转为树形结构,并输出为JSON
*/ public class Configuration { /** * 对于加密的keyPath,需要记录下来 * 为的是后面分布式情况下将该值加密后抛到DataXServer中 */ private Set secretKeyPathSet = new HashSet<>(); private Object root; private Configuration(String json) { try { this.root = JSON.parse(json); } catch (Exception e) { throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, String.format("配置信息错误. 您提供的配置信息不是合法的JSON格式: %s . 请按照标准json格式提供配置信息. ", e.getMessage())); } } /* * 初始化空白的Configuration */ public static Configuration newDefault() { return Configuration.from("{}"); } /* * 从JSON字符串加载Configuration */ public static Configuration from(String json) { json = StrUtil.replaceVariable(json); checkJSON(json); try { return new Configuration(json); } catch (Exception e) { throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, e); } } /* * 从包括json的File对象加载Configuration */ public static Configuration from(File file) { try { return Configuration.from(IOUtils .toString(new FileInputStream(file), StandardCharsets.UTF_8)); } catch (FileNotFoundException e) { throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, String.format("配置信息错误,您提供的配置文件[%s]不存在. 请检查您的配置文件.", file.getAbsolutePath())); } catch (IOException e) { throw DataXException.asDataXException( CommonErrorCode.CONFIG_ERROR, String.format("配置信息错误. 您提供配置文件[%s]读取失败,错误原因: %s. 请检查您的配置文件的权限设置.", file.getAbsolutePath(), e)); } } /* * 从包括json的InputStream对象加载Configuration */ public static Configuration from(InputStream is) { try { return Configuration.from(IOUtils.toString(is, StandardCharsets.UTF_8)); } catch (IOException e) { throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, String.format("请检查您的配置文件. 您提供的配置文件读取失败,错误原因: %s. 请检查您的配置文件的权限设置.", e)); } } /* * 从Map对象加载Configuration */ public static Configuration from(final Map object) { return Configuration.from(Configuration.toJSONString(object)); } /* * 从List对象加载Configuration */ public static Configuration from(final List object) { return Configuration.from(Configuration.toJSONString(object)); } private static void checkJSON(String json) { if (StringUtils.isBlank(json)) { throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, "配置信息错误. 因为您提供的配置信息不是合法的JSON格式, JSON不能为空白. 请按照标准json格式提供配置信息. "); } } private static String toJSONString(Object object) { return JSON.toJSONString(object); } public String getNecessaryValue(String key, ErrorCode errorCode) { String value = this.getString(key, null); if (StringUtils.isBlank(value)) { throw DataXException.asDataXException(errorCode, String.format("您提供配置文件有误,[%s]是必填参数,不允许为空或者留白 .", key)); } return value; } public String getUnnecessaryValue(String key, String defaultValue) { String value = this.getString(key, defaultValue); if (StringUtils.isBlank(value)) { value = defaultValue; } return value; } /** * 根据用户提供的json path,寻址具体的对象。 * * NOTE: 目前仅支持Map以及List下标寻址, 例如: * * 对于如下JSON *

* {"a": {"b": {"c": [0,1,2,3]}}} *

* config.get("") 返回整个Map
* config.get("a") 返回a下属整个Map
* config.get("a.b.c") 返回c对应的数组List
* config.get("a.b.c[0]") 返回数字0 * * @param path String 要查的json路径 * @return Java表示的JSON对象,如果path不存在或者对象不存在,均返回null。 */ public Object get(String path) { this.checkPath(path); try { return this.findObject(path); } catch (Exception e) { return null; } } /** * 用户指定部分path,获取Configuration的子集 * * @param path String json 路径 * @return Configuration 配置对象, 如果path获取的路径或者对象不存在,返回null */ public Configuration getConfiguration(String path) { Object object = this.get(path); if (null == object) { return null; } return Configuration.from(Configuration.toJSONString(object)); } /** * 根据用户提供的json path,寻址String对象 * * @param path String json 路径 * * @return String 对象,如果path不存在或者String不存在,返回null */ public String getString(String path) { Object string = this.get(path); if (null == string) { return null; } return String.valueOf(string); } /** * 根据用户提供的json path,寻址String对象,如果对象不存在,返回默认字符串 * * @param path String json 路径 * @param defaultValue String 如果path不存在,则返回该值 * * @return String对象,如果path不存在或者String不存在,返回默认字符串 */ public String getString(String path, String defaultValue) { String result = this.getString(path); if (null == result) { return defaultValue; } return result; } /** * 根据用户提供的json path,寻址Character对象 * * @param path String json 路径 * @return Character对象,如果path不存在或者Character不存在,返回null */ public Character getChar(String path) { String result = this.getString(path); if (null == result) { return null; } try { return CharUtils.toChar(result); } catch (Exception e) { throw DataXException.asDataXException( CommonErrorCode.CONFIG_ERROR, String.format("任务读取配置文件出错. 因为配置文件路径[%s] 值非法,期望是字符类型: %s. 请检查您的配置并作出修改.", path, e.getMessage())); } } /** * 根据用户提供的json path,寻址Boolean对象,如果对象不存在,返回默认Character对象 * * @param path String json 路径 * @param defaultValue String 如果path不存在,则返回该值 * * @return Character对象,如果path不存在或者Character不存在,返回默认Character对象 */ public Character getChar(String path, char defaultValue) { Character result = this.getChar(path); if (null == result) { return defaultValue; } return result; } /** * 根据用户提供的json path,寻址Boolean对象 * * @param path String json 路径 * * @return Boolean对象,如果path值非true,false ,将报错.特别注意:当 path 不存在时,会返回:null. */ public Boolean getBool(String path) { String result = this.getString(path); if (null == result) { return null; //NOSONAR } else if ("true".equalsIgnoreCase(result)) { return Boolean.TRUE; } else if ("false".equalsIgnoreCase(result)) { return Boolean.FALSE; } else { throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR, String.format("您提供的配置信息有误,因为从[%s]获取的值[%s]无法转换为bool类型. 请检查源表的配置并且做出相应的修改.", path, result)); } } /** * 根据用户提供的json path,寻址Boolean对象,如果对象不存在,返回默认Boolean对象 * * * @param path String json 路径 * @param defaultValue String 如果path不存在,则返回该值 * * @return Boolean对象,如果path不存在或者Boolean不存在,返回默认Boolean对象 */ public Boolean getBool(String path, boolean defaultValue) { Boolean result = this.getBool(path); if (null == result) { return defaultValue; } return result; } /** * 根据用户提供的json path,寻址Integer对象 * * @param path String json 路径 * * @return Integer对象,如果path不存在或者Integer不存在,返回null */ public Integer getInt(String path) { String result = this.getString(path); if (null == result) { return null; } try { return Integer.valueOf(result); } catch (Exception e) { throw DataXException.asDataXException( CommonErrorCode.CONFIG_ERROR, String.format("任务读取配置文件出错. 配置文件路径[%s] 值非法, 期望是整数类型: %s. 请检查您的配置并作出修改.", path, e.getMessage())); } } /** * 根据用户提供的json path,寻址Integer对象,如果对象不存在,返回默认Integer对象 * * @param path String json 路径 * @param defaultValue String 如果path不存在,则返回该值 * * @return Integer对象,如果path不存在或者Integer不存在,返回默认Integer对象 */ public Integer getInt(String path, int defaultValue) { Integer object = this.getInt(path); if (null == object) { return defaultValue; } return object; } /** * 根据用户提供的json path,寻址Long对象 * * @param path String json 路径 * * @return Long对象,如果path不存在或者Long不存在,返回null */ public Long getLong(String path) { String result = this.getString(path); if (StringUtils.isBlank(result)) { return null; } try { return Long.valueOf(result); } catch (Exception e) { throw DataXException.asDataXException( CommonErrorCode.CONFIG_ERROR, String.format("任务读取配置文件出错. 配置文件路径[%s] 值非法, 期望是整数类型: %s. 请检查您的配置并作出修改.", path, e.getMessage())); } } /** * 根据用户提供的json path,寻址Long对象,如果对象不存在,返回默认Long对象 * * @param path String json 路径 * @param defaultValue String 如果path不存在,则返回该值 * * @return Long对象,如果path不存在或者Integer不存在,返回默认Long对象 */ public Long getLong(String path, long defaultValue) { Long result = this.getLong(path); if (null == result) { return defaultValue; } return result; } /** * 根据用户提供的json path,寻址Double对象 * * @param path String json 路径 * * @return Double对象,如果path不存在或者Double不存在,返回null */ public Double getDouble(String path) { String result = this.getString(path); if (StringUtils.isBlank(result)) { return null; } try { return Double.valueOf(result); } catch (Exception e) { throw DataXException.asDataXException( CommonErrorCode.CONFIG_ERROR, String.format("任务读取配置文件出错. 配置文件路径[%s] 值非法, 期望是浮点类型: %s. 请检查您的配置并作出修改.", path, e.getMessage())); } } /** * 根据用户提供的json path,寻址Double对象,如果对象不存在,返回默认Double对象 * * @param path String json 路径 * @param defaultValue String 如果path不存在,则返回该值 * * @return Double对象,如果path不存在或者Double不存在,返回默认Double对象 */ public Double getDouble(String path, double defaultValue) { Double result = this.getDouble(path); if (null == result) { return defaultValue; } return result; } /** * 根据用户提供的json path,寻址List对象,如果对象不存在,返回null * * @param path String json 路径 * * @return 对象列表 */ @SuppressWarnings("unchecked") public List getList(String path) { return this.get(path, List.class); } /** * 根据用户提供的json path,寻址List对象,如果对象不存在,返回null * * @param path json 路径 * @param t 要转换的类型 * @param 类型 * @return 列表 */ @SuppressWarnings("unchecked") public List getList(String path, Class t) { List object = this.get(path, List.class); if (null == object) { return Collections.emptyList(); } List result = new ArrayList<>(); List origin = new ArrayList<>(); try { origin = object; } catch (ClassCastException e) { // .warn("{} 转为 List 时发生了异常,默认将此值添加到 List 中", String.valueOf(object)) origin.add(String.valueOf(object)); } for (Object each : origin) { result.add((T) each); } return result; } /** * 根据用户提供的json path,寻址List对象,如果对象不存在,返回默认List * * @param path json 路径 * @param defaultList 默认返回的值 * * @return 对象列表 */ public List getList(String path, List defaultList) { List object = this.getList(path); if (null == object) { return defaultList; } return object; } /** * 根据用户提供的json path,寻址List对象,如果对象不存在,返回默认List * * @param path String json 路径 * @param defaultList 默认返回的值 * @param t 要转换的类型 * @param 类型 * * @return 列表 */ public List getList(String path, List defaultList, Class t) { List list = this.getList(path, t); if (null == list) { return defaultList; } return list; } /** * 根据用户提供的json path,寻址包含Configuration的List,如果对象不存在,返回默认null * * @param path String json 路径 * * @return 列表 */ public List getListConfiguration(String path) { List lists = getList(path); if (lists == null) { return Collections.emptyList(); } List result = new ArrayList<>(); for (Object object : lists) { result.add(Configuration.from(Configuration.toJSONString(object))); } return result; } /** * 根据用户提供的json path,寻址Map对象,如果对象不存在,返回null * * @param path String json 路径 * * @return map 对象 */ @SuppressWarnings("unchecked") public Map getMap(String path) { return this.get(path, Map.class); } /** * 根据用户提供的json path,寻址Map对象,如果对象不存在,返回默认map * * @param path String json 路径 * @param defaultMap 默认返回值 * * @return map对象 */ public Map getMap(String path, Map defaultMap) { Map object = this.getMap(path); if (null == object) { return defaultMap; } return object; } /** * 根据用户提供的json path,寻址具体的对象,并转为用户提供的类型 * NOTE: 目前仅支持Map以及List下标寻址, 例如: * 对于如下JSON *

* {"a": {"b": {"c": [0,1,2,3]}}} *

* config.get("") 返回整个Map
* config.get("a") 返回a下属整个Map
* config.get("a.b.c") 返回c对应的数组List
* config.get("a.b.c[0]") 返回数字0 * * @param path String json 路径 * @param clazz Class 要转换的类型 * @param 类型 * * @return Java表示的JSON对象,如果转型失败,将抛出异常 */ @SuppressWarnings("unchecked") public T get(String path, Class clazz) { this.checkPath(path); return (T) this.get(path); } /** * 格式化Configuration输出 * * @return string */ public String beautify() { return JSON.toJSONString(this.getInternal(), SerializerFeature.PrettyFormat); } /** * 根据用户提供的json path,插入指定对象,并返回之前存在的对象(如果存在) * * 目前仅支持.以及数组下标寻址, 例如: *

* config.set("a.b.c[3]", object); *

* 对于插入对象,Configuration 不做任何限制,但是请务必保证该对象是简单对象,不要使用自定义对象,否则后续对于JSON序列化等情况会出现未定义行为。 * * @param path JSON path对象 * @param object 需要插入的对象 * * @return Java表示的JSON对象 */ public Object set(String path, Object object) { checkPath(path); Object result = this.get(path); setObject(path, extractConfiguration(object)); return result; } /** * 获取Configuration下所有叶子节点的key * 对于 *

* {"a": {"b": {"c": [0,1,2,3]}}, "x": "y"} *

* 下属的key包括: a.b.c[0],a.b.c[1],a.b.c[2],a.b.c[3],x * * @return set of string */ public Set getKeys() { Set collect = new HashSet<>(); this.getKeysRecursive(this.getInternal(), "", collect); return collect; } /** * 删除path对应的值,如果path不存在,将抛出异常。 * * @param path String json 路径 * * @return Object 返回查到的对象,若不存在则返回为空 */ public Object remove(String path) { Object result = this.get(path); if (null == result) { throw DataXException.asDataXException( CommonErrorCode.RUNTIME_ERROR, String.format("配置文件对应Key[%s]并不存在,该情况是代码编程错误. 请联系DataX团队的同学.", path)); } this.set(path, null); return result; } /** * 合并其他Configuration,并修改两者冲突的KV配置 * * @param another Configuration 合并加入的第三方Configuration * @param updateWhenConflict boolean 当合并双方出现KV冲突时候,选择更新当前KV,或者忽略该KV * * @return Configuration */ public Configuration merge(Configuration another, boolean updateWhenConflict) { Set keys = another.getKeys(); // 如果使用更新策略,凡是another存在的key,均需要更新 // 使用忽略策略,只有another Configuration存在但是当前Configuration不存在的key,才需要更新 keys.forEach(key -> { if (updateWhenConflict) { this.set(key, another.get(key)); return; } boolean isCurrentExists = this.get(key) != null; if (isCurrentExists) { return; } this.set(key, another.get(key)); }); return this; } @Override public String toString() { return this.toJSON(); } /** * 将Configuration作为JSON输出 * * @return String json string */ public String toJSON() { return Configuration.toJSONString(this.getInternal()); } /** * 拷贝当前Configuration,注意,这里使用了深拷贝,避免冲突 */ @Override public Configuration clone() { Configuration config = Configuration .from(Configuration.toJSONString(this.getInternal())); config.addSecretKeyPath(this.secretKeyPathSet); return config; } /** * 按照configuration要求格式的path * 比如: * a.b.c * a.b[2].c * * @param path 路径 * */ public void addSecretKeyPath(String path) { if (StringUtils.isNotBlank(path)) { this.secretKeyPathSet.add(path); } } public void addSecretKeyPath(Set pathSet) { if (pathSet != null) { this.secretKeyPathSet.addAll(pathSet); } } @SuppressWarnings("unchecked") void getKeysRecursive(Object current, String path, Set collect) { boolean isRegularElement = !(current instanceof Map || current instanceof List); if (isRegularElement) { collect.add(path); return; } boolean isMap = current instanceof Map; if (isMap) { Map mapping = ((Map) current); mapping.keySet().forEach(key -> { if (StringUtils.isBlank(path)) { getKeysRecursive(mapping.get(key), key.trim(), collect); } else { getKeysRecursive(mapping.get(key), path + "." + key.trim(), collect); } }); return; } List lists = (List) current; for (int i = 0; i < lists.size(); i++) { getKeysRecursive(lists.get(i), path + String.format("[%d]", i), collect); } } public Object getInternal() { return this.root; } private void setObject(String path, Object object) { Object newRoot = setObjectRecursive(this.root, split2List(path), 0, object); if (isSuitForRoot(newRoot)) { this.root = newRoot; return; } throw DataXException.asDataXException(CommonErrorCode.RUNTIME_ERROR, String.format("值[%s]无法适配您提供[%s], 该异常代表系统编程错误, 请联系DataX开发团队!", ToStringBuilder.reflectionToString(object), path)); } @SuppressWarnings("unchecked") private Object extractConfiguration(Object object) { if (object instanceof Configuration) { return extractFromConfiguration(object); } if (object instanceof List) { List result = new ArrayList<>(); for (Object each : (List) object) { result.add(extractFromConfiguration(each)); } return result; } if (object instanceof Map) { Map result = new HashMap<>(); for (String key : ((Map) object).keySet()) { result.put(key, extractFromConfiguration(((Map) object) .get(key))); } return result; } return object; } private Object extractFromConfiguration(Object object) { if (object instanceof Configuration) { return ((Configuration) object).getInternal(); } return object; } Object buildObject(List paths, Object object) { if (null == paths) { throw DataXException.asDataXException( CommonErrorCode.RUNTIME_ERROR, "Path不能为null,该异常代表系统编程错误, 请联系DataX开发团队 !"); } if (1 == paths.size() && StringUtils.isBlank(paths.get(0))) { return object; } Object child = object; for (int i = paths.size() - 1; i >= 0; i--) { String path = paths.get(i); if (isPathMap(path)) { Map mapping = new HashMap<>(); mapping.put(path, child); child = mapping; continue; } if (isPathList(path)) { List lists = new ArrayList<>( this.getIndex(path) + 1); expand(lists, this.getIndex(path) + 1); lists.set(this.getIndex(path), child); child = lists; continue; } throw DataXException.asDataXException( CommonErrorCode.RUNTIME_ERROR, String.format( "路径[%s]出现非法值类型[%s],该异常代表系统编程错误, 请联系DataX开发团队! .", StringUtils.join(paths, "."), path)); } return child; } @SuppressWarnings("unchecked") Object setObjectRecursive(Object current, List paths, int index, Object value) { // 如果是已经超出path,我们就返回value即可,作为最底层叶子节点 boolean isLastIndex = index == paths.size(); if (isLastIndex) { return value; } String path = paths.get(index).trim(); boolean isNeedMap = isPathMap(path); if (isNeedMap) { Map mapping; // 当前不是map,因此全部替换为map,并返回新建的map对象 boolean isCurrentMap = current instanceof Map; if (!isCurrentMap) { mapping = new HashMap<>(); mapping.put( path, buildObject(paths.subList(index + 1, paths.size()), value)); return mapping; } // 当前是map,但是没有对应的key,也就是我们需要新建对象插入该map,并返回该map mapping = ((Map) current); boolean hasSameKey = mapping.containsKey(path); if (!hasSameKey) { mapping.put( path, buildObject(paths.subList(index + 1, paths.size()), value)); return mapping; } // 当前是map,而且还竟然存在这个值,好吧,继续递归遍历 current = mapping.get(path); mapping.put(path, setObjectRecursive(current, paths, index + 1, value)); return mapping; } boolean isNeedList = isPathList(path); if (isNeedList) { List lists; int listIndexer = getIndex(path); // 当前是list,直接新建并返回即可 boolean isCurrentList = current instanceof List; if (!isCurrentList) { lists = expand(new ArrayList<>(), listIndexer + 1); lists.set( listIndexer, buildObject(paths.subList(index + 1, paths.size()), value)); return lists; } // 当前是list,但是对应的indexer是没有具体的值,也就是我们新建对象然后插入到该list,并返回该List lists = expand((List) current, listIndexer + 1); boolean hasSameIndex = lists.get(listIndexer) != null; if (!hasSameIndex) { lists.set( listIndexer, buildObject(paths.subList(index + 1, paths.size()), value)); return lists; } // 当前是list,并且存在对应的index,没有办法继续递归寻找 current = lists.get(listIndexer); lists.set(listIndexer, setObjectRecursive(current, paths, index + 1, value)); return lists; } throw DataXException.asDataXException(CommonErrorCode.RUNTIME_ERROR, "该异常代表系统编程错误, 请联系DataX开发团队 !"); } private Object findObject(String path) { boolean isRootQuery = StringUtils.isBlank(path); if (isRootQuery) { return this.root; } Object target = this.root; for (String each : split2List(path)) { if (isPathMap(each)) { target = findObjectInMap(target, each); } else { target = findObjectInList(target, each); } } return target; } @SuppressWarnings("unchecked") private Object findObjectInMap(Object target, String index) { boolean isMap = (target instanceof Map); if (!isMap) { throw new IllegalArgumentException(String.format( "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象,但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.", index, target.getClass().toString())); } Object result = ((Map) target).get(index); if (null == result) { throw new IllegalArgumentException(String.format( "您提供的配置文件有误. 路径[%s]值为null,datax无法识别该配置. 请检查您的配置并作出修改.", index)); } return result; } @SuppressWarnings({"unchecked"}) private Object findObjectInList(Object target, String each) { boolean isList = (target instanceof List); if (!isList) { throw new IllegalArgumentException(String.format( "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象,但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.", each, target.getClass().toString())); } String index = each.replace("[", "").replace("]", ""); if (!StringUtils.isNumeric(index)) { throw new IllegalArgumentException( String.format( "系统编程错误,列表下标必须为数字类型,但该节点发现实际类型是[%s] ,该异常代表系统编程错误, 请联系DataX开发团队 !", index)); } return ((List) target).get(Integer.parseInt(index)); } private List expand(List list, int size) { int expand = size - list.size(); while (expand-- > 0) { list.add(null); } return list; } private boolean isPathList(String path) { return path.contains("[") && path.contains("]"); } private boolean isPathMap(String path) { return StringUtils.isNotBlank(path) && !isPathList(path); } private int getIndex(String index) { return Integer.parseInt(index.replace("[", "").replace("]", "")); } private boolean isSuitForRoot(Object object) { return (object instanceof List || object instanceof Map); } private String split(String path) { return StringUtils.replace(path, "[", ".["); } private List split2List(String path) { return Arrays.asList(StringUtils.split(split(path), ".")); } private void checkPath(String path) { if (null == path) { throw new IllegalArgumentException( "系统编程错误, 该异常代表系统编程错误, 请联系DataX开发团队!."); } for (String each : StringUtils.split(".")) { if (StringUtils.isBlank(each)) { throw new IllegalArgumentException(String.format( "系统编程错误, 路径[%s]不合法, 路径层次之间不能出现空白字符 .", path)); } } } public Set getSecretKeyPathSet() { return secretKeyPathSet; } public void setSecretKeyPathSet(Set keyPathSet) { if (keyPathSet != null) { this.secretKeyPathSet = keyPathSet; } } }