原文链接
https://code.google.com/archive/p/javastruct/
翻译用工具
翻译使用的是个人免费版Transmate
译文
简介
当与嵌入式设备和其他使用C语言样式的结构体的应用协同工作时,结构体类能非常简便地用于Java应用的网络协议编程。
不需要手动编解码消息,JavaStruct允许开发者对待java类就像C结构体。
JavaStruct使用Java5声明以将类或成员变量标记为结构体。JavaStruct 并不是第一种尝试提供类结构体功能的。Jean-Marie Dautelle 的 Javolution 库也是一个优秀的结构体实现。但是区别于Javolution使用特定类,JavaStruct是要用更简单的POJO方式。
一般性的使用
JavaStruct 装饰类用于封包和解包结构体类。下面是一个测试结构体类的简单的单元测试。结构体字段有一个顺序值,因为Java JVM的规范中并没有关于类成员顺序的信息。在Sun公司的实现中是按照他们的出现顺序,但是在其他JVM中则不一定。所以每一个结构体字段需要给定一个顺序值。
@StructClass
public class Foo{
@StructField(order = 0)
public byte b;
@StructField(order = 1)
public int i;
}
try{
// Pack the class as a byte buffer
Foo f = new Foo();
f.b = (byte)1;
f.i = 1;
byte[] b = JavaStruct.pack(f);
// Unpack it into an object
Foo f2 = new Foo();
JavaStruct.unpack(f2, b);
} catch(StructException e){ }
如果有任何错误,结构体操作将抛出一个StructException异常。
结构体类也能被流直接使用。请参考Photoshop ACB文件阅读器例子。
public void read(String acbFile){
try {
FileInputStream fis = new FileInputStream(new File(acbFile));
header = new ACBHeader();
StructUnpacker up = JavaStruct.getUnpacker(fis, ByteOrder.BIG_ENDIAN);
up.readObject(header); ...
基本类型
使用基本类型。注意私有(private)域和受保护(protected)域需要合适的getter和setter方法。临时字段(transient fields)将被自动排除。
@StructClass
public class PublicPrimitives implements Serializable {
@StructField(order = 0)
public byte b;
@StructField(order = 1)
public char c;
@StructField(order = 2)
public short s;
@StructField(order = 3)
public int i;
@StructField(order = 4)
public long lo;
@StructField(order = 5)
protected float f;
@StructField(order = 6)
private double d;
transient int blah;
transient double foo;
public float getF() {
return f;
}
public void setF(float f) {
this.f = f;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public boolean equals(Object o) {
PublicPrimitives other = (PublicPrimitives)o;
return (this.b == other.b
&& this.c == other.c
&& this.s == other.s
&& this.i == other.i
&& this.lo == other.lo
&& this.f == other.f
&& this.d == other.d);
}
}
数组
数组有一些先决条件。当解包时,数组中需要有足够的空间。仅仅数组在解包时自动分配,其长度可以是null由其他字段使用数组长度标记(ArrayLengthMarker)定义(见下面章节)。除此之外数组不能是空和未初始化。
@StructClass
public class PublicPrimitiveArrays{
@StructField(order = 0)
public byte[] b = new byte[5];
@StructField(order = 1)
public char[] c = new byte[10];
@StructField(order = 2)
public short[] s;
@StructField(order = 3)
public int[] i;
}
数组长度标记
数组长度标记对于那些自身长度由其他字段定义的字段非常有用,看如下例子。这是一个特别的字符串结构体,其有一个长度字段,长度值16 bit 字母随其后。
±-------±----------------------//----------------------------------------+ | Length | UTF-16 Characters \ | ±-------±----------------------//----------------------------------------+
为处理它,我们要构建一个结构体类来表示这些字符串,姑且叫它 A 结构体。长度字段应该使用“数组长度标记”声明。这样在解封包操作过程中处理数组字段时,javastruct能自动使用长度字段里的值。
@StructClass
public class AString {
@StructField (order = 0)
@ArrayLengthMarker (fieldName = "chars")
public int length;
@StructField (order = 1)
public char[] chars;
public AString(String content) {
this.length = content.length();
this.chars = content.toCharArray();
}
...
}