Skip to content

Commit fde5aab

Browse files
committed
✨ add typed accessors to list and object fields
1 parent 60b77e9 commit fde5aab

File tree

4 files changed

+194
-24
lines changed

4 files changed

+194
-24
lines changed

src/main/java/com/mindee/parsing/v2/field/ListField.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44
import com.fasterxml.jackson.annotation.JsonProperty;
5+
6+
import java.util.ArrayList;
57
import java.util.List;
68
import java.util.StringJoiner;
79
import lombok.AllArgsConstructor;
@@ -25,6 +27,40 @@ public final class ListField extends BaseField {
2527
@JsonProperty("items")
2628
private List<DynamicField> items;
2729

30+
/**
31+
* Retrieves the {@code items} as {@code SimpleField} objects.
32+
*
33+
* @return a list of {@code SimpleField} objects
34+
* @throws IllegalStateException if any dynamic field in the list is not of type {@code SIMPLE_FIELD}
35+
*/
36+
public List<SimpleField> getSimpleItems() throws IllegalStateException {
37+
List<SimpleField> simpleItems = new ArrayList<>();
38+
39+
if (items != null) {
40+
for (DynamicField item : items) {
41+
simpleItems.add(item.getSimpleField());
42+
}
43+
}
44+
return simpleItems;
45+
}
46+
47+
/**
48+
* Retrieves the {@code items} as {@code ObjectField} objects.
49+
*
50+
* @return a list of {@code ObjectField} objects
51+
* @throws IllegalStateException if any dynamic field in the list is not of type {@code OBJECT_FIELD}
52+
*/
53+
public List<ObjectField> getObjectItems() throws IllegalStateException {
54+
List<ObjectField> objectItems = new ArrayList<>();
55+
56+
if (items != null) {
57+
for (DynamicField item : items) {
58+
objectItems.add(item.getObjectField());
59+
}
60+
}
61+
return objectItems;
62+
}
63+
2864
@Override
2965
public String toString() {
3066
if (items == null || items.isEmpty()) {

src/main/java/com/mindee/parsing/v2/field/ObjectField.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import lombok.EqualsAndHashCode;
77
import lombok.Getter;
88
import lombok.NoArgsConstructor;
9+
import java.util.LinkedHashMap;
910

1011
/**
1112
* Field holding a map of sub-fields.
@@ -23,6 +24,21 @@ public class ObjectField extends BaseField {
2324
@JsonProperty("fields")
2425
private InferenceFields fields;
2526

27+
/**
28+
* Retrieves all sub-fields from the {@code fields} map as a {@link LinkedHashMap} of
29+
* {@code SimpleField} objects, keyed by their field names.
30+
*
31+
* @return a {@link LinkedHashMap} containing the field names as keys and their corresponding
32+
* {@code SimpleField} instances as values
33+
*/
34+
public LinkedHashMap<String, SimpleField> getSimpleFields() {
35+
LinkedHashMap<String, SimpleField> simpleFields = new LinkedHashMap<>();
36+
for (String fieldName : fields.keySet()) {
37+
simpleFields.put(fieldName, fields.getSimpleField(fieldName));
38+
}
39+
return simpleFields;
40+
}
41+
2642
@Override
2743
public String toString() {
2844
return "\n" + (fields != null ? fields.toString(1) : "");

src/main/java/com/mindee/parsing/v2/field/SimpleField.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,35 @@ public SimpleField(Object value, FieldConfidence confidence, List<FieldLocation>
2727
this.value = value;
2828
}
2929

30+
/**
31+
* Retrieves the value of the field as a string.
32+
*
33+
* @return the field value as a string
34+
* @throws ClassCastException if the value cannot be cast to a string
35+
*/
36+
public String getStringValue() throws ClassCastException {
37+
return (String) value;
38+
}
39+
40+
/**
41+
* Retrieves the value of the field as a Double.
42+
*
43+
* @return the field value as a Double
44+
* @throws ClassCastException if the value cannot be cast to a Double
45+
*/
46+
public Double getDoubleValue() throws ClassCastException {
47+
return (Double) value;
48+
}
49+
50+
/**
51+
* Retrieves the value of the field as a Boolean.
52+
*
53+
* @return the field value as a Boolean
54+
* @throws ClassCastException if the value cannot be cast to a Boolean
55+
*/
56+
public Boolean getBooleanValue() throws ClassCastException {
57+
return (Boolean) value;
58+
}
3059

3160
@Override
3261
public String toString() {

src/test/java/com/mindee/parsing/v2/InferenceTest.java

Lines changed: 113 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.mindee.parsing.v2.field.ObjectField;
1313
import com.mindee.parsing.v2.field.DynamicField.FieldType;
1414
import java.io.IOException;
15+
import java.util.HashMap;
1516
import java.util.List;
1617
import java.util.Map;
1718
import java.util.Objects;
@@ -189,8 +190,8 @@ void deepNestedFields_mustExposeCorrectTypes() throws IOException {
189190
class StandardFieldTypes {
190191

191192
@Test
192-
@DisplayName("simple / object / list variants must be recognised")
193-
void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
193+
@DisplayName("simple fields must be recognised")
194+
void standardFieldTypes_mustExposeSimpleFieldValues() throws IOException {
194195
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
195196
Inference inference = response.getInference();
196197
assertNotNull(inference);
@@ -202,18 +203,25 @@ void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
202203
SimpleField fieldSimpleString = fields.get("field_simple_string").getSimpleField();
203204
assertNotNull(fieldSimpleString);
204205
assertInstanceOf(String.class, fieldSimpleString.getValue());
206+
assertEquals(fieldSimpleString.getValue(), fieldSimpleString.getStringValue());
207+
assertThrows(ClassCastException.class, fieldSimpleString::getDoubleValue);
208+
assertThrows(ClassCastException.class, fieldSimpleString::getBooleanValue);
205209
assertEquals(FieldConfidence.Certain, fieldSimpleString.getConfidence());
206210
assertInstanceOf(List.class, fieldSimpleString.getLocations());
207211
assertEquals(1, fieldSimpleString.getLocations().size());
208212

209213
SimpleField fieldSimpleFloat = fields.get("field_simple_float").getSimpleField();
210214
assertNotNull(fieldSimpleFloat);
211215
assertInstanceOf(Double.class, fieldSimpleFloat.getValue());
216+
assertEquals(fieldSimpleFloat.getValue(), fieldSimpleFloat.getDoubleValue());
217+
assertThrows(ClassCastException.class, fieldSimpleFloat::getStringValue);
218+
assertThrows(ClassCastException.class, fieldSimpleFloat::getBooleanValue);
212219
assertEquals(FieldConfidence.High, fieldSimpleFloat.getConfidence());
213220

214221
SimpleField fieldSimpleInt = fields.get("field_simple_int").getSimpleField();
215222
assertNotNull(fieldSimpleInt);
216223
assertInstanceOf(Double.class, fieldSimpleInt.getValue());
224+
assertEquals(fieldSimpleInt.getValue(), fieldSimpleInt.getDoubleValue());
217225
assertEquals(FieldConfidence.Medium, fieldSimpleInt.getConfidence());
218226

219227
SimpleField fieldSimpleZero = fields.get("field_simple_zero").getSimpleField();
@@ -224,47 +232,128 @@ void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
224232
SimpleField fieldSimpleBool = fields.get("field_simple_bool").getSimpleField();
225233
assertNotNull(fieldSimpleBool);
226234
assertInstanceOf(Boolean.class, fieldSimpleBool.getValue());
235+
assertEquals(fieldSimpleBool.getValue(), fieldSimpleBool.getBooleanValue());
236+
assertThrows(ClassCastException.class, fieldSimpleBool::getStringValue);
237+
assertThrows(ClassCastException.class, fieldSimpleBool::getDoubleValue);
227238

228239
SimpleField fieldSimpleNull = fields.get("field_simple_null").getSimpleField();
229240
assertNotNull(fieldSimpleNull);
230241
assertNull(fieldSimpleNull.getValue());
242+
assertNull(fieldSimpleNull.getStringValue());
243+
assertNull(fieldSimpleNull.getBooleanValue());
244+
assertNull(fieldSimpleNull.getDoubleValue());
245+
}
246+
247+
@Test
248+
@DisplayName("simple list fields must be recognised")
249+
void standardFieldTypes_mustExposeSimpleListFieldValues() throws IOException {
250+
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
251+
Inference inference = response.getInference();
252+
assertNotNull(inference);
253+
254+
InferenceFields fields = inference.getResult().getFields();
231255

232-
ListField fieldSimpleList = fields.get("field_simple_list").getListField();
233-
assertNotNull(fieldSimpleList);
234-
List<DynamicField> simpleItems = fieldSimpleList.getItems();
256+
ListField listField = fields.get("field_simple_list").getListField();
257+
assertNotNull(listField);
258+
259+
// Low level (dynamic) access
260+
List<DynamicField> dynamicItems = listField.getItems();
261+
assertEquals(2, dynamicItems.size());
262+
SimpleField firstDynamicItem = dynamicItems.get(0).getSimpleField();
263+
assertNotNull(firstDynamicItem);
264+
assertEquals(FieldConfidence.Medium, firstDynamicItem.getConfidence());
265+
assertInstanceOf(String.class, firstDynamicItem.getValue());
266+
for (DynamicField item : dynamicItems) {
267+
SimpleField itemField = item.getSimpleField();
268+
assertInstanceOf(String.class, itemField.getValue());
269+
assertEquals(itemField.getValue(), itemField.getStringValue());
270+
assertEquals(1, itemField.getLocations().size());
271+
}
272+
273+
// High level (typed) access
274+
List<SimpleField> simpleItems = listField.getSimpleItems();
235275
assertEquals(2, simpleItems.size());
236-
SimpleField firstSimpleItem = simpleItems.get(0).getSimpleField();
237-
assertNotNull(firstSimpleItem);
276+
SimpleField firstSimpleItem = simpleItems.get(0);
238277
assertEquals(FieldConfidence.Medium, firstSimpleItem.getConfidence());
239-
assertInstanceOf(String.class, firstSimpleItem.getValue());
240-
for (DynamicField item : fieldSimpleList.getItems()) {
241-
SimpleField itemField = item.getSimpleField();
278+
for (SimpleField itemField : simpleItems) {
242279
assertInstanceOf(String.class, itemField.getValue());
280+
assertEquals(itemField.getValue(), itemField.getStringValue());
243281
assertEquals(1, itemField.getLocations().size());
244282
}
245283

284+
assertThrows(IllegalStateException.class, listField::getObjectItems);
285+
}
286+
287+
@Test
288+
@DisplayName("object list fields must be recognised")
289+
void standardFieldTypes_mustExposeObjectListFieldValues() throws IOException {
290+
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
291+
Inference inference = response.getInference();
292+
assertNotNull(inference);
293+
294+
InferenceFields fields = inference.getResult().getFields();
295+
296+
ListField listField = fields.get("field_object_list").getListField();
297+
assertNotNull(listField);
298+
299+
List<DynamicField> dynamicItems = listField.getItems();
300+
assertEquals(2, dynamicItems.size());
301+
ObjectField firstDynamicItem = dynamicItems.get(0).getObjectField();
302+
assertEquals(
303+
FieldConfidence.Low,
304+
firstDynamicItem.getFields().get("subfield_1").getSimpleField().getConfidence()
305+
);
306+
for (DynamicField item : dynamicItems) {
307+
ObjectField itemField = item.getObjectField();
308+
assertNotNull(itemField);
309+
InferenceFields itemFields = itemField.getFields();
310+
assertEquals(2, itemFields.size());
311+
}
312+
313+
List<ObjectField> objectItems = listField.getObjectItems();
314+
assertEquals(2, objectItems.size());
315+
ObjectField firstObjectItem = objectItems.get(0);
316+
assertEquals(
317+
FieldConfidence.Low,
318+
firstObjectItem.getSimpleFields().get("subfield_1").getConfidence()
319+
);
320+
for (ObjectField itemField : objectItems) {
321+
assertNotNull(itemField);
322+
HashMap<String, SimpleField> itemFields = itemField.getSimpleFields();
323+
assertEquals(2, itemFields.size());
324+
InferenceFields itemSubFields = itemField.getFields();
325+
SimpleField itemSubfield1 = itemSubFields.getSimpleField("subfield_1");
326+
assertInstanceOf(String.class, itemSubfield1.getValue());
327+
for (Map.Entry<String, SimpleField> entry : itemFields.entrySet()) {
328+
SimpleField subfield = entry.getValue();
329+
assertEquals(subfield.getValue(), subfield.getStringValue());
330+
}
331+
}
332+
333+
assertThrows(IllegalStateException.class, listField::getSimpleItems);
334+
}
335+
336+
@Test
337+
@DisplayName("simple / object / list variants must be recognised")
338+
void standardFieldTypes_mustExposeObjectFieldValues() throws IOException {
339+
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
340+
Inference inference = response.getInference();
341+
assertNotNull(inference);
342+
343+
InferenceFields fields = inference.getResult().getFields();
344+
246345
ObjectField fieldObject = fields.get("field_object").getObjectField();
247346
assertNotNull(fieldObject);
248347
InferenceFields fieldObjectFields = fieldObject.getFields();
348+
249349
assertEquals(2, fieldObjectFields.size());
250350
SimpleField subfield1 = fieldObjectFields.get("subfield_1").getSimpleField();
251351
assertInstanceOf(String.class, subfield1.getValue());
252352
assertEquals(FieldConfidence.High, subfield1.getConfidence());
253353

254-
ListField fieldObjectList = fields.get("field_object_list").getListField();
255-
assertNotNull(fieldObjectList);
256-
List<DynamicField> objectItems = fieldObjectList.getItems();
257-
assertEquals(2, objectItems.size());
258-
ObjectField firstObjectItem = objectItems.get(0).getObjectField();
259-
assertNotNull(firstObjectItem);
260-
assertInstanceOf(
261-
String.class,
262-
firstObjectItem.getFields().get("subfield_1").getSimpleField().getValue()
263-
);
264-
for (DynamicField item : fieldObjectList.getItems()) {
265-
SimpleField listSubfield1 = item.getObjectField().getFields().get("subfield_1").getSimpleField();
266-
assertInstanceOf(String.class, listSubfield1.getValue());
267-
assertEquals(1, listSubfield1.getLocations().size());
354+
for (Map.Entry<String, DynamicField> entry : fieldObjectFields.entrySet()) {
355+
String fieldName = entry.getKey();
356+
SimpleField subField = entry.getValue().getSimpleField();
268357
}
269358
}
270359
}

0 commit comments

Comments
 (0)