Skip to content

[BUG] 2.0.61版本、jdk8环境下序列化报错 #7650

@1160068538

Description

@1160068538

问题描述

1、使用开源的datax进行数据迁移,将依赖的fastjson升级到2.0.61,执行任务时发生报错
2、fastjson调整为2.0.60,功能正常

环境信息

  • OS信息: [e.g.:windows11]
  • JDK信息: [e.g.:Openjdk 1.8.0_312]
  • 版本信息:[e.g.:Fastjson2 2.0.61]

相关日志输出

java.lang.RuntimeException: Failed to create lambda for method: public
java.util.HashSet com.alibaba.datax.common.util.Configuration.getSecretKeyPathSet()
atcom.alibaba.fastjson2.introspect.PropertyAccessorFactoryLambda.getObject(PropertyAccessorFactoryLambda.java:513)
at com.alibaba.fastjson2.introspect.PropertyAccessorFactoryLambda.create(PropertyAccessorFactoryLambda.java:310)
at com.alibaba.fastjson2.introspect.PropertyAccessorFactory.create(PropertyAccessorFactory.java:2806)
at com.alibaba.fastjson2.introspect.PropertyAccessorFactory.create(PropertyAccessorFactory.java:2791)
at com.alibaba.fastjson2.writer.FieldWriter.createPropertyAccessor(FieldWriter.java:222)
at com.alibaba.fastjson2.writer.FieldWriter.(FieldWriter.java:194)
at com.alibaba.fastjson2.writer.FieldWriterObject.(FieldWriterObject.java:51)
at com.alibaba.fastjson2.writer.ObjectWriterCreator.createFieldWriter(ObjectWriterCreator.java:1449)
at com.alibaba.fastjson2.writer.ObjectWriterCreatorASM.lambda$createObjectWriter$1(ObjectWriterCreatorASM.java:338)
at com.alibaba.fastjson2.util.BeanUtils.getters(BeanUtils.java:1152)
at com.alibaba.fastjson2.writer.ObjectWriterCreatorASM.createObjectWriter(ObjectWriterCreatorASM.java:244)
at com.alibaba.fastjson2.writer.ObjectWriterProvider.getObjectWriterInternal(ObjectWriterProvider.java:720)
at com.alibaba.fastjson2.writer.ObjectWriterProvider.getObjectWriter(ObjectWriterProvider.java:582)
at com.alibaba.fastjson2.JSONWriter$Context.getObjectWriter(JSONWriter.java:3499)
at com.alibaba.fastjson2.writer.ObjectWriterImplList.write(ObjectWriterImplList.java:348)
at com.alibaba.fastjson2.JSON.toJSONString(JSON.java:3233)
at com.alibaba.datax.core.taskgroup.TaskGroupContainer.start(TaskGroupContainer.java:127)
at com.alibaba.datax.core.Engine.start(Engine.java:86)
at com.alibaba.datax.core.Engine.entry(Engine.java:168)

附加信息

package com.alibaba.datax.common.util;

import com.alibaba.datax.common.exception.CommonErrorCode;
import com.alibaba.datax.common.exception.DataXException;
import com.alibaba.datax.common.spi.ErrorCode;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
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.;
import java.util.
;

