前言
在自我训练的项目: RMI 框架实现中,我遇到了需要将参数进行传递和恢复的技术难点,但又觉得基于 JRMP 协议的方式内部效率过低,为了提高以后的编程效率,经过思考,给出 Argument Maker 这样一个工具类,将所要传递的方法和参数转换为 JSON 字符串来实现参数的传递和恢复。
工具需求分析
假设对于如下方法:
public void fun(int num, String str, Complex complex) {
…… ……
}
对于上述方法,现在存在如下对应的实参:
int number = 777;
String str = "huangbo";
Complex c = new Complex(1.1, 2.2);
如何将上述3个实参,字符串化,并且要考虑到未来反向转换成对象。这里经过思考,觉得要使用Map,也就是说,对于实参,无非就是“参数名称” 与 “ Gson 字符串化的参数值”,形成键值对,最后将 Map 对象再次 json 化,形成最终的字符串。于是就有了Argument Maker 这样一个工具类
基于 Json 的 ArgumentMaker
- 首先利用 GsonBuilder() 类生成 Gson 对象,定义了一个存放参数的 map(键是参数名字,值是参数值所形成的 JSON对象)
private static final Type mapType = new TypeToken<Map<String, String>>() {}.getType();
// 上面的mapType是专门为gson使用的!
// 因为,当使用gson转换“泛型”对象时,需要告知gson泛型类型中的泛型。
private Map<String, String> parameterPool;
public ArgumentMaker() {
this.parameterPool = new HashMap<String, String>();
}
注意第 2 行这里出现了 Type 类型(Type 是 Java 编程语言中所有类型的公共高级接口),这里使用它是为了处理泛型,保留泛型类型,避免泛型擦除问题,创建一个 TypeToken 的匿名继承类,由于匿名类信息中保留了泛型信息,通过反射可得。
- 将字符串反向解析成 Map
public ArgumentMaker(String string) {
// 以现在要实现的问题为例,需要让gson知道,将string转换成Map对象,而这个Map
// 本身是存在两个泛型的,需要明确这两个泛型类型。通过mapType就可以说明。
this.parameterPool = gson.fromJson(string, mapType);
// 要特别注意的是,此时this.paramterPool中的内容是:字符串 -> 字符串
}
- 通过
gson.toJson()
方法,将参数的值转为 JSON 字符串放到 map 去;
public ArgumentMaker add(String parameteraName, Object parameterValue) {
this.parameterPool.put(parameteraName, gson.toJson(parameterValue));
return this;
}
- ;通过
gson.fromJson()
方法进行解析,将 JSON 字符串转回去;
第 13 行,传递 Type 类型参数<T> T get(String parameterName, Type parameterType)
,因为Type可以处理泛型,避免泛型擦除问题
@SuppressWarnings("unchecked")
public <T> T get(String parameterName, Class<?> parameterType) throws Exception {
String strParameterValue = this.parameterPool.get(parameterName);
if (strParameterValue == null) {
throw new Exception("没有名为[" + parameterName + "]的形参!");
}
return (T) gson.fromJson(strParameterValue, parameterType);
}
@SuppressWarnings("unchecked")
public <T> T get(String parameterName, Type parameterType) throws Exception {
String strParameterValue = this.parameterPool.get(parameterName);
if (strParameterValue == null) {
throw new Exception("没有名为[" + parameterName + "]的形参!");
}
return (T) gson.fromJson(strParameterValue, parameterType);
}
ArgumentMaker工具
下面给出 ArgumentMaker 工具的完整代码:
package com.mec.util;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
public class ArgumentMaker {
public static final Gson gson = new GsonBuilder().create();
private static final Type mapType = new TypeToken<Map<String, String>>() {}.getType();
// 上面的mapType是专门为gson使用的!
// 因为,当使用gson转换“泛型”对象时,需要告知gson泛型类型中的泛型。
private Map<String, String> parameterPool;
public ArgumentMaker(String string) {
// 以现在要实现的问题为例,需要让gson知道,将string转换成Map对象,而这个Map
// 本身是存在两个泛型的,需要明确这两个泛型类型。通过mapType就可以说明。
this.parameterPool = gson.fromJson(string, mapType);
// 要特别注意的是,此时this.paramterPool中的内容是:字符串 -> 字符串
}
public ArgumentMaker() {
this.parameterPool = new HashMap<String, String>();
}
@SuppressWarnings("unchecked")
public <T> T get(String parameterName, Class<?> parameterType) throws Exception {
String strParameterValue = this.parameterPool.get(parameterName);
if (strParameterValue == null) {
throw new Exception("没有名为[" + parameterName + "]的形参!");
}
return (T) gson.fromJson(strParameterValue, parameterType);
}
@SuppressWarnings("unchecked")
public <T> T get(String parameterName, Type parameterType) throws Exception {
String strParameterValue = this.parameterPool.get(parameterName);
if (strParameterValue == null) {
throw new Exception("没有名为[" + parameterName + "]的形参!");
}
return (T) gson.fromJson(strParameterValue, parameterType);
}
public ArgumentMaker add(String parameteraName, Object parameterValue) {
this.parameterPool.put(parameteraName, gson.toJson(parameterValue));
return this;
}
@Override
public String toString() {
return gson.toJson(this.parameterPool);
}
}