我正在编写一个反序列化器方法,它看起来像这样:
public <T> T deserialize(Object[] result, String[] fields, Class<T> type);
所以基本上我将传入一个结果数据数组,它是所有对象,以及一个类类型T,我需要将数组中的数据转换为给定类中的类型,并创建一个T类型的新类并返回它。String[]
字段为Object[]
结果中数据对应的字段名。字段名将与类T
对应。
强制转换需要使用给定类的反射来找出每个字段的类型。
。
result = ["Mike", "London", 28];
fields = ["name", "location", "age" ];
分类T =
public class GivenClass{
private String name;
private String location;
private Integer age;
public GivenClass(String name, String location, Integer age){
this.name = name;
this.location = location;
this.age = age;
}
}
类实现
static class GivenClass {
private String name;
private String location;
private Integer age;
public GivenClass(String name, String location, Integer age) {
this.name = name;
this.location = location;
this.age = age;
}
public GivenClass(Map<String, Object> data) throws Exception {
for (Field f : GivenClass.class.getDeclaredFields())
f.set(this, data.get(f.getName()));
}
public Map<String, Object> serialize() throws Exception {
Map<String, Object> fields = new HashMap<String, Object>();
for (Field f : GivenClass.class.getDeclaredFields())
fields.put(f.getName(), f.get(this));
return fields;
}
@Override
public String toString() {
return "age=" + age + ", location=" + location + ", name=" + name;
}
}
例子:
public static void main(String[] args) throws Exception {
GivenClass o1 = new GivenClass("Mike", "London", 28);
Map<String, Object> serialized = o1.serialize();
GivenClass o2 = new GivenClass(serialized);
System.out.println(o2.toString());
}
输出:age=28, location=London, name=Mike
您需要自己进行转换。反射不会转换(它只会检查对象的类型是否正确)
反射不会给你方法/构造函数参数的名字。(你可以从调试字节码中获得它们,但这是一个真正的痛苦)
我采用的方法是使用构造函数参数与字段顺序相同的约定。您还需要假设构造函数参数的类型和字段类型匹配。;)
我也会尽可能使用原语而不是包装器。使用int
,除非您希望null
是一个有效的选项。如果是这种情况,你应该考虑如何表示它。对于文本,我通常根据上下文为null
或NaN
使用空字符串或空白字段。
问题是,在Java中无法获取构造函数的参数名。
对于这个特殊的例子,您需要一个默认构造函数,使用它可以创建一个空对象。
public GivenClass() {
super();
}
那么您可以使用反射来获取类的字段,然后为它们设置适当的值。
但是我认为注释你的构造函数,然后在你的deserialize
方法中获取注释信息会容易得多。在这种情况下,您不需要获取字段并创建空构造函数。
例子:
您需要创建如下注释:
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property
{
String value();
}
然后你可以像这样在你的构造函数中使用它:
public GivenClass(@Property("name") String name, @Property("location") String location, @Property("age") Integer age) {
// ...
}
正如Peter Lawrey所说,强制类型转换不会将字符串转换为整数。
如果您的bean遵循标准bean约定(即您有getter &设置),然后可以使用BeanUtils。BeanUtils做了一些标准的转换,您可以通过添加converter来添加更多。
请看下面的例子:
import org.apache.commons.beanutils.BeanUtils;
public class BeanUtilsTest {
public static class Obj {
private int number;
private String string;
public void setNumber(int number) {
this.number = number;
}
public void setString(String string) {
this.string = string;
}
public String toString() {
return "number=" + number + " string=" + string;
}
}
public static void main(String args[]) throws Exception {
String[] values = new String[] { "1", "two" };
String[] properties = new String[] { "number", "string" };
Obj obj = new Obj();
for (int i = 0; i < properties.length; i++) {
BeanUtils.setProperty(obj, properties[i], values[i]);
}
System.out.println("obj=" + obj);
}
}
产生如下输出:
obj=number=1 string=two
注意,上面的例子只有setter,但仍然有效。