Skip to content

Commit ea8ab42

Browse files
committed
#29 added example of read-write-mapping processor for nullable byte arrays
1 parent 2606b5a commit ea8ab42

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

jbbp/src/test/java/com/igormaznitsa/jbbp/it/BasedOnQuestionsAndCasesTest.java

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
2020
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
import static org.junit.jupiter.api.Assertions.assertNull;
2122

2223

2324
import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor;
@@ -27,14 +28,18 @@
2728
import com.igormaznitsa.jbbp.io.JBBPBitInputStream;
2829
import com.igormaznitsa.jbbp.io.JBBPBitNumber;
2930
import com.igormaznitsa.jbbp.io.JBBPBitOrder;
31+
import com.igormaznitsa.jbbp.io.JBBPBitOutputStream;
3032
import com.igormaznitsa.jbbp.io.JBBPByteOrder;
33+
import com.igormaznitsa.jbbp.io.JBBPCustomFieldWriter;
3134
import com.igormaznitsa.jbbp.io.JBBPOut;
3235
import com.igormaznitsa.jbbp.mapper.Bin;
3336
import com.igormaznitsa.jbbp.mapper.BinType;
37+
import com.igormaznitsa.jbbp.mapper.JBBPMapperCustomFieldProcessor;
3438
import com.igormaznitsa.jbbp.model.JBBPAbstractField;
3539
import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte;
3640
import com.igormaznitsa.jbbp.model.JBBPFieldArrayLong;
3741
import com.igormaznitsa.jbbp.model.JBBPFieldArrayString;
42+
import com.igormaznitsa.jbbp.model.JBBPFieldArrayStruct;
3843
import com.igormaznitsa.jbbp.model.JBBPFieldInt;
3944
import com.igormaznitsa.jbbp.model.JBBPFieldLong;
4045
import com.igormaznitsa.jbbp.model.JBBPFieldString;
@@ -45,10 +50,12 @@
4550
import java.io.EOFException;
4651
import java.io.IOException;
4752
import java.io.InputStream;
53+
import java.lang.reflect.Field;
4854
import java.nio.charset.StandardCharsets;
4955
import java.util.ArrayList;
5056
import java.util.Iterator;
5157
import java.util.List;
58+
import java.util.Locale;
5259
import java.util.concurrent.atomic.AtomicInteger;
5360
import java.util.concurrent.atomic.AtomicLong;
5461
import org.junit.jupiter.api.Test;
@@ -415,4 +422,174 @@ public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final
415422
result = sasParser.parse(new byte[] {0, 0, 0, 2, 1, 2, 3, 4});
416423
assertEquals(2, ((JBBPNumericField) result.findFieldForName("keycount")).getAsInt());
417424
}
425+
426+
/**
427+
* Case 09-jun-2020
428+
* Example how to write custom field type read-write-mapping processor for nullable byte array.
429+
*
430+
* @throws Exception for any error
431+
*/
432+
@Test
433+
public void testNullableByteArrayField() throws Exception {
434+
class NullableByteArrayProcessor
435+
implements JBBPCustomFieldWriter, JBBPMapperCustomFieldProcessor,
436+
JBBPCustomFieldTypeProcessor {
437+
438+
private final String TYPE = "nullableByteArray";
439+
private final String[] CUSTOM_TYPE = new String[] {TYPE.toLowerCase(Locale.ENGLISH)};
440+
441+
@Override
442+
public String[] getCustomFieldTypes() {
443+
return CUSTOM_TYPE;
444+
}
445+
446+
@Override
447+
public boolean isAllowed(JBBPFieldTypeParameterContainer fieldType, String fieldName,
448+
int extraData, boolean isArray) {
449+
return !isArray;
450+
}
451+
452+
private byte[] readFromStream(JBBPByteOrder byteOrder, JBBPBitInputStream in)
453+
throws IOException {
454+
final int len = in.readInt(byteOrder);
455+
return len < 0 ? null : in.readByteArray(len);
456+
}
457+
458+
@Override
459+
public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder bitOrder,
460+
int parserFlags,
461+
JBBPFieldTypeParameterContainer customTypeFieldInfo,
462+
JBBPNamedFieldInfo fieldName, int extraData,
463+
boolean readWholeStream, int arrayLength)
464+
throws IOException {
465+
if (arrayLength < 0) {
466+
return toStruct(fieldName, readFromStream(customTypeFieldInfo.getByteOrder(), in));
467+
} else {
468+
throw new IllegalArgumentException("Array of nullable byte arrays is unsupported");
469+
}
470+
}
471+
472+
private void writeTo(final JBBPBitOutputStream outStream, final JBBPByteOrder order,
473+
final byte[] data) throws IOException {
474+
if (data == null) {
475+
outStream.writeInt(-1, order);
476+
} else {
477+
outStream.writeInt(data.length, order);
478+
outStream.write(data);
479+
}
480+
}
481+
482+
@Override
483+
public void writeCustomField(JBBPOut context, JBBPBitOutputStream outStream,
484+
Object instanceToSave, Field instanceCustomField,
485+
Bin fieldAnnotation, Object value) throws IOException {
486+
if (fieldAnnotation.customType().equals(TYPE)) {
487+
writeTo(outStream, fieldAnnotation.byteOrder(), (byte[]) value);
488+
} else {
489+
throw new IllegalArgumentException(
490+
"Unsupported custom type: " + fieldAnnotation.customType());
491+
}
492+
}
493+
494+
private JBBPFieldStruct toStruct(JBBPNamedFieldInfo fieldName, final byte[] array) {
495+
if (array == null) {
496+
return new JBBPFieldStruct(fieldName, new JBBPAbstractField[0]);
497+
} else {
498+
return new JBBPFieldStruct(fieldName,
499+
new JBBPAbstractField[] {new JBBPFieldArrayByte(null, array)});
500+
}
501+
}
502+
503+
private byte[] fromStruct(final JBBPFieldStruct struct) {
504+
final JBBPAbstractField[] fields = struct.getArray();
505+
return fields.length == 0 ? null : ((JBBPFieldArrayByte) struct.getArray()[0]).getArray();
506+
}
507+
508+
@Override
509+
public Object prepareObjectForMapping(JBBPFieldStruct parsedBlock,
510+
Bin annotation,
511+
Field field) {
512+
if (annotation.customType().equals(TYPE)) {
513+
if (field.getType() == byte[][].class) {
514+
final JBBPFieldArrayStruct structs =
515+
parsedBlock.findFieldForNameAndType(field.getName(), JBBPFieldArrayStruct.class);
516+
final byte[][] result = new byte[structs.size()][];
517+
for (int i = 0; i < structs.size(); i++) {
518+
result[i] = fromStruct(structs.getElementAt(i));
519+
}
520+
return result;
521+
} else {
522+
return fromStruct(
523+
parsedBlock.findFieldForNameAndType(field.getName(), JBBPFieldStruct.class));
524+
}
525+
} else {
526+
throw new IllegalArgumentException("Unexpected custom type: " + annotation.customType());
527+
}
528+
}
529+
}
530+
;
531+
532+
final NullableByteArrayProcessor nullableByteArrayProcessor = new NullableByteArrayProcessor();
533+
534+
class Klazz {
535+
@Bin
536+
int a;
537+
@Bin(custom = true, customType = "nullableByteArray")
538+
byte[] b;
539+
@Bin
540+
int c;
541+
}
542+
;
543+
544+
Klazz object = new Klazz();
545+
object.a = 12345;
546+
object.b = null;
547+
object.c = 7890;
548+
549+
final byte[] withNullField =
550+
JBBPOut.BeginBin().Bin(object, nullableByteArrayProcessor).End().toByteArray();
551+
552+
assertArrayEquals(
553+
new byte[] {0, 0, 48, 57, (byte) -1, (byte) -1, (byte) -1, (byte) -1, 0, 0, 30, (byte) -46},
554+
withNullField);
555+
556+
object = new Klazz();
557+
object.a = 12345;
558+
object.b = new byte[] {1, 2, 3};
559+
object.c = 7890;
560+
561+
final byte[] withContent =
562+
JBBPOut.BeginBin().Bin(object, nullableByteArrayProcessor).End().toByteArray();
563+
assertArrayEquals(new byte[] {0, 0, 48, 57, 0, 0, 0, 3, 1, 2, 3, 0, 0, 30, (byte) -46},
564+
withContent);
565+
566+
object = new Klazz();
567+
object.a = 12345;
568+
object.b = new byte[0];
569+
object.c = 7890;
570+
571+
final byte[] withZeroLength =
572+
JBBPOut.BeginBin().Bin(object, nullableByteArrayProcessor).End().toByteArray();
573+
assertArrayEquals(new byte[] {0, 0, 48, 57, 0, 0, 0, 0, 0, 0, 30, (byte) -46}, withZeroLength);
574+
575+
JBBPParser parser =
576+
JBBPParser.prepare("int a; nullableByteArray b; int c;", nullableByteArrayProcessor);
577+
578+
Klazz parsed = parser.parse(withNullField).mapTo(new Klazz(), nullableByteArrayProcessor);
579+
580+
assertEquals(12345, parsed.a);
581+
assertNull(parsed.b);
582+
assertEquals(7890, parsed.c);
583+
584+
parsed = parser.parse(withZeroLength).mapTo(new Klazz(), nullableByteArrayProcessor);
585+
assertEquals(12345, parsed.a);
586+
assertArrayEquals(new byte[0], parsed.b);
587+
assertEquals(7890, parsed.c);
588+
589+
parsed = parser.parse(withContent).mapTo(new Klazz(), nullableByteArrayProcessor);
590+
assertEquals(12345, parsed.a);
591+
assertArrayEquals(new byte[] {1, 2, 3}, parsed.b);
592+
assertEquals(7890, parsed.c);
593+
}
594+
418595
}

0 commit comments

Comments
 (0)