Thoughts on building custom protocols (Java)

It has been a year since I started working. Looking back on the process, agreements account for the vast majority.

JSON (common communication text), protoBuf (the editor has written a tutorial), custom protocols (byte splicing, in some IoT fields the standards are almost all byte splicing), of course there are many others, but I don’t know how, and I still need to complete the agreement through asn (I haven’t been exposed to it)
For JSON and protoBuf, it is relatively simple, because there are ready-made libraries that call the JSON and protoBuf compilers;
For byte splicing, it may be more complicated, or it is not complicated at first, but the protocol is complicated, and the splicing becomes complicated;

The protocol in the form of splicing bytes also involves the big-endian and little-endian modes (the big-endian mode is that the low-order bytes are arranged at the low address end of the memory, and the high-order bytes are arranged at the high address end of the memory; while the little-endian mode is that the high-order words are The bits are placed at the low address end of the memory, and the low bytes are placed at the high address end of the memory)
A simple explanation is: big endian converts a number directly into a bytes array; while little endian requires a reverse inversion of the array;

Suppose there is such a protocol: (big end is used as an example below)
Protocol header:

Message name Number of bytes occupied
Message header 1
Message type 1
Message version 1
Message timestamp 8
Message body 1 + 15*n

Agreement:

Message name Number of bytes occupied
Number of perceived objects 1
Perceptual object list 15*n

Perceptual objects:

Message name Number of bytes occupied
Sensed object id 1
Speed of perceived object 4
Courting angle of perceived object 2
Perceived object longitude 4
Perceived object latitude 4

Then I will build several objects like this in Java to implement the protocol:
structure:

Entity upper layer interface specification: Protocol

public abstract class Protocol {<!-- -->
    byte[] bytes = new byte[0];//Abstract bytes array, used to store the final bytes of the successor

    void toBytes() {<!-- -->//Abstract method, constraint subclasses must implement it

    }
}

Message header:

@Data
public class ProtocolHead<T extends Protocol> extends Protocol {<!-- -->
    private byte msgHead;
    private byte msgType;
    private byte msgVersion;
    private long timeStamp;
    private T msgBody;

    @Override
    public void toBytes() {<!-- -->
        msgBody.toBytes();//Array msgBody bytes
        ByteBuffer buffer = ByteBuffer.allocate(1 + 1 + 1 + 8 + msgBody.bytes.length);
        buffer.put(msgHead);
        buffer.put(msgType);
        buffer.put(msgVersion);
        buffer.putLong(timeStamp);
        buffer.put(msgBody.bytes);
        bytes = buffer.array();
    }
}

Message body:

@Data
public class ProtocolBody extends Protocol {<!-- -->
    private byte perNum;
    private PerceptionData[] perceptionDataArr;

    @Override
    public void toBytes() {<!-- -->
        int size = 1;
        for (byte i = 0; i < perNum; i + + ) {<!-- -->
            perceptionDataArr[i].toBytes();//Byteize each perception object
            size + = perceptionDataArr[i].bytes.length;
        }
        ByteBuffer buffer = ByteBuffer.allocate(size);
        for (byte i = 0; i < perNum; i + + ) {<!-- -->
            buffer.put(perceptionDataArr[i].bytes);
        }
        bytes=buffer.array();
    }
}

Message content:

@Data
public class PerceptionData extends Protocol {<!-- -->

    private byte id;
    private int speed;
    private short heading;
    private int lon;
    private int lat;

    @Override
    public void toBytes() {<!-- -->
        ByteBuffer buffer = ByteBuffer.allocate(1 + 4 + 2 + 4 + 4);
        buffer.put(id);
        buffer.putInt(speed);
        buffer.putShort(heading);
        buffer.putInt(lon);
        buffer.putInt(lat);
        bytes= buffer.array();
    }
}

Input data (data incoming from the simulated device)

@Data
public class InputPerData {<!-- -->

    private long timeStamp;
    private List<Per> perList;


    @Data
   public static class Per {<!-- -->
        private byte id;
        private int speed;
        private short heading;
        private int lon;
        private int lat;
    }
}

Parsing class convert conversion:

public class EncodeParser {<!-- -->

    public byte[] convertData(InputPerData inputPerData) {<!-- -->

        PerceptionData[] perArr = new PerceptionData[inputPerData.getPerList().size()];
        for (int i = 0; i < inputPerData.getPerList().size(); i + + ) {<!-- -->
            InputPerData.Per inputPer = inputPerData.getPerList().get(i);
            perArr[i] = new PerceptionData();
            perArr[i].setId(inputPer.getId());
            perArr[i].setSpeed(inputPer.getSpeed());
            perArr[i].setHeading(inputPer.getHeading());
            perArr[i].setLon(inputPer.getLon());
            perArr[i].setLat(inputPer.getLat());
        }

        ProtocolBody body = new ProtocolBody();
        body.setPerNum((byte) inputPerData.getPerList().size());
        body.setPerceptionDataArr(perArr);


        ProtocolHead<ProtocolBody> head = new ProtocolHead<>();
        head.setMsgHead((byte) 0x01);
        head.setMsgType((byte) 0x04);
        head.setMsgVersion((byte) 0x01);
        head.setTimeStamp(inputPerData.getTimeStamp());
        head.setMsgBody(body);

        head.toBytes();//Call encoding method

        return head.bytes;


    }

    public static void main(String[] args) {<!-- -->
        InputPerData.Per per = new InputPerData.Per();
        per.setId((byte) 1);
        per.setSpeed(11);
        per.setHeading((short) 180);
        per.setLon(111342345);
        per.setLat(260099888);
        InputPerData.Per per1 = new InputPerData.Per();
        per1.setId((byte) 2);
        per1.setSpeed(10);
        per1.setHeading((short) 120);
        per1.setLon(114909989);
        per1.setLat(269894903);

        EncodeParser parser = new EncodeParser();
        InputPerData input = new InputPerData();
        input.setTimeStamp(System.currentTimeMillis());
        input.setPerList(Lists.newArrayList(per, per1));
        byte[] bytes = parser.convertData(input); //Final byte is used for network communication, commonly used in netty's tcp/udp communication
        System.out.println("bytes = " + Arrays.toString(bytes));
    }

}

I feel that this can reduce intrusive calculations inside the code, and it is more convenient to write custom protocols;
If there are any shortcomings in the article, please correct me and I will edit it.
Of course, if the bosses have any better methods, we can communicate with them.