序列化和反序列化相关类

54 阅读3分钟

1.Avro生成类

(1) 已知类型

     // 1.创建avro序列化器
    private AvroSerializationSchema<DwtMoDspAdModel> adSchema = AvroSerializationSchema.forSpecific(DwtMoDspAdModel.class);
    // 2.在下面process中将处理后的数据进行序列化传递下去
    ctx.output(OUT_TAG_MO_DSP, adSchema.serialize(adModel));
----------------------------------------------------------------------------------------------------
    // 3.创建avro反序列化器
        private AvroDeserializationSchema<DwdEscClickCheat> escClickSchema = AvroDeserializationSchema.forSpecific(DwdEscClickCheat.class);
    // 4.在下面的process中先将byte数组反序列化成Avro类对象A  
    DwdEscClickCheat escClick = escClickSchema.deserialize(value.getMessage());
      DwtMvDspModel mvDspAvroObj = DwtMvDspModel.newBuilder().build();

(2) 不知道什么类型,但是知道全类名

下面案例是以反序列化为例,序列化与其相似,只需要创建avro序列化器,把deserialize改为serialize即可

    // 1.创建需要用到的Class和avro反序列化器
    private final Class<?> modelClass;
        private AvroDeserializationSchema<?> avroSchema;

      // 2.初始化Class和avro反序列化器
    this.modelClass = Class.forName(filterModel);
    // 先利用反射获取AvroDeserializationSchema类里面的静态方法forSpecific,然后利用forSpecific方法进行动态创建avro类对象,参数是全类名
         Method forSpecificMethod = AvroDeserializationSchema.class.getMethod("forSpecific", Class.class);
           this.avroSchema = (AvroCompatibleDeserializationSchema<?>) forSpecificMethod.invoke(null, modelClass);
    // 3.开始反序列化
     try {
        byte[] bytes = ((KafkaMsg) t).getMessage();
        Object convertData = avroSchema.deserialize(bytes);
          } catch (IOException e) {
        LOG.error("Failed to deserialize Avro data", e);
             return null;
          }

(3) avro类独有的获取对应名字的字段

    if (t instanceof GenericRecord) {
           GenericRecord avroRecord = (GenericRecord) t;
           return avroRecord.get(fieldName);
    }

2.Thrift生成类

(1) 已知类型

    // 序列化
    // 1.创建thrift类的对象
    UnitedEvent ue = new UnitedEvent();
    // 2. 创建 TSerializer 对象
           TSerializer tSerializer = new TSerializer();
    // 3.将指定thrift类对象序列化成二进制数组  
        byte[] serializedData = tSerializer.serialize(ue);
----------------------------------------------------------
    // 反序列化
    // 1.创建thrift类的对象
    UnitedEvent ue = new UnitedEvent();
    // 2.创建TDeserializer对象
        TDeserializer tDeserializer = new TDeserializer();
    // 3.将二进制数组反序列化成指定thrift类对象 
        tDeserializer.deserialize(ue, data);

(2) 不知道类型,只知道全类名

下面是反序列化案例,序列化只需要创建TSeriealizer对象,将deserialize改为serialize即可

    private final Class<?> modelClass;
    this.modelClass = Class.forName(filterModel);
    //使用.getDeclaredConstructor().newInstance()代替Class.newInstance()更安全、灵活
    Object thriftObject = modelClass.getDeclaredConstructor().newInstance();
    // 指定使用二进制协议,其实new TDeserializer()无参底层也是默认使用二进制协议
    TDeserializer deserializer = new TDeserializer(new TBinaryProtocol.Factory());
    deserializer.deserialize((TBase) thriftObject, bytes);
    Object convertData = thriftObject;

(3) Thrift类独有的获取Field

不建议这样用,因为要循环遍历map,不如反射Field

        TBase<?, ?> thiriftRecord = (TBase<?, ?>) t;
        // 获取thrift类的元数据map
        Map<?, FieldMetaData> metaDataMap = FieldMetaData.getStructMetaDataMap(thiriftRecord.getClass());
        // 遍历元数据,并根据元数据的fieldName去判断,然后return对应的Field的值
        for (Map.Entry<?, FieldMetaData> entry : metaDataMap.entrySet()) {
            FieldMetaData metaData = entry.getValue();
            if (metaData.fieldName.equals(fieldName)) {
                return thiriftRecord.getFieldValue((TFieldIdEnum) entry.getKey());
            }
        }

3.pojo类

(1) 已知类型

    // 利用JSON   
    Gson gson = new Gson();

    // 序列化
    User user = new User("John", 30);
    String json = gson.toJson(user);
    System.out.println("Serialized JSON: " + json);

    // 反序列化
    User deserializedUser = gson.fromJson(json, User.class);
    System.out.println("Deserialized User: " + deserializedUser)

(2) 不知道类型,只知道全类名

    // 方式1.利用反射和json    
    // 获取类对象
    Class<?> clazz = Class.forName(className);
    // 获取构造函数
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
    // 创建对象实例
    Object user = constructor.newInstance("Alice", 25);

    // 序列化
    String json = gson.toJson(user);
    System.out.println("Serialized JSON: " + json);

    // 反序列化
    Object deserializedUser = gson.fromJson(json, clazz);
    System.out.println("Deserialized object: " + deserializedUser);

    // 方式2
    private final ObjectMapper objectMapper = new ObjectMapper();
    // 反序列化
    Object convertData = objectMapper.readValue(bytes, modelClass);
    // 序列化
    File outputFile = new File("employee.json");
    objectMapper.writeValue(outputFile, modelClass);

4.JsonObject

(1) 已知类型

// 创建 Gson 对象
Gson gson = new Gson();

// 序列化
Employee employee = new Employee("Bob", 123);
String json = gson.toJson(employee);
System.out.println("Serialized JSON: " + json);

// 反序列化
Employee deserializedEmployee = gson.fromJson(json, Employee.class);

(2) 不知道类型,只知道全类名

    // 反序列化利用String     
    String jsonStr = new String(bytes);
    JSONObject convertData = new JSONObject(jsonStr);
    // 序列化利用String
    // 将 JSONObject 对象转换为 JSON 字符串
    String jsonStr = convertData .toString();
    // 将 JSON 字符串转换为字节数组,使用 UTF-8 编码
    return jsonStr.getBytes(StandardCharsets.UTF_8);
  • 类型匹配
    • invoke是要看MethodHandle 是get还是set,如果是get只传一个参数;如果是set需要传多个参数,第一个参数是Field,后面都是构造函数。千万注意WrongMethodTypeException类型不匹配问题。
    • 使用 invokeExact 时,要确保参数类型严格匹配,否则会抛出 WrongMethodTypeException
  • 异常处理
    • 调用 MethodHandle 可能会抛出 Throwable,因此要妥善处理异常,避免程序崩溃。

通过上述介绍,你可以更灵活地使用 MethodHandle 进行方法调用和操作,它为 Java 提供了更强大的动态性和灵活性,特别是在需要动态调用方法、组合方法或进行类型转换的场景中。根据实际需求,你可以结合 MethodHandle 的各种方法,如 asTypefilterArguments 等来实现复杂的动态调用逻辑。