Skip to content

Commit 66643b2

Browse files
authored
✨ add typed accessors to list and object fields (#268)
1 parent 60b77e9 commit 66643b2

File tree

4 files changed

+222
-34
lines changed

4 files changed

+222
-34
lines changed

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

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

33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import java.util.ArrayList;
56
import java.util.List;
67
import java.util.StringJoiner;
78
import lombok.AllArgsConstructor;
@@ -25,6 +26,38 @@ public final class ListField extends BaseField {
2526
@JsonProperty("items")
2627
private List<DynamicField> items;
2728

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

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

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

33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import java.util.LinkedHashMap;
56
import lombok.AllArgsConstructor;
67
import lombok.EqualsAndHashCode;
78
import lombok.Getter;
@@ -23,6 +24,24 @@ 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+
* @throws IllegalStateException if any field is not of type {@code SIMPLE_FIELD}
34+
*/
35+
public LinkedHashMap<String, SimpleField> getSimpleFields() throws IllegalStateException {
36+
LinkedHashMap<String, SimpleField> simpleFields = new LinkedHashMap<>();
37+
if (fields != null) {
38+
for (String fieldName : fields.keySet()) {
39+
simpleFields.put(fieldName, fields.getSimpleField(fieldName));
40+
}
41+
}
42+
return simpleFields;
43+
}
44+
2645
@Override
2746
public String toString() {
2847
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: 141 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
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;
16+
import java.util.LinkedHashMap;
1517
import java.util.List;
1618
import java.util.Map;
1719
import java.util.Objects;
@@ -188,9 +190,17 @@ void deepNestedFields_mustExposeCorrectTypes() throws IOException {
188190
@DisplayName("standard_field_types.json")
189191
class StandardFieldTypes {
190192

193+
private void testSimpleFieldString(SimpleField field) {
194+
assertNotNull(field);
195+
assertEquals(field.getValue(), field.getStringValue());
196+
assertThrows(ClassCastException.class, field::getDoubleValue);
197+
assertThrows(ClassCastException.class, field::getBooleanValue);
198+
assertInstanceOf(List.class, field.getLocations());
199+
}
200+
191201
@Test
192-
@DisplayName("simple / object / list variants must be recognised")
193-
void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
202+
@DisplayName("simple fields must be recognised")
203+
void standardFieldTypes_mustExposeSimpleFieldValues() throws IOException {
194204
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
195205
Inference inference = response.getInference();
196206
assertNotNull(inference);
@@ -200,20 +210,22 @@ void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
200210
assertNotNull(fields.get("field_simple_string").getSimpleField());
201211

202212
SimpleField fieldSimpleString = fields.get("field_simple_string").getSimpleField();
203-
assertNotNull(fieldSimpleString);
204-
assertInstanceOf(String.class, fieldSimpleString.getValue());
213+
testSimpleFieldString(fieldSimpleString);
205214
assertEquals(FieldConfidence.Certain, fieldSimpleString.getConfidence());
206-
assertInstanceOf(List.class, fieldSimpleString.getLocations());
207215
assertEquals(1, fieldSimpleString.getLocations().size());
208216

209217
SimpleField fieldSimpleFloat = fields.get("field_simple_float").getSimpleField();
210218
assertNotNull(fieldSimpleFloat);
211219
assertInstanceOf(Double.class, fieldSimpleFloat.getValue());
220+
assertEquals(fieldSimpleFloat.getValue(), fieldSimpleFloat.getDoubleValue());
221+
assertThrows(ClassCastException.class, fieldSimpleFloat::getStringValue);
222+
assertThrows(ClassCastException.class, fieldSimpleFloat::getBooleanValue);
212223
assertEquals(FieldConfidence.High, fieldSimpleFloat.getConfidence());
213224

214225
SimpleField fieldSimpleInt = fields.get("field_simple_int").getSimpleField();
215226
assertNotNull(fieldSimpleInt);
216227
assertInstanceOf(Double.class, fieldSimpleInt.getValue());
228+
assertEquals(fieldSimpleInt.getValue(), fieldSimpleInt.getDoubleValue());
217229
assertEquals(FieldConfidence.Medium, fieldSimpleInt.getConfidence());
218230

219231
SimpleField fieldSimpleZero = fields.get("field_simple_zero").getSimpleField();
@@ -224,47 +236,142 @@ void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
224236
SimpleField fieldSimpleBool = fields.get("field_simple_bool").getSimpleField();
225237
assertNotNull(fieldSimpleBool);
226238
assertInstanceOf(Boolean.class, fieldSimpleBool.getValue());
239+
assertEquals(fieldSimpleBool.getValue(), fieldSimpleBool.getBooleanValue());
240+
assertThrows(ClassCastException.class, fieldSimpleBool::getStringValue);
241+
assertThrows(ClassCastException.class, fieldSimpleBool::getDoubleValue);
227242

228243
SimpleField fieldSimpleNull = fields.get("field_simple_null").getSimpleField();
229244
assertNotNull(fieldSimpleNull);
230245
assertNull(fieldSimpleNull.getValue());
246+
assertNull(fieldSimpleNull.getStringValue());
247+
assertNull(fieldSimpleNull.getBooleanValue());
248+
assertNull(fieldSimpleNull.getDoubleValue());
249+
}
250+
251+
@Test
252+
@DisplayName("simple list fields must be recognised")
253+
void standardFieldTypes_mustExposeSimpleListFieldValues() throws IOException {
254+
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
255+
Inference inference = response.getInference();
256+
assertNotNull(inference);
257+
258+
InferenceFields fields = inference.getResult().getFields();
259+
260+
ListField listField = fields.get("field_simple_list").getListField();
261+
assertNotNull(listField);
262+
263+
// Low level (dynamic) access
264+
List<DynamicField> dynamicItems = listField.getItems();
265+
assertEquals(2, dynamicItems.size());
266+
SimpleField firstDynamicItem = dynamicItems.get(0).getSimpleField();
267+
assertNotNull(firstDynamicItem);
268+
assertEquals(FieldConfidence.Medium, firstDynamicItem.getConfidence());
269+
assertInstanceOf(String.class, firstDynamicItem.getValue());
270+
for (DynamicField item : dynamicItems) {
271+
SimpleField itemField = item.getSimpleField();
272+
testSimpleFieldString(itemField);
273+
assertEquals(1, itemField.getLocations().size());
274+
}
231275

232-
ListField fieldSimpleList = fields.get("field_simple_list").getListField();
233-
assertNotNull(fieldSimpleList);
234-
List<DynamicField> simpleItems = fieldSimpleList.getItems();
276+
// High level (typed) access
277+
List<SimpleField> simpleItems = listField.getSimpleItems();
235278
assertEquals(2, simpleItems.size());
236-
SimpleField firstSimpleItem = simpleItems.get(0).getSimpleField();
237-
assertNotNull(firstSimpleItem);
279+
SimpleField firstSimpleItem = simpleItems.get(0);
238280
assertEquals(FieldConfidence.Medium, firstSimpleItem.getConfidence());
239-
assertInstanceOf(String.class, firstSimpleItem.getValue());
240-
for (DynamicField item : fieldSimpleList.getItems()) {
241-
SimpleField itemField = item.getSimpleField();
242-
assertInstanceOf(String.class, itemField.getValue());
281+
for (SimpleField itemField : simpleItems) {
282+
testSimpleFieldString(itemField);
243283
assertEquals(1, itemField.getLocations().size());
244284
}
245285

246-
ObjectField fieldObject = fields.get("field_object").getObjectField();
247-
assertNotNull(fieldObject);
248-
InferenceFields fieldObjectFields = fieldObject.getFields();
249-
assertEquals(2, fieldObjectFields.size());
250-
SimpleField subfield1 = fieldObjectFields.get("subfield_1").getSimpleField();
251-
assertInstanceOf(String.class, subfield1.getValue());
252-
assertEquals(FieldConfidence.High, subfield1.getConfidence());
253-
254-
ListField fieldObjectList = fields.get("field_object_list").getListField();
255-
assertNotNull(fieldObjectList);
256-
List<DynamicField> objectItems = fieldObjectList.getItems();
286+
assertThrows(IllegalStateException.class, listField::getObjectItems);
287+
}
288+
289+
private void testObjectSubFieldSimpleString(String fieldName, SimpleField subField) {
290+
assertTrue(fieldName.startsWith("subfield_"));
291+
testSimpleFieldString(subField);
292+
}
293+
294+
@Test
295+
@DisplayName("object list fields must be recognised")
296+
void standardFieldTypes_mustExposeObjectListFieldValues() throws IOException {
297+
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
298+
Inference inference = response.getInference();
299+
assertNotNull(inference);
300+
301+
InferenceFields fields = inference.getResult().getFields();
302+
303+
ListField listField = fields.get("field_object_list").getListField();
304+
assertNotNull(listField);
305+
306+
List<DynamicField> dynamicItems = listField.getItems();
307+
assertEquals(2, dynamicItems.size());
308+
ObjectField firstDynamicItem = dynamicItems.get(0).getObjectField();
309+
assertEquals(
310+
FieldConfidence.Low,
311+
firstDynamicItem.getFields().get("subfield_1").getSimpleField().getConfidence()
312+
);
313+
for (DynamicField item : dynamicItems) {
314+
ObjectField itemField = item.getObjectField();
315+
assertNotNull(itemField);
316+
InferenceFields itemFields = itemField.getFields();
317+
assertEquals(2, itemFields.size());
318+
}
319+
320+
List<ObjectField> objectItems = listField.getObjectItems();
257321
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()
322+
ObjectField firstObjectItem = objectItems.get(0);
323+
assertEquals(
324+
FieldConfidence.Low,
325+
firstObjectItem.getSimpleFields().get("subfield_1").getConfidence()
263326
);
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());
327+
for (ObjectField itemField : objectItems) {
328+
assertNotNull(itemField);
329+
HashMap<String, SimpleField> itemFields = itemField.getSimpleFields();
330+
assertEquals(2, itemFields.size());
331+
InferenceFields itemSubFields = itemField.getFields();
332+
SimpleField itemSubfield1 = itemSubFields.getSimpleField("subfield_1");
333+
assertInstanceOf(String.class, itemSubfield1.getValue());
334+
for (Map.Entry<String, SimpleField> entry : itemFields.entrySet()) {
335+
String fieldName = entry.getKey();
336+
SimpleField subfield = entry.getValue();
337+
testObjectSubFieldSimpleString(fieldName, subfield);
338+
}
339+
}
340+
341+
assertThrows(IllegalStateException.class, listField::getSimpleItems);
342+
}
343+
344+
@Test
345+
@DisplayName("simple / object / list variants must be recognised")
346+
void standardFieldTypes_mustExposeObjectFieldValues() throws IOException {
347+
InferenceResponse response = loadFromResource("v2/inference/standard_field_types.json");
348+
Inference inference = response.getInference();
349+
assertNotNull(inference);
350+
351+
InferenceFields fields = inference.getResult().getFields();
352+
353+
ObjectField fieldObject = fields.get("field_object").getObjectField();
354+
assertNotNull(fieldObject);
355+
356+
InferenceFields subFieldsDynamic = fieldObject.getFields();
357+
assertEquals(2, subFieldsDynamic.size());
358+
SimpleField dynamicSubfield1 = subFieldsDynamic.get("subfield_1").getSimpleField();
359+
assertInstanceOf(String.class, dynamicSubfield1.getValue());
360+
assertEquals(FieldConfidence.High, dynamicSubfield1.getConfidence());
361+
for (Map.Entry<String, DynamicField> entry : subFieldsDynamic.entrySet()) {
362+
String fieldName = entry.getKey();
363+
SimpleField subField = entry.getValue().getSimpleField();
364+
testObjectSubFieldSimpleString(fieldName, subField);
365+
}
366+
367+
LinkedHashMap<String, SimpleField> subFieldsSimple = fieldObject.getSimpleFields();
368+
assertEquals(2, subFieldsSimple.size());
369+
SimpleField simpleSubfield1 = subFieldsSimple.get("subfield_1");
370+
assertEquals(FieldConfidence.High, simpleSubfield1.getConfidence());
371+
for (Map.Entry<String, SimpleField> entry : subFieldsSimple.entrySet()) {
372+
String fieldName = entry.getKey();
373+
SimpleField subField = entry.getValue();
374+
testObjectSubFieldSimpleString(fieldName, subField);
268375
}
269376
}
270377
}

0 commit comments

Comments
 (0)