我知道的asn.1数据编解码java库中,有一个开源的,而且可以编解码per/uper格式数据。算是一个很不错的开源库了。这里推荐给java的朋友们,它也不是没有缺点,比如他就没有GeneralizedTime这种日期类型,而且他目前无法实现asn.1文件到java类的自动生成功能,但是这些问题,不妨碍他作为开源界里一个好工具,因为很多工具并不提供per/uper格式的编解码。github地址为:https://github.com/alexvoronov/gcdc-asn1,虽然star只有9颗,但是个人感觉他很好用。
首先,对于普通的编解码都是支持的,比如ber、der,下面来谈谈个人使用的总结:
对于asn.1中的choice,sequence,bit string,integer,ia5string,octet string,enumerated都有很好的支持,下面给出几个示例:
sequence类型asn.1文件定义如下:
MapData ::= SEQUENCE {
msgCnt MsgCount,
timeStamp MinuteOfTheYear OPTIONAL,
nodes NodeList,
-- intersections or road endpoints
...
}
对应的java类代码如下:
@Sequence
@HasExtensionMarker
public static class MapData{
MsgCount msgCount;
@Asn1Optional
MinuteOfTheYear timeStamp ;
NodeList nodes;
public MapData() {
this(new MsgCount(), new MinuteOfTheYear(), new NodeList());
}
public MapData(MsgCount msgCount,MinuteOfTheYear timeStamp,NodeList nodes) {
this.msgCount = msgCount;
this.timeStamp = timeStamp;
this.nodes = nodes;
}
public MsgCount getMsgCount() {
return msgCount;
}
public MinuteOfTheYear getTimeStamp() {
return timeStamp;
}
public NodeList getNodes() {
return nodes;
}
}
enum类型的asn.1文件定义如下:
SourceType ::= ENUMERATED {
unknown(0),
selfinfo(1),
v2x(2),
video(3),
microwaveRadar(4),
loop(5),
lidar(6),
integrated(7),
...
}
对应的java类代码如下所示:
@HasExtensionMarker
public static enum SourceType{
unknown(0),
selfinfo(1),
v2x(2),
video(3),
microwaveRadar(4),
loop(5),
lidar(6),
integrated(7);
private int value;
private SourceType(int value) {this.value = value;}
public int value() {return value;}
}
bit string类型的asn.1文件定义如下:
LaneAttributes-Sidewalk ::= BIT STRING {
sidewalk-RevocableLane (0),
bicyleUseAllowed (1),
isSidewalkFlyOverLane (2),
walkBikes (3)
} (SIZE (16))
对应的java类代码如下所示:
@Bitstring
@FixedSize(16)
public static class LaneAttributes_Sidewalk extends Asn1VarSizeBitstring{
public LaneAttributes_Sidewalk(Boolean... coll) {
this(Arrays.asList(coll));
}
public LaneAttributes_Sidewalk(Collection<Boolean> coll) {
super(coll);
}
protected LaneAttributes_Sidewalk() {
this(new ArrayList<Boolean>());
}
boolean sidewalk_RevocableLane;
boolean bicyleUseAllowed;
boolean isSidewalkFlyOverLane;
boolean walkBikes;
}
bitstring个数大于列举个数的:
LaneAttributes-Vehicle ::= BIT STRING {
isVehicleRevocableLane (0),
isVehicleFlyOverLane (1),
hovLaneUseOnly (2),
restrictedToBusUse (3),
restrictedToTaxiUse (4),
restrictedFromPublicUse (5),
hasIRbeaconCoverage (6),
permissionOnRequest (7)
} (SIZE (8,...))
对应的java类如下所示:
@Bitstring
@FixedSize(8)
@HasExtensionMarker
public static class LaneAttributes_Vehicle{
boolean isVehicleRevocableLane;
boolean isVehicleFlyOverLane;
boolean hovLaneUseOnly;
boolean restrictedToBusUse;
boolean restrictedToTaxiUse;
boolean restrictedFromPublicUse;
boolean hasIRbeaconCoverage;
boolean permissionOnRequest;
}
以上只是简单的列举了几个例子,总得来说,每一个asn.1的类型都可以对应一个java类型,不管是集合sequence of,还是对象sequence,还是枚举enumerated,还是bitstring,还是integer,另外,对于数据范围也有限制,主要是integer类型的,比如INTEGER(0..127),可以通过注解@IntRange(minValue=0,maxValue=127)来标注在java类上实现范围限制。如下所示:
MsgCount ::= INTEGER (0..127)
@IntRange(minValue = 0,maxValue = 127)
public static class MsgCount extends Asn1Integer{
public MsgCount() {
this(0);
}
public MsgCount(int value) {
super(value);
}
}
集合类型asn.1文件定义如下:
ParticipantList ::= SEQUENCE (SIZE(1..16)) OF ParticipantData
java类代码如下所示:
@SizeRange(minValue = 1,maxValue = 16)
public static class ParticipantList extends Asn1SequenceOf<ParticipantData>{
public ParticipantList(ParticipantData... coll) {
this(Arrays.asList(coll));
}
public ParticipantList(Collection<ParticipantData> coll){
super(coll);
}
}
==========================补充choice类型的写法=====================
这里根据有个朋友的提示,没有choice类型的写法,这里补上,算是疏漏了。
asn表示:
-- Main message frame
MessageFrame ::= CHOICE {
bsmFrame BSM,
mapFrame MAP,
rsmFrame RSM,
spatFrame SPAT,
rsiFrame RSI,
...
}
java代码:
@Choice
@HasExtensionMarker
public class MessageFrame{
BSM bsmFrame;
MAP mapFrame;
RSM rsmFrame;
SPAT spatFrame;
RSI rsiFrame;
public MessageFrame() {
this(new BSM());
}
public MessageFrame(BSM bsmFrame) {
this.bsmFrame = bsmFrame;
}
public MessageFrame(MAP mapFrame) {
this.mapFrame = mapFrame;
}
public MessageFrame(RSM rsmFrame) {
this.rsmFrame = rsmFrame;
}
public MessageFrame(SPAT spatFrame) {
this.spatFrame = spatFrame;
}
public MessageFrame(RSI rsiFrame) {
this.rsiFrame = rsiFrame;
}
public BSM getBsmFrame() {
return bsmFrame;
}
public MAP getMapFrame() {
return mapFrame;
}
public RSM getRsmFrame() {
return rsmFrame;
}
public SPAT getSpatFrame() {
return spatFrame;
}
public RSI getRsiFrame() {
return rsiFrame;
}
public boolean hasBsmFrame() {
return this.bsmFrame != null;
}
public boolean hasMapFrame() {
return this.mapFrame != null;
}
public boolean hasRsmFrame() {
return this.rsmFrame != null;
}
public boolean hasSpatFrame() {
return this.spatFrame != null;
}
public boolean hasRsiFrame() {
return this.rsiFrame != null;
}
}
octet string类型asn1表示:
id OCTET STRING (SIZE(8))
java代码:
@OctetString
@FixedSize(8)
public class OctetID extends Asn1SequenceOf<Byte>{
public OctetID() {
this(new byte[] {0});
}
public OctetID(byte... coll) {
this(boxed(coll));
}
public OctetID(Byte... coll) {
this(Arrays.asList(coll));
}
public OctetID(Collection<Byte> coll) {
super(coll);
}
private static Byte[] boxed(byte... coll) {
Byte[] boxedArray = new Byte[coll.length];
for (int i = 0; i < coll.length; i++) {
boxedArray[i] = coll[i];
}
return boxedArray;
}
}
在asn.1表示中,如果有(...)表示还有扩展,在java类上,就需要加上注解:@HasExtensionMarker。
在使用的时候,如果是需要per/uper编解码,我们直接使用UperEncode.encode(Object obj),或者UperEncode.decode(byte[] data,Class<T> t) 来分别进行编码和解码。
需要说明的是,数据的范围,比如(0...127)明确表示范围从0-127,这个一定要在java类上通过注解@IntRange()表示清楚,而且不能省略,否则会出错,再一个就是如果asn.1表式中有...,在java类上,一定要通过@HasExtenstionMarker标注出来,否则,也会因为范围问题而出现意想不到的错误,集合的长度也有明确的限制,比如SIZE(1..16),就是表示集合长度在最小值1,最大值16之间,需要通过@SizeRange()标注出来。
还有一个OPTIONAL修饰符,表示字段可有可无,可选的,我们在定义java类的时候,对其属性一定要使用@Asn1Optional注解标注。
再一个需要注意的地方是,很多java类,都需要定义好几个构造函数,基本需要一个无参构造函数和一个全部参数的构造函数,因为在进行解码的时候,肯定需要通过反射来进行生成对应的类的,如果对应的构造函数缺失,极有可能运行的时候报错。
以前写过一个博客,介绍过asnlab提供的一个编解码框架,他能根据asn.1文件生成java代码,而且还可以与eclipse集成,但是有个缺点就是他提供一个免费试用的机会,只有一个月的license,一个月一过,就无法使用了。功能倒是很齐全,per/uper也都支持,唯独不是免费的,一年的费用好像就是6000RMB,如果没有特别的需要,觉着还是免费的比较好。