Skip to content

Commit be09670

Browse files
committed
added JBBPOut.Bin to override @bin field values in written objects
1 parent ebb1750 commit be09670

File tree

7 files changed

+90
-37
lines changed

7 files changed

+90
-37
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**/target/
22
/target/
33
/nbproject/
4-
/.idea/
4+
/**/.idea/
55
*.iml
66
/jbbp-plugins/jbbp-gradle/.gradle/
77
/jbbp-plugins/jbbp-gradle/build/
@@ -39,4 +39,4 @@
3939
/jbbp-plugins/jbbp-gradle/bin/
4040
/jbbp-plugins/jbbp-gradle/.classpath
4141
/jbbp-plugins/jbbp-gradle/.project
42-
/.vscode/
42+
/**/.vscode/

README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Java has some embedded features to parse binary data (for instance ByteBuffer),
1313

1414
# Change log
1515
- **2.0.2 (SNAPSHOT)**
16+
- added `JBBPOut#Bin` variant to override `@Bin` annotation fields in written objects.
1617
- [#28](https://github.com/raydac/java-binary-block-parser/issues/28) added `JBBPOut#BinForceByteOrder` to override byte order defined in `@Bin` annotations of written object.
1718

1819
- **2.0.1 (04-feb-2020)**
@@ -29,13 +30,6 @@ Java has some embedded features to parse binary data (for instance ByteBuffer),
2930
- added generating of `makeFIELD()` method for structure types in Java class converter
3031
- refactoring
3132

32-
- **1.4.1 (20-aug-2018)**
33-
- fixed incompatibility in tokenizer regex syntax for Android SDK [#23](https://github.com/raydac/java-binary-block-parser/issues/23)
34-
- added DslBinCustom annotation to provide way to mark custom type fields for JBBPDslBuilder
35-
- fixed NPE in JBBPDslBuilder for not-provided outBitNumber attribute in annotated field marked as type BIT or BIT_ARRAY [#20](https://github.com/raydac/java-binary-block-parser/issues/20)
36-
- naming of fields has been made more tolerant, now it is allowed to have field names with names similar to data types
37-
- improved check of field names in JBBPDslBuilder [#21](https://github.com/raydac/java-binary-block-parser/issues/21)
38-
3933
[Full changelog](https://github.com/raydac/java-binary-block-parser/blob/master/changelog.txt)
4034

4135
# Maven dependency

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
2.0.2 (SNAPSHOT)
2+
- added `JBBPOut#Bin` variant to override `@Bin` annotation fields in written objects.
23
- [#28](https://github.com/raydac/java-binary-block-parser/issues/28) added `JBBPOut#BinForceByteOrder` to override byte order defined in `@Bin` annotations of written object.
34

45
2.0.1

jbbp/src/main/java/com/igormaznitsa/jbbp/io/AbstractMappedClassFieldObserver.java

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,17 @@ private static void assertFieldArray(final Field field) {
7676
*
7777
* @param obj an object which is an instance of a mapped class, must not be null
7878
* @param field a field where the object has been found, it can be null for first call
79-
* @param forceByteOrder value to replace all byte order values in processing oject, can be null
79+
* @param binAnnotationWrapper wrapper to replace Bin annotation values for processing fields, can be null to be ignored
8080
* @param customFieldProcessor a processor for custom fields, it can be null
8181
* @see Bin
8282
* @since 2.0.2
8383
*/
84-
protected void processObject(final Object obj, Field field, final JBBPByteOrder forceByteOrder, final Object customFieldProcessor) {
84+
protected void processObject(
85+
final Object obj,
86+
final Field field,
87+
final BinAnnotationWrapper binAnnotationWrapper,
88+
final Object customFieldProcessor
89+
) {
8590
JBBPUtils.assertNotNull(obj, "Object must not be null");
8691

8792
final List<MappedFieldRecord> orderedFields = JBBPMapper.findAffectedFields(obj);
@@ -92,13 +97,13 @@ protected void processObject(final Object obj, Field field, final JBBPByteOrder
9297
this.onStructStart(obj, field, clazzAnno == null ? fieldAnno : clazzAnno);
9398

9499
for (final MappedFieldRecord rec : orderedFields) {
95-
Bin binAnno = rec.binAnnotation;
100+
final Bin binAnno = binAnnotationWrapper == null ? rec.binAnnotation : binAnnotationWrapper.setWrapped(rec.binAnnotation);
96101

97102
if (binAnno.custom() && customFieldProcessor == null) {
98-
throw new JBBPIllegalArgumentException("Class '" + obj.getClass().getName() + "' contains field '" + rec.mappingField.getName() + "\' which is custom one, you must provide JBBPCustomFieldWriter instance to save it.");
103+
throw new JBBPIllegalArgumentException("Class '" + obj.getClass().getName() + "' contains field '" + rec.mappingField.getName() + "' which is custom one, you must provide JBBPCustomFieldWriter instance to save it.");
99104
}
100105

101-
processObjectField(obj, rec, forceByteOrder, binAnno, customFieldProcessor);
106+
processObjectField(obj, rec, binAnno, customFieldProcessor);
102107
}
103108

104109
this.onStructEnd(obj, field, clazzAnno == null ? fieldAnno : clazzAnno);
@@ -109,7 +114,6 @@ protected void processObject(final Object obj, Field field, final JBBPByteOrder
109114
*
110115
* @param obj the object which field under processing, must not be null
111116
* @param fieldRecord internal record about the field, must not be null
112-
* @param forceByteOrder byte order to replace byte order defined for field, can be null
113117
* @param annotation the annotation to be used as data source about the field,
114118
* must not be null
115119
* @param customFieldProcessor an object which will be provided for processing
@@ -119,21 +123,16 @@ protected void processObject(final Object obj, Field field, final JBBPByteOrder
119123
protected void processObjectField(
120124
final Object obj,
121125
final MappedFieldRecord fieldRecord,
122-
final JBBPByteOrder forceByteOrder,
123-
Bin annotation,
126+
final Bin annotation,
124127
final Object customFieldProcessor
125128
) {
126129
final Field field = fieldRecord.mappingField;
127130

128-
if (forceByteOrder != null) {
129-
annotation = new BinAnnotationWrapper(annotation).setByteOrder(forceByteOrder);
130-
}
131-
132131
if (annotation.custom()) {
133132
this.onFieldCustom(obj, field, annotation, customFieldProcessor, readFieldValue(obj, fieldRecord));
134133
} else {
135134
final Class<?> fieldType = field.getType();
136-
135+
final BinAnnotationWrapper wrapper = annotation instanceof BinAnnotationWrapper ? (BinAnnotationWrapper) annotation : null;
137136
final BinType type;
138137
if (annotation.type() == BinType.UNDEFINED) {
139138
type = BinType.findCompatible(fieldType);
@@ -249,7 +248,7 @@ protected void processObjectField(
249248
}
250249
break;
251250
case STRUCT: {
252-
processObject(readFieldValue(obj, fieldRecord), field, forceByteOrder, customFieldProcessor);
251+
processObject(readFieldValue(obj, fieldRecord), field, wrapper, customFieldProcessor);
253252
}
254253
break;
255254
default: {
@@ -444,7 +443,7 @@ protected void processObjectField(
444443
final int len = Array.getLength(array);
445444
this.onArrayStart(obj, field, annotation, len);
446445
for (int i = 0; i < len; i++) {
447-
this.processObject(Array.get(array, i), field, forceByteOrder, customFieldProcessor);
446+
this.processObject(Array.get(array, i), field, wrapper, customFieldProcessor);
448447
}
449448
this.onArrayEnd(obj, field, annotation);
450449
}

jbbp/src/main/java/com/igormaznitsa/jbbp/io/JBBPOut.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.igormaznitsa.jbbp.mapper.Bin;
2121
import com.igormaznitsa.jbbp.mapper.JBBPMapper;
2222
import com.igormaznitsa.jbbp.model.JBBPFieldShort;
23+
import com.igormaznitsa.jbbp.utils.BinAnnotationWrapper;
2324
import com.igormaznitsa.jbbp.utils.JBBPUtils;
2425
import java.io.ByteArrayOutputStream;
2526
import java.io.IOException;
@@ -998,35 +999,53 @@ protected void assertNotEnded() {
998999
* through {@link Bin#order()} field, NB! By default Java doesn't keep field
9991000
* outOrder. Ordered fields of class will be saved into internal cache for speed
10001001
* but the cache can be reset through {@link JBBPMapper#clearFieldCache()}
1002+
* <b>Warning!</b> it doesn't affect byte order provided in Bin annotations of object.
10011003
*
10021004
* @param object an object to be saved into stream, must not be null
10031005
* @return the context
10041006
* @throws IOException it will be thrown for any transport error
10051007
* @see JBBPMapper#clearFieldCache()
1008+
* @see #BinForceByteOrder(Object)
10061009
* @see Bin
10071010
* @since 1.1
10081011
*/
10091012
public JBBPOut Bin(final Object object) throws IOException {
1010-
return this.Bin(object, null);
1013+
return this.Bin(object, null, null);
10111014
}
10121015

10131016
/**
10141017
* Save fields of an object marked by Bin annotation. Fields will be ordered
10151018
* through {@link Bin#order()} field, NB! By default Java doesn't keep field
10161019
* outOrder. Ordered fields of class will be saved into internal cache for speed
10171020
* but the cache can be reset through {@link JBBPMapper#clearFieldCache()}
1021+
* <b>Warning!</b> it doesn't affect byte order provided in Bin annotations of object.
10181022
*
10191023
* @param object an object to be saved into stream, must not be null
10201024
* @param customFieldWriter a custom field writer to be used for saving of
10211025
* custom fields of the object, it can be null
10221026
* @return the context
10231027
* @see JBBPMapper#clearFieldCache()
10241028
* @see Bin
1029+
* @see #BinForceByteOrder(Object, JBBPCustomFieldWriter)
10251030
* @since 1.1
10261031
*/
10271032
public JBBPOut Bin(final Object object, final JBBPCustomFieldWriter customFieldWriter) {
1033+
return this.Bin(object, null, customFieldWriter);
1034+
}
1035+
1036+
/**
1037+
* Save fields of object but bin annotation wrapper can be provided to replace some annnotation field values in <b>all</b> field annotations.
1038+
*
1039+
* @param object an object to be saved into stream, must not be null
1040+
* @param binAnnotationWrapper wrapper for all bin annotations, can be null
1041+
* @param customFieldWriter a custom field writer to be used for saving of
1042+
* custom fields of the object, it can be null
1043+
* @return the context
1044+
* @since 2.0.2
1045+
*/
1046+
public JBBPOut Bin(final Object object, final BinAnnotationWrapper binAnnotationWrapper, final JBBPCustomFieldWriter customFieldWriter) {
10281047
if (this.processCommands) {
1029-
this.processObject(object, null, null, customFieldWriter);
1048+
this.processObject(object, null, binAnnotationWrapper, customFieldWriter);
10301049
}
10311050
return this;
10321051
}
@@ -1047,20 +1066,18 @@ public JBBPOut BinForceByteOrder(final Object object) throws IOException {
10471066
}
10481067

10491068
/**
1050-
* Works like {@link #Bin(Object, JBBPCustomFieldWriter)} but forcing override of all annotation byte order values by the JBBPOut byte order.
1069+
* Works like {@link #Bin(Object, JBBPCustomFieldWriter)} but forcing override of all annotation byte order values by the context byte order.
10511070
*
10521071
* @param object an object to be saved into stream, must not be null
10531072
* @param customFieldWriter a custom field writer to be used for saving of
10541073
* custom fields of the object, it can be null
10551074
* @return the context
1075+
* @see #ByteOrder(JBBPByteOrder)
10561076
* @see Bin#byteOrder()
10571077
* @since 2.0.2
10581078
*/
10591079
public JBBPOut BinForceByteOrder(final Object object, final JBBPCustomFieldWriter customFieldWriter) {
1060-
if (this.processCommands) {
1061-
this.processObject(object, null, this.byteOrder, customFieldWriter);
1062-
}
1063-
return this;
1080+
return this.Bin(object, new BinAnnotationWrapper().setByteOrder(this.byteOrder), customFieldWriter);
10641081
}
10651082

10661083
@Override

jbbp/src/main/java/com/igormaznitsa/jbbp/utils/BinAnnotationWrapper.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
import java.lang.annotation.Annotation;
99

1010
/**
11-
* Auxiliary class to replace Bin annotation fields during internal processing
11+
* Auxiliary class to replace Bin annotation field values.
12+
* <b>Not thread safe!</b>
1213
*
13-
* @since 2.0.
14+
* @since 2.0.2
1415
*/
15-
public class BinAnnotationWrapper implements Bin {
16-
private final Bin bin;
16+
public final class BinAnnotationWrapper implements Bin {
17+
private Bin bin;
1718
private String name;
1819
private String path;
1920
private String customType;
@@ -27,8 +28,12 @@ public class BinAnnotationWrapper implements Bin {
2728
private Integer order;
2829
private String comment;
2930

30-
public BinAnnotationWrapper(final Bin bin) {
31+
public BinAnnotationWrapper() {
32+
}
33+
34+
public BinAnnotationWrapper setWrapped(final Bin bin) {
3135
this.bin = bin;
36+
return this;
3237
}
3338

3439
public BinAnnotationWrapper setName(final String value) {
@@ -38,6 +43,7 @@ public BinAnnotationWrapper setName(final String value) {
3843

3944
@Override
4045
public String name() {
46+
assert this.bin != null;
4147
return this.name == null ? this.bin.name() : this.name;
4248
}
4349

@@ -48,6 +54,7 @@ public BinAnnotationWrapper setPath(final String value) {
4854

4955
@Override
5056
public String path() {
57+
assert this.bin != null;
5158
return this.path == null ? this.bin.path() : this.path;
5259
}
5360

@@ -58,6 +65,7 @@ public BinAnnotationWrapper setCustomType(final String value) {
5865

5966
@Override
6067
public String customType() {
68+
assert this.bin != null;
6169
return this.customType == null ? this.bin.customType() : this.customType;
6270
}
6371

@@ -68,6 +76,7 @@ public BinAnnotationWrapper setArraySizeExpr(final String value) {
6876

6977
@Override
7078
public String arraySizeExpr() {
79+
assert this.bin != null;
7180
return this.arraySizeExpr == null ? this.bin.arraySizeExpr() : this.arraySizeExpr;
7281
}
7382

@@ -78,6 +87,7 @@ public BinAnnotationWrapper setType(final BinType value) {
7887

7988
@Override
8089
public BinType type() {
90+
assert this.bin != null;
8191
return this.type == null ? this.bin.type() : this.type;
8292
}
8393

@@ -88,6 +98,7 @@ public BinAnnotationWrapper setBitOrder(final JBBPBitOrder value) {
8898

8999
@Override
90100
public JBBPBitOrder bitOrder() {
101+
assert this.bin != null;
91102
return this.bitOrder == null ? this.bin.bitOrder() : this.bitOrder;
92103
}
93104

@@ -98,6 +109,7 @@ public BinAnnotationWrapper setCustom(final Boolean value) {
98109

99110
@Override
100111
public boolean custom() {
112+
assert this.bin != null;
101113
return this.custom == null ? this.bin.custom() : this.custom;
102114
}
103115

@@ -108,6 +120,7 @@ public BinAnnotationWrapper setParamExpr(final String value) {
108120

109121
@Override
110122
public String paramExpr() {
123+
assert this.bin != null;
111124
return this.paramExpr == null ? this.bin.paramExpr() : this.paramExpr;
112125
}
113126

@@ -118,6 +131,7 @@ public BinAnnotationWrapper setBitNumber(final JBBPBitNumber value) {
118131

119132
@Override
120133
public JBBPBitNumber bitNumber() {
134+
assert this.bin != null;
121135
return this.bitNumber == null ? this.bin.bitNumber() : this.bitNumber;
122136
}
123137

@@ -128,6 +142,7 @@ public BinAnnotationWrapper setByteOrder(final JBBPByteOrder value) {
128142

129143
@Override
130144
public JBBPByteOrder byteOrder() {
145+
assert this.bin != null;
131146
return this.byteOrder == null ? this.bin.byteOrder() : this.byteOrder;
132147
}
133148

@@ -138,6 +153,7 @@ public BinAnnotationWrapper setOrder(final Integer value) {
138153

139154
@Override
140155
public int order() {
156+
assert this.bin != null;
141157
return this.order == null ? this.bin.order() : this.order;
142158
}
143159

@@ -148,11 +164,12 @@ public BinAnnotationWrapper setComment(final String value) {
148164

149165
@Override
150166
public String comment() {
167+
assert this.bin != null;
151168
return this.comment == null ? this.bin.comment() : this.comment;
152169
}
153170

154171
@Override
155172
public Class<? extends Annotation> annotationType() {
156-
return this.bin.getClass();
173+
return Bin.class;
157174
}
158175
}

jbbp/src/test/java/com/igormaznitsa/jbbp/io/JBBPOutTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@
3232
import com.igormaznitsa.jbbp.mapper.BinType;
3333
import com.igormaznitsa.jbbp.model.JBBPFieldInt;
3434
import com.igormaznitsa.jbbp.model.JBBPFieldLong;
35+
import com.igormaznitsa.jbbp.utils.BinAnnotationWrapper;
3536
import com.igormaznitsa.jbbp.utils.JBBPUtils;
3637
import java.io.ByteArrayOutputStream;
3738
import java.io.DataOutputStream;
39+
import java.io.IOException;
40+
import java.lang.reflect.Field;
3841
import org.junit.jupiter.api.Test;
3942

4043
public class JBBPOutTest {
@@ -842,6 +845,28 @@ class Test {
842845
assertArrayEquals(new byte[] {(byte) 0x55, 0x0C}, BeginBin().Bin(new Test((byte) 0x05, (byte) 0x0A, (byte) 0x0C)).End().toByteArray());
843846
}
844847

848+
@Test
849+
public void testBin_OverrideAnnotationValues() throws Exception {
850+
class Test {
851+
@Bin(bitNumber = JBBPBitNumber.BITS_4, type = BinType.BIT)
852+
byte a = (byte) 0b10101010;
853+
}
854+
855+
assertArrayEquals(new byte[] {(byte) 0b00001010}, BeginBin().Bin(new Test(), null, null).End().toByteArray());
856+
assertArrayEquals(new byte[] {(byte) 0b10101010}, BeginBin().Bin(new Test(), new BinAnnotationWrapper().setBitNumber(JBBPBitNumber.BITS_8), null).End().toByteArray());
857+
assertArrayEquals(new byte[] {(byte) 0b00000101}, BeginBin().Bin(new Test(), new BinAnnotationWrapper().setBitOrder(JBBPBitOrder.MSB0), null).End().toByteArray());
858+
assertArrayEquals(new byte[] {(byte) 0b10101010}, BeginBin().Bin(new Test(), new BinAnnotationWrapper().setType(BinType.BYTE), null).End().toByteArray());
859+
860+
final JBBPCustomFieldWriter customFieldWriter = new JBBPCustomFieldWriter() {
861+
@Override
862+
public void writeCustomField(JBBPOut context, JBBPBitOutputStream outStream, Object instanceToSave, Field instanceCustomField, Bin fieldAnnotation, Object value) throws IOException {
863+
outStream.write(123);
864+
}
865+
};
866+
867+
assertArrayEquals(new byte[] {(byte) 123}, BeginBin().Bin(new Test(), new BinAnnotationWrapper().setCustom(true), customFieldWriter).End().toByteArray());
868+
}
869+
845870
@Test
846871
public void testBin_UndefinedType_Short() throws Exception {
847872
class Test {

0 commit comments

Comments
 (0)