Converting Java objects into byte arrays is very common in scenarios where communication protocol transmission is used using netty. For example, the protocol has some established protocol headers, classids, messageids and other information, and another key content is payload. Different protocol contents will be placed in the payload, and this payload is often a byte array.
So, how to conveniently construct a java object into a byte array?
1 bytebuf fill
Let's give an example of the following object:
public class UgvData implements Serialisible{ private static final long serialVersionUID = -219988432063763456L; //Status code byte status; //Current GPS longitude float longitude; //Current GPS latitude float latitude; //Driving speed unit is m/s, with a decimal point float speed; //Current battery percentage short batteryPercentage; //Task number 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(); } //omit get set}Then you just need to new out one of the above objects and call its toByteArray method to convert this object into a byte array.
2. Use json skillfully
We all know that strings can be converted into byte arrays. It is also easy to convert an object into a json string, just use fastjson directly. If you have problems using fastjson, you can check out another blog of my JSON.parseObject and JSON.toJSONString instance
JSON.toJsonString(ugvData).getBytes()
3 Reflection method
The disadvantage of the first method is that each class must write a toByteArray method like this. If there are too many classes, it is very troublesome. Is there any convenient way? Of course, there is one, which uses reflection (it will only reflect the first time, and local cache will be done later, so the performance overhead is not large). You need to add the following five classes in a folder
1.Codecable
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;@Datapublic 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
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 { /** * Attribute order* @return */ int order(); /** * Data length. Used during decoding, it only works except for a simple data type (such as String). * @return */ int length() default 0;}3. FieldWrapper
import lombok.AllArgsConstructor;import lombok.Data;import java.lang.reflect.Field;@Data@AllArgsConstructorpublic class FieldWrapper { /** * Up and down data attributes*/ private Field field; /** * Annotations on up and down data attributes*/ private CodecProprety codecProprety;}4. PayloadDecoder
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("Instantiation class failed", 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": 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 + "Not supported, bug"); } } catch (Exception e) { throw new RuntimeException(typeName + "Read failed, field:" + field.getName(), e); } }}5. PayloadEncoder
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(); } /** * Data is written to 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("Reflection failed to get value, 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 + "not supported, bug"); } }}After adding the above five classes, it is also very easy to use. You only need to convert driveStartData into a byte array as shown below.
PayloadEncoder.getPayload(driveStartData)
4 Summary
Some people may ask, the above three types are obviously the second type to convert JSON is the simplest, so why do you need to use the other two?
In fact, the first and third types can be classified into the same category, both converting the object directly into a byte array. If the next layer is parsed, it can be taken one by one;
The second case is to convert the json string of the object into a byte array. The problem is that the beginning of the json string is "{", that is, the first digit of the byte array converted is "{" corresponding to the value of "{"
In use, it should be based on the situation. If the next layer analyzes the elements directly, use the first one if there are fewer objects; use the third one if there are many objects;
If the next layer does parse some formats of json, use the second one.
All the above are the entire content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.