Skip to content

Commit 768e6e2

Browse files
committed
added test and improved mapping
1 parent 0be9bee commit 768e6e2

File tree

5 files changed

+132
-36
lines changed

5 files changed

+132
-36
lines changed

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

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,20 @@ public abstract class AbstractMappedClassFieldObserver {
4242
* Inside auxiliary method to read object field value.
4343
*
4444
* @param obj an object which field is read
45-
* @param field a field to be read
45+
* @param record field record, must not be null
4646
* @return a value from the field of the object
4747
* @throws JBBPException if the field can't be read
48-
* @since 1.1
48+
* @since 2.0
4949
*/
50-
private static Object readFieldValue(final Object obj, final Field field) {
50+
private static Object readFieldValue(final Object obj, final MappedFieldRecord record) {
5151
try {
52-
return field.get(obj);
52+
if (record.getter == null) {
53+
return record.mappingField.get(obj);
54+
} else {
55+
return record.getter.invoke(obj);
56+
}
5357
} catch (Exception ex) {
54-
throw new JBBPException("Can't get value from field [" + field + ']', ex);
58+
throw new JBBPException("Can't get value from field [" + record + ']', ex);
5559
}
5660
}
5761

@@ -79,6 +83,7 @@ protected void processObject(final Object obj, Field field, final Object customF
7983

8084
final List<MappedFieldRecord> orderedFields = JBBPMapper.findAffectedFields(obj);
8185

86+
//TODO check DslBinCustom
8287
final Bin clazzAnno = obj.getClass().getAnnotation(Bin.class);
8388
final DslBinCustom clazzCustomAnno = obj.getClass().getAnnotation(DslBinCustom.class);
8489
final Bin fieldAnno = field == null ? null : field.getAnnotation(Bin.class);
@@ -93,7 +98,7 @@ protected void processObject(final Object obj, Field field, final Object customF
9398
throw new JBBPIllegalArgumentException("The Class '" + obj.getClass().getName() + "' contains the field '" + rec.mappingField.getName() + "\' which is a custom one, you must provide a JBBPCustomFieldWriter instance to save the field.");
9499
}
95100

96-
processObjectField(obj, rec.mappingField, binAnno, customFieldProcessor);
101+
processObjectField(obj, rec, binAnno, customFieldProcessor);
97102
}
98103

99104
this.onStructEnd(obj, field, clazzAnno == null ? fieldAnno : clazzAnno);
@@ -103,15 +108,16 @@ protected void processObject(final Object obj, Field field, final Object customF
103108
* Inside auxiliary method to process a field of an object.
104109
*
105110
* @param obj the object which field under processing, must not be null
106-
* @param field the field to be written, must not be null
111+
* @param fieldRecord internal record about the field, must not be null
107112
* @param annotation the annotation to be used as data source about the field,
108113
* must not be null
109114
* @param customFieldProcessor an object which will be provided for processing
110115
* of custom fields, must not be null if object contains custom fields
111116
*/
112-
protected void processObjectField(final Object obj, final Field field, final Bin annotation, final Object customFieldProcessor) {
117+
protected void processObjectField(final Object obj, final MappedFieldRecord fieldRecord, final Bin annotation, final Object customFieldProcessor) {
118+
final Field field = fieldRecord.mappingField;
113119
if (annotation.custom()) {
114-
this.onFieldCustom(obj, field, annotation, customFieldProcessor, readFieldValue(obj, field));
120+
this.onFieldCustom(obj, field, annotation, customFieldProcessor, readFieldValue(obj, fieldRecord));
115121
} else {
116122
final Class<?> fieldType = field.getType();
117123

@@ -128,9 +134,9 @@ protected void processObjectField(final Object obj, final Field field, final Bin
128134
case BIT: {
129135
final JBBPBitNumber bitNumber = annotation.outBitNumber();
130136
if (fieldType == boolean.class) {
131-
this.onFieldBits(obj, field, annotation, bitNumber, ((Boolean) readFieldValue(obj, field)) ? 0xFF : 0x00);
137+
this.onFieldBits(obj, field, annotation, bitNumber, ((Boolean) readFieldValue(obj, fieldRecord)) ? 0xFF : 0x00);
132138
} else {
133-
byte value = ((Number) readFieldValue(obj, field)).byteValue();
139+
byte value = ((Number) readFieldValue(obj, fieldRecord)).byteValue();
134140
if (reverseBits) {
135141
value = JBBPUtils.reverseBitsInByte(bitNumber, value);
136142
}
@@ -140,15 +146,15 @@ protected void processObjectField(final Object obj, final Field field, final Bin
140146
break;
141147
case BOOL: {
142148
if (fieldType == boolean.class) {
143-
onFieldBool(obj, field, annotation, (Boolean) readFieldValue(obj, field));
149+
onFieldBool(obj, field, annotation, (Boolean) readFieldValue(obj, fieldRecord));
144150
} else {
145-
onFieldBool(obj, field, annotation, ((Number) readFieldValue(obj, field)).longValue() != 0);
151+
onFieldBool(obj, field, annotation, ((Number) readFieldValue(obj, fieldRecord)).longValue() != 0);
146152
}
147153
}
148154
break;
149155
case BYTE:
150156
case UBYTE: {
151-
byte value = ((Number) readFieldValue(obj, field)).byteValue();
157+
byte value = ((Number) readFieldValue(obj, fieldRecord)).byteValue();
152158
if (reverseBits) {
153159
value = JBBPUtils.reverseBitsInByte(value);
154160
}
@@ -159,9 +165,9 @@ protected void processObjectField(final Object obj, final Field field, final Bin
159165
case USHORT: {
160166
short value;
161167
if (fieldType == char.class) {
162-
value = (short) ((Character) readFieldValue(obj, field)).charValue();
168+
value = (short) ((Character) readFieldValue(obj, fieldRecord)).charValue();
163169
} else {
164-
value = ((Number) readFieldValue(obj, field)).shortValue();
170+
value = ((Number) readFieldValue(obj, fieldRecord)).shortValue();
165171
}
166172
if (reverseBits) {
167173
value = (short) JBBPFieldShort.reverseBits(value);
@@ -171,7 +177,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin
171177
break;
172178
case INT: {
173179
int value;
174-
value = ((Number) readFieldValue(obj, field)).intValue();
180+
value = ((Number) readFieldValue(obj, fieldRecord)).intValue();
175181
if (reverseBits) {
176182
value = (int) JBBPFieldInt.reverseBits(value);
177183
}
@@ -181,9 +187,9 @@ protected void processObjectField(final Object obj, final Field field, final Bin
181187
case FLOAT: {
182188
float value;
183189
if (float.class == fieldType) {
184-
value = (Float) readFieldValue(obj, field);
190+
value = (Float) readFieldValue(obj, fieldRecord);
185191
} else {
186-
value = ((Number) readFieldValue(obj, field)).floatValue();
192+
value = ((Number) readFieldValue(obj, fieldRecord)).floatValue();
187193
}
188194
if (reverseBits) {
189195
value = Float.intBitsToFloat((int) JBBPFieldInt.reverseBits(Float.floatToIntBits(value)));
@@ -193,7 +199,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin
193199
break;
194200
case STRING: {
195201
String value;
196-
final Object valueAsObject = readFieldValue(obj, field);
202+
final Object valueAsObject = readFieldValue(obj, fieldRecord);
197203
if (valueAsObject != null) {
198204
value = String.valueOf(valueAsObject);
199205
if (reverseBits) {
@@ -206,7 +212,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin
206212
}
207213
break;
208214
case LONG: {
209-
long value = ((Number) readFieldValue(obj, field)).longValue();
215+
long value = ((Number) readFieldValue(obj, fieldRecord)).longValue();
210216
if (reverseBits) {
211217
value = JBBPFieldLong.reverseBits(value);
212218
}
@@ -216,11 +222,11 @@ protected void processObjectField(final Object obj, final Field field, final Bin
216222
case DOUBLE: {
217223
double value;
218224
if (float.class == fieldType) {
219-
value = (Float) readFieldValue(obj, field);
225+
value = (Float) readFieldValue(obj, fieldRecord);
220226
} else if (double.class == fieldType) {
221-
value = (Double) readFieldValue(obj, field);
227+
value = (Double) readFieldValue(obj, fieldRecord);
222228
} else {
223-
value = ((Number) readFieldValue(obj, field)).doubleValue();
229+
value = ((Number) readFieldValue(obj, fieldRecord)).doubleValue();
224230
}
225231

226232
if (reverseBits) {
@@ -230,11 +236,11 @@ protected void processObjectField(final Object obj, final Field field, final Bin
230236
}
231237
break;
232238
case STRUCT: {
233-
processObject(readFieldValue(obj, field), field, customFieldProcessor);
239+
processObject(readFieldValue(obj, fieldRecord), field, customFieldProcessor);
234240
}
235241
break;
236242
default: {
237-
final Object array = readFieldValue(obj, field);
243+
final Object array = readFieldValue(obj, fieldRecord);
238244
switch (type) {
239245
case BIT_ARRAY: {
240246
assertFieldArray(field);
@@ -279,7 +285,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin
279285
final boolean signed = type == BinType.BYTE_ARRAY;
280286

281287
if (fieldType == String.class) {
282-
final String strValue = (String) readFieldValue(obj, field);
288+
final String strValue = (String) readFieldValue(obj, fieldRecord);
283289
this.onArrayStart(obj, field, annotation, strValue.length());
284290

285291
for (int i = 0; i < strValue.length(); i++) {
@@ -310,7 +316,7 @@ protected void processObjectField(final Object obj, final Field field, final Bin
310316
final boolean signed = type == BinType.SHORT_ARRAY;
311317

312318
if (fieldType == String.class) {
313-
final String str = (String) readFieldValue(obj, field);
319+
final String str = (String) readFieldValue(obj, fieldRecord);
314320
this.onArrayStart(obj, field, annotation, str.length());
315321

316322
for (int i = 0; i < str.length(); i++) {

jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/JBBPMapper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,11 @@ public static List<MappedFieldRecord> findAffectedFields(final Object instance)
365365
final Method fieldGetter = auxMethods.getB();
366366
final Method fieldSetter = auxMethods.getC();
367367

368-
if (fieldSetter == null && Modifier.isPrivate(mappingField.getModifiers())) {
369-
throw new JBBPMapperException("Detected private field, there must be provided setter for mapping", null, processingClazz, mappingField, null);
368+
if (mappingField.getType().isPrimitive() && fieldSetter == null && Modifier.isPrivate(mappingField.getModifiers())) {
369+
throw new JBBPMapperException("Detected private primitive field, mapping requires setter", null, processingClazz, mappingField, null);
370370
}
371371

372-
if (fieldGetter == null && !ReflectUtils.isPotentiallyAccessibleField(mappingField)) {
372+
if (fieldGetter == null && fieldGenerator == null && !ReflectUtils.isPotentiallyAccessibleField(mappingField)) {
373373
mappingField = ReflectUtils.makeAccessible(mappingField);
374374
}
375375

jbbp/src/main/java/com/igormaznitsa/jbbp/mapper/MappedFieldRecord.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@ public final class MappedFieldRecord implements Comparable<MappedFieldRecord> {
124124
} else {
125125
final Object curValue = getFieldValue(instance, record.getter, record.mappingField);
126126
if (curValue == null) {
127-
if (record.classMemberGenerator == null) {
127+
if (record.instanceMaker == null) {
128128
setFieldValue(instance, record.setter, record.mappingField, binField, JBBPMapper.map((JBBPFieldStruct) binField, tryMakeInstance(record.mappingField.getType(), binField, instance, record.mappingField, instantiators), customFieldProcessor));
129129
} else {
130130
try {
131-
JBBPMapper.map((JBBPFieldStruct) binField, record.classMemberGenerator.invoke(instance));
131+
JBBPMapper.map((JBBPFieldStruct) binField, record.instanceMaker.invoke(instance));
132132
} catch (Exception ex) {
133133
throw new JBBPMapperException("Can't map field which member generatet by instance", binField, record.mappingClass, record.mappingField, ex);
134134
}
@@ -156,7 +156,7 @@ public final class MappedFieldRecord implements Comparable<MappedFieldRecord> {
156156
public final Class<?> mappingClass;
157157
public final Method setter;
158158
public final Method getter;
159-
public final Method classMemberGenerator;
159+
public final Method instanceMaker;
160160
public final Bin binAnnotation;
161161
public final boolean bitWideField;
162162
public final String fieldName;
@@ -166,12 +166,12 @@ public final class MappedFieldRecord implements Comparable<MappedFieldRecord> {
166166
public final FieldProcessor proc;
167167

168168
MappedFieldRecord(final Field mappingField,
169-
final Method classMemberGenerator,
169+
final Method instanceMaker,
170170
final Method setter,
171171
final Method getter,
172172
final Class<?> mappingClass,
173173
final Bin binAnnotation) {
174-
this.classMemberGenerator = classMemberGenerator;
174+
this.instanceMaker = instanceMaker;
175175
this.setter = setter;
176176
this.getter = getter;
177177

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.igormaznitsa.jbbp.mapper;
2+
3+
@Bin
4+
public class ClassWithPFGSG {
5+
@Bin(outOrder = 1)
6+
private byte a;
7+
@Bin(outOrder = 2)
8+
private byte b;
9+
@Bin(outOrder = 3)
10+
private Internal i;
11+
12+
public Internal getI() {
13+
return this.i;
14+
}
15+
16+
public byte getA() {
17+
return this.a;
18+
}
19+
20+
public void setA(final byte a) {
21+
this.a = a;
22+
}
23+
24+
public byte getB() {
25+
return this.b;
26+
}
27+
28+
public void setB(final byte b) {
29+
this.b = b;
30+
}
31+
32+
public Internal makeI() {
33+
this.i = new Internal();
34+
return this.i;
35+
}
36+
37+
@Bin
38+
public class Internal {
39+
@Bin(outOrder = 1)
40+
private byte c;
41+
@Bin(outOrder = 2)
42+
private InternalInternal ii;
43+
44+
public byte getC() {
45+
return this.c;
46+
}
47+
48+
public void setC(byte c) {
49+
this.c = c;
50+
}
51+
52+
public InternalInternal getIi() {
53+
return this.ii;
54+
}
55+
56+
public InternalInternal makeIi() {
57+
this.ii = new InternalInternal();
58+
return ii;
59+
}
60+
61+
@Bin
62+
public class InternalInternal {
63+
@Bin(outOrder = 1)
64+
private byte d;
65+
66+
public byte getD() {
67+
return this.d;
68+
}
69+
70+
public void setD(final byte d) {
71+
this.d = d;
72+
}
73+
}
74+
}
75+
76+
}

jbbp/src/test/java/com/igormaznitsa/jbbp/mapper/JBBPMapperTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,20 @@ void testMap_privateFieldWithSetterInPackagelevelClass() throws Exception {
548548
assertEquals(0x1020304, instance.getField());
549549
}
550550

551+
@Test
552+
public void testMap_classWithGettersSettersAndGenerator() throws Exception {
553+
final ClassWithPFGSG instance = JBBPParser.prepare("byte a; byte b; i { byte c; ii { byte d;}}")
554+
.parse(new byte[] {1, 2, 3, 4})
555+
.mapTo(new ClassWithPFGSG());
556+
557+
assertEquals(1, instance.getA());
558+
assertEquals(2, instance.getB());
559+
assertEquals(3, instance.getI().getC());
560+
assertEquals(4, instance.getI().getIi().getD());
561+
562+
assertArrayEquals(new byte[] {1, 2, 3, 4}, JBBPOut.BeginBin().Bin(instance).End().toByteArray());
563+
}
564+
551565
@Test
552566
void testMap_customMappingFields_Class() throws Exception {
553567
final class Mapped {

0 commit comments

Comments
 (0)