java对象转成byte数组,在使用netty进行通信协议传输的场景中是非常常见的。比如,协议有一些定好的协议头、classid,messageid等等信息,还有一个关键的内容是payload。不同的协议内容都会放到payload中,而这个payload往往就是一个byte数组。
那么,如何方便的将一个java对象构造成一个byte数组呢?
1 bytebuf填充
我们以下面这个对象举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public class ugvdata implements serializible{
private static final long serialversionuid = -219988432063763456l;
//状态码
byte status;
//当前gps经度
float longitude;
//当前gps纬度
float latitude;
//行驶速度 单位是 m/s,带一个小数点
float speed;
//当前电量百分比
short batterypercentage;
//任务编号
long quest;
public byte [] tobytearray() {
bytebuf buf = unpooled.buffer( 32 );
buf.writebyte( this .getstatus());
buf.writefloat(getlongitude());
buf.writefloat(getlatitude());
buf.writefloat(getspeed());
buf.writeshort(getbatterypercentage());
buf.writelong(getquest());
return buf.array();
}
//省略get set
}
|
那么只需要new出一个上面的对象,调用其tobytearray方法,即可将这个对象转成byte数组。
2 巧用json
我们都知道,字符串是可以转成byte数组的。将一个对象转成json字符串也很容易,直接使用fastjson就可以了。如果对fastjson使用有问题的,可以看我的另一篇博客json.parseobject 和 json.tojsonstring 实例
1
|
json.tojsonstring(ugvdata).getbytes()
|
3 反射的方式
第一种方法的缺点在于,每一个类都要这么写一个tobytearray方法。如果类多了是非常麻烦的。有什么方便的方法吗?当然是有的,利用反射的方式(只会在第一次反射,后面会做本地缓存,所以性能开销不大)。需要在一个文件夹下添加下面五个类
1.codecable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import com.fasterxml.jackson.annotation.jsonignore;
import com.google.common.collect.lists;
import lombok.data;
import java.lang.reflect.field;
import java.util.collections;
import java.util.comparator;
import java.util.list;
@data
public abstract class codecable {
public static list<fieldwrapper> resolvefileldwrapperlist( class clazz){
field[] fields = clazz.getdeclaredfields();
list<fieldwrapper> fieldwrapperlist = lists.newarraylist();
for (field field : fields) {
codecproprety codecproprety = field.getannotation(codecproprety. class );
if (codecproprety == null ) {
continue ;
}
fieldwrapper fw = new fieldwrapper(field, codecproprety);
fieldwrapperlist.add(fw);
}
collections.sort(fieldwrapperlist, new comparator<fieldwrapper>() {
@override
public int compare(fieldwrapper o1, fieldwrapper o2) {
return o1.getcodecproprety().order() - o2.getcodecproprety().order();
}
});
return fieldwrapperlist;
}
@jsonignore
public abstract list<fieldwrapper> getfieldwrapperlist();
}
|
2.codecproprety
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
@retention (retentionpolicy.runtime)
@target ({elementtype.field})
public @interface codecproprety {
/**
* 属性顺序
* @return
*/
int order();
/**
* 数据长度。解码时用,除了简单数据类型之外才起作用(如:string)。
* @return
*/
int length() default 0 ;
}
|
3.fieldwrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import lombok.allargsconstructor;
import lombok.data;
import java.lang.reflect.field;
@data
@allargsconstructor
public class fieldwrapper {
/**
* 上下行数据属性
*/
private field field;
/**
* 上下行数据属性上的注解
*/
private codecproprety codecproprety;
}
|
4.payloaddecoder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import io.netty.buffer.bytebuf;
import io.netty.buffer.unpooled;
import java.lang.reflect.field;
import java.lang.reflect.method;
import java.nio.charset.charset;
import java.util.list;
public class payloaddecoder {
public static <t extends codecable> t resolve( byte [] src, class <t> clazz) {
t instance = null ;
try {
instance = clazz.newinstance();
} catch (exception e) {
throw new runtimeexception( "实例化类失败" , e);
}
list<fieldwrapper> fieldwrapperlist = instance.getfieldwrapperlist();
bytebuf buffer = unpooled.buffer().writebytes(src);
for (fieldwrapper fieldwrapper : fieldwrapperlist) {
filldata(fieldwrapper, instance, buffer);
}
return instance;
}
private static void filldata(fieldwrapper fieldwrapper, object instance, bytebuf buffer) {
field field = fieldwrapper.getfield();
field.setaccessible( true );
string typename = field.gettype().getname();
try {
switch (typename) {
case "java.lang.boolean" :
case "boolean" :
boolean b = buffer.readboolean();
field.set(instance, b);
break ;
case "java.lang.character" :
case "char" :
charsequence charsequence = buffer.readcharsequence(fieldwrapper.getcodecproprety().length(), charset.forname( "utf-8" ));
field.set(instance, charsequence);
break ;
case "java.lang.byte" :
case "byte" :
byte b1 = buffer.readbyte();
field.set(instance, b1);
break ;
case "java.lang.short" :
case "short" :
short readshort = buffer.readshort();
field.set(instance, readshort);
break ;
case "java.lang.integer" :
case "int" :
int readint = buffer.readint();
field.set(instance, readint);
break ;
case "java.lang.long" :
case "long" :
long l = buffer.readlong();
field.set(instance, l);
break ;
case "java.lang.float" :
case "float" :
float readfloat = buffer.readfloat();
field.set(instance, readfloat);
break ;
case "java.lang.double" :
case "double" :
double readdouble = buffer.readdouble();
field.set(instance, readdouble);
break ;
case "java.lang.string" :
string readstring = buffer.readcharsequence(fieldwrapper.getcodecproprety().length(), charset.forname( "utf-8" )).tostring();
field.set(instance, readstring);
break ;
default :
throw new runtimeexception(typename + "不支持,bug" );
}
} catch (exception e) {
throw new runtimeexception(typename + "读取失败,field:" + field.getname(), e);
}
}
}
|
5.payloadencoder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
import io.netty.buffer.bytebuf;
import io.netty.buffer.unpooled;
import java.lang.reflect.field;
import java.lang.reflect.method;
import java.nio.charset.charset;
import java.util.list;
public class payloadencoder {
public static <t extends codecable> byte [] getpayload(t command) {
list<fieldwrapper> fieldwrapperlist = command.getfieldwrapperlist();
bytebuf buffer = unpooled.buffer();
fieldwrapperlist.foreach(fieldwrapper -> write2bytebuf(fieldwrapper, command, buffer));
return buffer.array();
}
/**
* 数据写入到bytebuf
*
* @param fieldwrapper
* @param instance
* @param buffer
*/
private static void write2bytebuf(fieldwrapper fieldwrapper, object instance, bytebuf buffer) {
field field = fieldwrapper.getfield();
string typename = field.gettype().getname();
field.setaccessible( true );
object value = null ;
try {
value = field.get(instance);
} catch (illegalaccessexception e) {
new runtimeexception( "反射获取值失败,filed:" + field.getname(), e);
}
switch (typename) {
case "java.lang.boolean" :
case "boolean" :
buffer.writeboolean(( boolean ) value);
break ;
case "java.lang.character" :
case "char" :
buffer.writecharsequence((charsequence) value, charset.forname( "utf-8" ));
break ;
case "java.lang.byte" :
case "byte" :
buffer.writebyte(( byte ) value);
break ;
case "java.lang.short" :
case "short" :
buffer.writeshort(( short ) value);
break ;
case "java.lang.integer" :
case "int" :
buffer.writeint(( int ) value);
break ;
case "java.lang.long" :
case "long" :
buffer.writelong(( long ) value);
break ;
case "java.lang.float" :
case "float" :
buffer.writefloat(( float ) value);
break ;
case "java.lang.double" :
case "double" :
buffer.writedouble(( double ) value);
break ;
case "java.lang.string" :
buffer.writecharsequence((charsequence) value, charset.forname( "utf-8" ));
break ;
default :
throw new runtimeexception(typename + "不支持,bug" );
}
}
}
|
添加完上面五个类之后,使用也很简单,只需要如下所示,就可以把drivestartdata转成byte数组。
1
|
payloadencoder.getpayload(drivestartdata)
|
4 总结
可能会有人问了,上面三种,明显第二种转json最简单,为什么还要用另外两种呢?
其实,第一种和第三种可以归为一类,都是把对象直接转成byte数组,下一层做解析的话,可以一个一个元素取;
第二种情况是把对象的json字符串转成byte数组,问题就在于,json字符串最开头是”{“,也就是转成的byte数组的第一位是”{“对应的数值
在使用中应该根据情况来,如果下一层做解析是直接取元素,对象少的话用第一种;对象多的话用第三种;
如果下一层做了排除掉json的一些格式的解析,就用第二种。
以上全部为本篇文章的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/antony9118/article/details/80713348