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