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