datax的配置文件是json格式的,作为参数传递给datax.py运行。
python datax.py {YOUR_JOB.json}
datax将其抽象为Configuration类。
在Configuration的java doc中有这段描述:
* Configuration 存在两种较好地实现方式<br>
* 第一种是将JSON配置信息中所有的Key全部打平,用a.b.c的级联方式作为Map的Key,内部使用一个Map保存信息 <br>
* 第二种是将JSON的对象直接使用结构化树形结构保存<br>
* <p/>
* 目前使用的第二种实现方式,使用第一种的问题在于: <br>
* 1. 插入新对象,比较难处理,例如a.b.c="bazhen",此时如果需要插入a="bazhen",也即是根目录下第一层所有类型全部要废弃
* ,使用"bazhen"作为value,第一种方式使用字符串表示key,难以处理这类问题。 <br>
* 2. 返回树形结构,例如 a.b.c.d = "bazhen",如果返回"a"下的所有元素,实际上是一个Map,需要合并处理 <br>
* 3. 输出JSON,将上述对象转为JSON,要把上述Map的多级key转为树形结构,并输出为JSON <br>
有意思的是,Configuration类可以通过json的key路径来访问值:
* 根据用户提供的json path,寻址具体的对象。
* <p/>
* <br>
* <p/>
* NOTE: 目前仅支持Map以及List下标寻址, 例如:
* <p/>
* <br />
* <p/>
* 对于如下JSON
* <p/>
* {"a": {"b": {"c": [0,1,2,3]}}}
* <p/>
* config.get("") 返回整个Map <br>
* config.get("a") 返回a下属整个Map <br>
* config.get("a.b.c") 返回c对应的数组List <br>
* config.get("a.b.c[0]") 返回数字0
我们来看看是怎么做到的。
Configuration依赖了fastjson,将json配置文件存储在一个对象 root中:
private Object root = null;
......
private Configuration(final String json) {
try {
this.root = JSON.parse(json);
} catch (Exception e) {
throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR,
String.format("配置信息错误. 您提供的配置信息不是合法的JSON格式: %s . 请按照标准json格式提供配置信息. ", e.getMessage()));
}
}
我们可以通过get(path)输入一个路径来访问对应的值。例如a.b.c[0]
a.b.c[0]会被解析成 ["a", "b", "c", "[0]"]
的数组。
看下面的代码,each就是["a", "b", "c", "[0]"]
的项,遍历到a时,就从root取出a的值,直到遍历到“[0]”,target为一个List,则从一个列表中取值。
private Object findObject(final String path) {
boolean isRootQuery = StringUtils.isBlank(path);
if (isRootQuery) {
return this.root;
}
Object target = this.root;
for (final String each : split2List(path)) {
if (isPathMap(each)) {
target = findObjectInMap(target, each);
continue;
} else {
target = findObjectInList(target, each);
continue;
}
}
return target;
}
@SuppressWarnings("unchecked")
private Object findObjectInMap(final Object target, final 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<String, Object>) target).get(index);
if (null == result) {
throw new IllegalArgumentException(String.format(
"您提供的配置文件有误. 路径[%s]值为null,datax无法识别该配置. 请检查您的配置并作出修改.", index));
}
return result;
}
@SuppressWarnings({ "unchecked" })
private Object findObjectInList(final Object target, final 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<Object>) target).get(Integer.valueOf(index));
}
private boolean isPathMap(final String path) {
return StringUtils.isNotBlank(path) && !isPathList(path);
}
网友评论