/**

  • 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,难以处理这类问题。

    1. 返回树形结构,例如 a.b.c.d = "bazhen",如果返回"a"下的所有元素,实际上是一个Map,需要合并处理
    1. 输出JSON,将上述对象转为JSON,要把上述Map的多级key转为树形结构,并输出为JSON

      */
      public class Configuration {

    /**

    • 对于加密的keyPath,需要记录下来
    • 为的是后面分布式情况下将该值加密后抛到DataXServer中
      */
      private Set secretKeyPathSet =
      new HashSet();

    private Object root = null;

    /**

    • 初始化空白的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)));
      } 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));
      } catch (IOException e) {
      throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR,
      String.format("请检查您的配置文件. 您提供的配置文件读取失败,错误原因: %s. 请检查您的配置文件的权限设置.", e));
      }
      }

    /**

    • 从Map对象加载Configuration
      */
      public static Configuration from(final Map<String, Object> object) {
      return Configuration.from(Configuration.toJSONString(object));
      }

    /**

    • 从List对象加载Configuration
      */
      public static Configuration from(final List object) {
      return Configuration.from(Configuration.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,ErrorCode errorCode) {
      String value = this.getString(key, defaultValue);
      if (StringUtils.isBlank(value)) {
      value = defaultValue;
      }
      return value;
      }

      public Boolean getNecessaryBool(String key, ErrorCode errorCode) {
      Boolean value = this.getBool(key);
      if (value == null) {
      throw DataXException.asDataXException(errorCode,
      String.format("您提供配置文件有误,[%s]是必填参数,不允许为空或者留白 .", key));
      }

       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
      • @return Java表示的JSON对象,如果path不存在或者对象不存在,均返回null。
        */
        public Object get(final String path) {
        this.checkPath(path);
        try {
        return this.findObject(path);
        } catch (Exception e) {
        return null;
        }
        }

      /**

      • 用户指定部分path,获取Configuration的子集


      • 如果path获取的路径或者对象不存在,返回null
        */
        public Configuration getConfiguration(final String path) {
        Object object = this.get(path);
        if (null == object) {
        return null;
        }

        return Configuration.from(Configuration.toJSONString(object));
        }

      /**

      • 根据用户提供的json path,寻址String对象
      • @return String对象,如果path不存在或者String不存在,返回null
        */
        public String getString(final String path) {
        Object string = this.get(path);
        if (null == string) {
        return null;
        }
        return String.valueOf(string);
        }

      /**

      • 根据用户提供的json path,寻址String对象,如果对象不存在,返回默认字符串

      • @return String对象,如果path不存在或者String不存在,返回默认字符串
        */
        public String getString(final String path, final String defaultValue) {
        String result = this.getString(path);

        if (null == result) {
        return defaultValue;
        }

        return result;
        }

      /**

      • 根据用户提供的json path,寻址Character对象

      • @return Character对象,如果path不存在或者Character不存在,返回null
        */
        public Character getChar(final 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对象
      • @return Character对象,如果path不存在或者Character不存在,返回默认Character对象
        */
        public Character getChar(final String path, char defaultValue) {
        Character result = this.getChar(path);
        if (null == result) {
        return defaultValue;
        }
        return result;
        }

      /**

      • 根据用户提供的json path,寻址Boolean对象

      • @return Boolean对象,如果path值非true,false ,将报错.特别注意:当 path 不存在时,会返回:null.
        */
        public Boolean getBool(final String path) {
        String result = this.getString(path);

        if (null == result) {
        return null;
        } 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对象
      • @return Boolean对象,如果path不存在或者Boolean不存在,返回默认Boolean对象
        */
        public Boolean getBool(final String path, boolean defaultValue) {
        Boolean result = this.getBool(path);
        if (null == result) {
        return defaultValue;
        }
        return result;
        }

      /**

      • 根据用户提供的json path,寻址Integer对象

      • @return Integer对象,如果path不存在或者Integer不存在,返回null
        */
        public Integer getInt(final 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对象
      • @return Integer对象,如果path不存在或者Integer不存在,返回默认Integer对象
        */
        public Integer getInt(final String path, int defaultValue) {
        Integer object = this.getInt(path);
        if (null == object) {
        return defaultValue;
        }
        return object;
        }

      /**

      • 根据用户提供的json path,寻址Long对象

      • @return Long对象,如果path不存在或者Long不存在,返回null
        */
        public Long getLong(final 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对象
      • @return Long对象,如果path不存在或者Integer不存在,返回默认Long对象
        */
        public Long getLong(final String path, long defaultValue) {
        Long result = this.getLong(path);
        if (null == result) {
        return defaultValue;
        }
        return result;
        }

      /**

      • 根据用户提供的json path,寻址Double对象

      • @return Double对象,如果path不存在或者Double不存在,返回null
        */
        public Double getDouble(final 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对象
      • @return Double对象,如果path不存在或者Double不存在,返回默认Double对象
        */
        public Double getDouble(final String path, double defaultValue) {
        Double result = this.getDouble(path);
        if (null == result) {
        return defaultValue;
        }
        return result;
        }

      /**

      • 根据用户提供的json path,寻址List对象,如果对象不存在,返回null
        */
        @SuppressWarnings("unchecked")
        public List getList(final String path) {
        List list = this.get(path, List.class);
        if (null == list) {
        return null;
        }
        return list;
        }

        public List getListWithJson(final String path, Class t) {
        Object object = this.get(path, List.class);
        if (null == object) {
        return null;
        }

         return JSON.parseArray(JSON.toJSONString(object),t);
        

        }

        /**

        • 根据用户提供的json path,寻址List对象,如果对象不存在,返回null
          */
          @SuppressWarnings("unchecked")
          public List getList(final String path, Class t) {
          Object object = this.get(path, List.class);
          if (null == object) {
          return null;
          }

          List result = new ArrayList();

          List origin = (List) object;
          for (final Object each : origin) {
          result.add((T) each);
          }

          return result;
          }

          /**

          • 根据用户提供的json path,寻址List对象,如果对象不存在,返回默认List
            */
            @SuppressWarnings("unchecked")
            public List getList(final String path,
            final List defaultList) {
            Object object = this.getList(path);
            if (null == object) {
            return defaultList;
            }
            return (List) object;
            }

            /**

            • 根据用户提供的json path,寻址List对象,如果对象不存在,返回默认List
              */
              public List getList(final String path, final List defaultList,
              Class t) {
              List list = this.getList(path, t);
              if (null == list) {
              return defaultList;
              }
              return list;
              }

            /**

            • 根据用户提供的json path,寻址包含Configuration的List,如果对象不存在,返回默认null
              */
              public List getListConfiguration(final String path) {
              List lists = getList(path);
              if (lists == null) {
              return null;
              }

              List result = new ArrayList();
              for (final Object object : lists) {
              result.add(Configuration.from(Configuration.toJSONString(object)));
              }
              return result;
              }

              /**

              • 根据用户提供的json path,寻址Map对象,如果对象不存在,返回null
                */
                @SuppressWarnings("unchecked")
                public Map<String, Object> getMap(final String path) {
                Map<String, Object> result = this.get(path, Map.class);
                if (null == result) {
                return null;
                }
                return result;
                }

              /**

              • 根据用户提供的json path,寻址Map对象,如果对象不存在,返回null;
                */
                @SuppressWarnings("unchecked")
                public Map<String, T> getMap(final String path, Class t) {
                Map<String, Object> map = this.get(path, Map.class);
                if (null == map) {
                return null;
                }

                Map<String, T> result = new HashMap<String, T>();
                for (final String key : map.keySet()) {
                result.put(key, (T) map.get(key));
                }

                return result;
                }

              /**

              • 根据用户提供的json path,寻址Map对象,如果对象不存在,返回默认map
                */
                @SuppressWarnings("unchecked")
                public Map<String, Object> getMap(final String path,
                final Map<String, Object> defaultMap) {
                Object object = this.getMap(path);
                if (null == object) {
                return defaultMap;
                }
                return (Map<String, Object>) object;
                }

              /**

              • 根据用户提供的json path,寻址Map对象,如果对象不存在,返回默认map
                */
                public Map<String, T> getMap(final String path,
                final Map<String, T> defaultMap, Class t) {
                Map<String, T> result = getMap(path, t);
                if (null == result) {
                return defaultMap;
                }
                return result;
                }

              /**

              • 根据用户提供的json path,寻址包含Configuration的Map,如果对象不存在,返回默认null
                */
                @SuppressWarnings("unchecked")
                public Map<String, Configuration> getMapConfiguration(final String path) {
                Map<String, Object> map = this.get(path, Map.class);
                if (null == map) {
                return null;
                }

                Map<String, Configuration> result = new HashMap<String, Configuration>();
                for (final String key : map.keySet()) {
                result.put(key, Configuration.from(Configuration.toJSONString(map
                .get(key))));
                }

                return result;
                }

              /**

              • 根据用户提供的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
              • @return Java表示的JSON对象,如果转型失败,将抛出异常
                */
                @SuppressWarnings("unchecked")
                public T get(final String path, Class clazz) {
                this.checkPath(path);
                return (T) this.get(path);
                }

              /**

              • 格式化Configuration输出
                */
                public String beautify() {
                return JSON.toJSONString(this.getInternal(),
                JSONWriter.Feature.PrettyFormat);
                }

              /**

              • 根据用户提供的json path,插入指定对象,并返回之前存在的对象(如果存在)


              • 目前仅支持.以及数组下标寻址, 例如:


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


              • 对于插入对象,Configuration不做任何限制,但是请务必保证该对象是简单对象(包括Map<String,

              • Object>、List),不要使用自定义对象,否则后续对于JSON序列化等情况会出现未定义行为。

              • @param path

              •        JSON path对象
                
              • @param object

              •        需要插入的对象
                
              • @return Java表示的JSON对象
                */
                public Object set(final String path, final 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
                  */
                  public Set getKeys() {
                  Set collect = new HashSet();
                  this.getKeysRecursive(this.getInternal(), "", collect);
                  return collect;
                  }

                /**

                • 删除path对应的值,如果path不存在,将抛出异常。
                  */
                  public Object remove(final String path) {
                  final 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
                  
                • @param updateWhenConflict

                •        当合并双方出现KV冲突时候,选择更新当前KV,或者忽略该KV
                  
                • @return 返回合并后对象
                  */
                  public Configuration merge(final Configuration another,
                  boolean updateWhenConflict) {
                  Set keys = another.getKeys();

                  for (final String key : keys) {
                  // 如果使用更新策略,凡是another存在的key,均需要更新
                  if (updateWhenConflict) {
                  this.set(key, another.get(key));
                  continue;
                  }

                   // 使用忽略策略,只有another Configuration存在但是当前Configuration不存在的key,才需要更新
                   boolean isCurrentExists = this.get(key) != null;
                   if (isCurrentExists) {
                   	continue;
                   }
                  
                   this.set(key, another.get(key));
                  

                  }
                  return this;
                  }

                @OverRide
                public String toString() {
                return this.toJSON();
                }

                /**

                • 将Configuration作为JSON输出
                  */
                  public String toJSON() {
                  return Configuration.toJSONString(this.getInternal());
                  }

                /**

                • 拷贝当前Configuration,注意,这里使用了深拷贝,避免冲突
                  */
                  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);
                }
                }

                public void setSecretKeyPathSet(Set keyPathSet) {
                if(keyPathSet != null) {
                this.secretKeyPathSet = keyPathSet;
                }
                }

                public boolean isSecretPath(String path) {
                return this.secretKeyPathSet.contains(path);
                }

                @SuppressWarnings("unchecked")
                void getKeysRecursive(final 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<String, Object> mapping = ((Map<String, Object>) current);
                 	for (final String key : mapping.keySet()) {
                 		if (StringUtils.isBlank(path)) {
                 			getKeysRecursive(mapping.get(key), key.trim(), collect);
                 		} else {
                 			getKeysRecursive(mapping.get(key), path + "." + key.trim(),
                 					collect);
                 		}
                 	}
                 	return;
                 }
                
                 boolean isList = current instanceof List;
                 if (isList) {
                 	List<Object> lists = (List<Object>) current;
                 	for (int i = 0; i < lists.size(); i++) {
                 		getKeysRecursive(lists.get(i), path + String.format("[%d]", i),
                 				collect);
                 	}
                 	return;
                 }
                
                 return;
                

                }

                public Object getInternal() {
                return this.root;
                }

                private void setObject(final String path, final 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(final Object object) {
                if (object instanceof Configuration) {
                return extractFromConfiguration(object);
                }

                 if (object instanceof List) {
                 	List<Object> result = new ArrayList<Object>();
                 	for (final Object each : (List<Object>) object) {
                 		result.add(extractFromConfiguration(each));
                 	}
                 	return result;
                 }
                
                 if (object instanceof Map) {
                 	Map<String, Object> result = new HashMap<String, Object>();
                 	for (final String key : ((Map<String, Object>) object).keySet()) {
                 		result.put(key,
                 				extractFromConfiguration(((Map<String, Object>) object)
                 						.get(key)));
                 	}
                 	return result;
                 }
                
                 return object;
                

                }

                private Object extractFromConfiguration(final Object object) {
                if (object instanceof Configuration) {
                return ((Configuration) object).getInternal();
                }

                 return object;
                

                }

                Object buildObject(final List paths, final 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<String, Object> mapping = new HashMap<String, Object>();
                 		mapping.put(path, child);
                 		child = mapping;
                 		continue;
                 	}
                
                 	if (isPathList(path)) {
                 		List<Object> lists = new ArrayList<Object>(
                 				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, final List paths,
                int index, final 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<String, Object> mapping;
                
                 	// 当前不是map,因此全部替换为map,并返回新建的map对象
                 	boolean isCurrentMap = current instanceof Map;
                 	if (!isCurrentMap) {
                 		mapping = new HashMap<String, Object>();
                 		mapping.put(
                 				path,
                 				buildObject(paths.subList(index + 1, paths.size()),
                 						value));
                 		return mapping;
                 	}
                
                 	// 当前是map,但是没有对应的key,也就是我们需要新建对象插入该map,并返回该map
                 	mapping = ((Map<String, Object>) 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<Object> lists;
                 	int listIndexer = getIndex(path);
                
                 	// 当前是list,直接新建并返回即可
                 	boolean isCurrentList = current instanceof List;
                 	if (!isCurrentList) {
                 		lists = expand(new ArrayList<Object>(), listIndexer + 1);
                 		lists.set(
                 				listIndexer,
                 				buildObject(paths.subList(index + 1, paths.size()),
                 						value));
                 		return lists;
                 	}
                
                 	// 当前是list,但是对应的indexer是没有具体的值,也就是我们新建对象然后插入到该list,并返回该List
                 	lists = (List<Object>) current;
                 	lists = expand(lists, 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(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 List expand(List list, int size) {
                int expand = size - list.size();
                while (expand-- > 0) {
                list.add(null);
                }
                return list;
                }

                private boolean isPathList(final String path) {
                return path.contains("[") && path.contains("]");
                }

                private boolean isPathMap(final String path) {
                return StringUtils.isNotBlank(path) && !isPathList(path);
                }

                private int getIndex(final String index) {
                return Integer.valueOf(index.replace("[", "").replace("]", ""));
                }

                private boolean isSuitForRoot(final Object object) {
                if (null != object && (object instanceof List || object instanceof Map)) {
                return true;
                }

                 return false;
                

                }

                private String split(final String path) {
                return StringUtils.replace(path, "[", ".[");
                }

                private List split2List(final String path) {
                return Arrays.asList(StringUtils.split(split(path), "."));
                }

                private void checkPath(final String path) {
                if (null == path) {
                throw new IllegalArgumentException(
                "系统编程错误, 该异常代表系统编程错误, 请联系DataX开发团队!.");
                }

                 for (final String each : StringUtils.split(".")) {
                 	if (StringUtils.isBlank(each)) {
                 		throw new IllegalArgumentException(String.format(
                 				"系统编程错误, 路径[%s]不合法, 路径层次之间不能出现空白字符 .", path));
                 	}
                 }
                

                }

                @SuppressWarnings("unused")
                private String toJSONPath(final String path) {
                return (StringUtils.isBlank(path) ? "$" : "$." + path).replace("$.[",
                "$[");
                }

                private static void checkJSON(final String json) {
                if (StringUtils.isBlank(json)) {
                throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR,
                "配置信息错误. 因为您提供的配置信息不是合法的JSON格式, JSON不能为空白. 请按照标准json格式提供配置信息. ");
                }
                }

                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()));
                }
                }

                private static String toJSONString(final Object object) {
                return JSON.toJSONString(object);
                }

                public Set getSecretKeyPathSet() {
                return secretKeyPathSet;
                }
                }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions