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。
- invoke是要看
- 异常处理:
- 调用
MethodHandle可能会抛出Throwable,因此要妥善处理异常,避免程序崩溃。
- 调用
通过上述介绍,你可以更灵活地使用 MethodHandle 进行方法调用和操作,它为 Java 提供了更强大的动态性和灵活性,特别是在需要动态调用方法、组合方法或进行类型转换的场景中。根据实际需求,你可以结合 MethodHandle 的各种方法,如 asType、filterArguments 等来实现复杂的动态调用逻辑。