diff --git a/src/zutil/parser/binary/BinaryFieldData.java b/src/zutil/parser/binary/BinaryFieldData.java index dc57e83..b403a04 100755 --- a/src/zutil/parser/binary/BinaryFieldData.java +++ b/src/zutil/parser/binary/BinaryFieldData.java @@ -33,6 +33,7 @@ import zutil.parser.binary.BinaryStruct.CustomBinaryField; import zutil.parser.binary.BinaryStruct.VariableLengthBinaryField; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; import java.util.*; @@ -49,7 +50,7 @@ public class BinaryFieldData { private BinaryFieldData lengthField; private int lengthMultiplier; /* @CustomBinaryField */ - private BinaryFieldSerializer serializer; + private Class serializerClass; protected static List getStructFieldList(Class clazz) { @@ -80,16 +81,17 @@ public class BinaryFieldData { } - private BinaryFieldData(Field f) throws IllegalAccessException, InstantiationException, NoSuchFieldException { + private BinaryFieldData(Field f) throws NoSuchFieldException { field = f; this.length = -1; this.lengthField = null; this.lengthMultiplier = 1; - this.serializer = null; + this.serializerClass = null; + if (field.isAnnotationPresent(CustomBinaryField.class)) { CustomBinaryField fieldData = field.getAnnotation(CustomBinaryField.class); this.index = fieldData.index(); - this.serializer = fieldData.serializer().newInstance(); + this.serializerClass = fieldData.serializer(); } else if (field.isAnnotationPresent(VariableLengthBinaryField.class)) { VariableLengthBinaryField fieldData = field.getAnnotation(VariableLengthBinaryField.class); @@ -185,8 +187,21 @@ public class BinaryFieldData { return length; } + + public boolean hasSerializer() { + return serializerClass != null; + } + + public Class getSerializerClass() { + return serializerClass; + } + public BinaryFieldSerializer getSerializer() { - return serializer; + try { + return serializerClass.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Unable to instantiate class: " + serializerClass, e); + } } @@ -197,8 +212,8 @@ public class BinaryFieldData { (lengthField != null ? "LengthField: " + lengthField + ", LengthMultiplier: " + lengthMultiplier : length + " bits") + - (serializer != null ? - ", Serializer: " + serializer.getClass().getName() : "") + + (serializerClass != null ? + ", Serializer: " + serializerClass.getClass().getName() : "") + ")"; } diff --git a/src/zutil/parser/binary/BinaryFieldSerializer.java b/src/zutil/parser/binary/BinaryFieldSerializer.java index a7ac9cf..4820af7 100755 --- a/src/zutil/parser/binary/BinaryFieldSerializer.java +++ b/src/zutil/parser/binary/BinaryFieldSerializer.java @@ -30,6 +30,11 @@ import java.io.OutputStream; /** * An Interface where custom field parser and writer can be implemented. + *

+ * One instance of the serializer and will have the scope of the methods + * {@link BinaryStructInputStream#read(BinaryStruct)} and {@link BinaryStructOutputStream#write(BinaryStruct)} + * where as it will be deallocated after the methods have returned. + *

* NOTE: Partial octet serializing not supported. * * Created by Ziver on 2016-04-11. diff --git a/src/zutil/parser/binary/BinaryStruct.java b/src/zutil/parser/binary/BinaryStruct.java index d2450b2..efa706b 100755 --- a/src/zutil/parser/binary/BinaryStruct.java +++ b/src/zutil/parser/binary/BinaryStruct.java @@ -42,7 +42,7 @@ public interface BinaryStruct { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) - @interface BinaryField{ + @interface BinaryField { /** @return a number indicating the order the fields are read. Lowest index number field will be read first. */ int index(); /** @return the bit length of the data */ @@ -56,7 +56,7 @@ public interface BinaryStruct { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) - @interface VariableLengthBinaryField{ + @interface VariableLengthBinaryField { /** @return a number indicating the order the fields are read. Lowest index number field will be read first. */ int index(); /** @return a String name of the field that contains the length of the data to be read. */ @@ -71,7 +71,7 @@ public interface BinaryStruct { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) - @interface CustomBinaryField{ + @interface CustomBinaryField { /** @return a number indicating the order the fields are read. Lowest index number field will be read first. */ int index(); /** @return the serializer class name that will be used. Class needs to be publicly visible. */ diff --git a/src/zutil/parser/binary/BinaryStructInputStream.java b/src/zutil/parser/binary/BinaryStructInputStream.java index 79b8d7b..b940612 100755 --- a/src/zutil/parser/binary/BinaryStructInputStream.java +++ b/src/zutil/parser/binary/BinaryStructInputStream.java @@ -29,11 +29,15 @@ import zutil.ByteUtil; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** - * A stream class that parses a byte stream into - * binary struct objects. + * A stream class that parses a byte stream into binary struct objects. + *

+ * Limitations:
+ * - Does not support sub binary objects.
* * @author Ziver */ @@ -74,14 +78,20 @@ public class BinaryStructInputStream { */ public int read(BinaryStruct struct) throws IOException { List structDataList = BinaryFieldData.getStructFieldList(struct.getClass()); + Map serializerCache = new HashMap<>(); int totalReadLength = 0; for (BinaryFieldData field : structDataList) { - if (field.getSerializer() != null) { - Object value = field.getSerializer().read(in, field); + if (field.hasSerializer()) { + BinaryFieldSerializer serializer = serializerCache.get(field.getSerializerClass()); + if (serializer == null) { + serializer = field.getSerializer(); + serializerCache.put(serializer.getClass(), serializer); + } + + Object value = serializer.read(in, field); field.setValue(struct, value); - } - else { + } else { byte[] valueData = new byte[(int) Math.ceil(field.getBitLength(struct) / 8.0)]; int fieldReadLength = 0; // How much we have read so far int shiftBy = shiftLeftBy(dataBitIndex, field.getBitLength(struct)); diff --git a/src/zutil/parser/binary/BinaryStructOutputStream.java b/src/zutil/parser/binary/BinaryStructOutputStream.java index 3d66ba5..673647b 100755 --- a/src/zutil/parser/binary/BinaryStructOutputStream.java +++ b/src/zutil/parser/binary/BinaryStructOutputStream.java @@ -29,12 +29,16 @@ import zutil.ByteUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** - * A stream class that generates a byte stream from - * binary struct objects. + * A stream class that generates a byte stream from a binary struct objects. + *

+ * Limitations:
+ * - Does not support sub binary objects.
* * @author Ziver */ @@ -84,13 +88,19 @@ public class BinaryStructOutputStream { */ public void write(BinaryStruct struct) throws IOException { List structDataList = BinaryFieldData.getStructFieldList(struct.getClass()); + Map serializerCache = new HashMap<>(); for (BinaryFieldData field : structDataList) { - if (field.getSerializer() != null) { + if (field.hasSerializer()) { + BinaryFieldSerializer serializer = serializerCache.get(field.getSerializerClass()); + if (serializer == null) { + serializer = field.getSerializer(); + serializerCache.put(serializer.getClass(), serializer); + } + localFlush(); - field.getSerializer().write(out, field.getValue(struct), field); - } - else { + serializer.write(out, field.getValue(struct), field); + } else { int fieldBitLength = field.getBitLength(struct); byte[] data = field.getByteValue(struct); data = ByteUtil.shiftRight(data, ((8 - fieldBitLength % 8) % 8)); @@ -100,7 +110,7 @@ public class BinaryStructOutputStream { if (restBitLength == 0 && fieldBitLength >= 8) out.write(0xFF & b); else { - b = (byte)((b&0xFF) >> restBitLength); + b = (byte) ((b & 0xFF) >> restBitLength); b &= ByteUtil.getBitMask(7 - restBitLength, fieldBitLength); rest |= b; restBitLength += fieldBitLength;