Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class JacksonEvent implements Event {

private static final Logger LOG = LoggerFactory.getLogger(JacksonEvent.class);

private static final int FILL_OUT_OF_BOUNDS_ELEMENTS_LIMIT = 0;

private static final String SEPARATOR = "/";

private static final ObjectMapper mapper = JsonMapper.builder()
Expand Down Expand Up @@ -195,8 +197,31 @@ private JsonNode getOrCreateNode(final JsonNode node, final String key) {
JsonNode childNode = node.get(key);
if (childNode == null) {
childNode = mapper.createObjectNode();
((ObjectNode) node).set(key, childNode);
if (node.isArray()) {
int index = Integer.parseInt(key);
ArrayNode arrayNode = (ArrayNode) node;

int distanceFromArrayEnd = index - arrayNode.size();
if (distanceFromArrayEnd >= FILL_OUT_OF_BOUNDS_ELEMENTS_LIMIT + 1) {
throw new IndexOutOfBoundsException(
String.format("Cannot expand array past the limit of size %s to reach index %s", arrayNode.size(), index));
}
while (arrayNode.size() <= index) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test case for this?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think we should limit the number new null nodes can be added.

arrayNode.addNull();
}
Comment on lines +209 to +211

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to fill nulls? You have null check in the below logic anyway right?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided to not allow extending the size of array by filling nulls. We will allow at most one more entry beyond the current size


JsonNode existing = arrayNode.get(index);
if (existing == null || !existing.isObject()) {
childNode = mapper.createObjectNode();
arrayNode.set(index, childNode);
} else {
childNode = existing;
}
} else {
((ObjectNode) node).set(key, childNode);
}
}

return childNode;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -147,6 +148,81 @@ void testPutAndGet_withStrings_eventKey(final String key) {
assertThat(result, is(equalTo(value)));
}

@Test
void testPutAndGet_withArrays_eventKey() {

final String key = "list-key/0/foo";
final String newValue = UUID.randomUUID().toString();

final List<Map<String, Object>> listValue = new ArrayList<>();
final Map<String, Object> mapValue = Map.of("foo", "bar", "foo-2", "bar-2");
listValue.add(mapValue);

final String listKey = "list-key";
final EventKey eventKey = new JacksonEventKey(listKey);
event.put(eventKey, listValue);

final Map<String, Object> expectedMap = new HashMap<>();
expectedMap.put(listKey, listValue);

assertThat(event.toMap(), equalTo(expectedMap));

final EventKey eventNestedKey = new JacksonEventKey(key);
event.put(eventNestedKey, newValue);

final List<Map<String, Object>> newlistValue = new ArrayList<>();
final Map<String, Object> newMapValue = Map.of("foo", newValue, "foo-2", "bar-2");
newlistValue.add(newMapValue);

expectedMap.put(listKey, newlistValue);

assertThat(event.toMap(), equalTo(expectedMap));


final List<Map<String, Object>> result = event.get(listKey, List.class);
assertThat(result, equalTo(newlistValue));

final String resultValue = event.get(key, String.class);
assertThat(resultValue, equalTo(newValue));
}

@Test
void testPutAndGet_withArrays_out_of_bounds_on_end_of_list_creates_new_element() {

final String key = "list-key/1/foo";
final String fooValue = UUID.randomUUID().toString();

final List<Map<String, Object>> listValue = new ArrayList<>();
final Map<String, Object> mapValue = Map.of("foo", "bar", "foo-2", "bar-2");
listValue.add(mapValue);

final String listKey = "list-key";
final EventKey eventKey = new JacksonEventKey(listKey);
event.put(eventKey, listValue);

event.put(key, fooValue);

final String resultValue = event.get(key, String.class);
assertThat(resultValue, equalTo(fooValue));
}

@Test
void testPutAndGet_withArrays_out_of_bounds_throws_IndexOutOfBoundsException() {

final String key = "list-key/3/foo";
final String fooValue = UUID.randomUUID().toString();

final List<Map<String, Object>> listValue = new ArrayList<>();
final Map<String, Object> mapValue = Map.of("foo", "bar", "foo-2", "bar-2");
listValue.add(mapValue);

final String listKey = "list-key";
final EventKey eventKey = new JacksonEventKey(listKey);
event.put(eventKey, listValue);

assertThrows(IndexOutOfBoundsException.class, () -> event.put(key, fooValue));
}

@Test
public void testPutKeyCannotBeEmptyString() {
Throwable exception = assertThrows(IllegalArgumentException.class, () -> event.put("", "value"));
Expand Down Expand Up @@ -1117,5 +1193,4 @@ private static Stream<Arguments> getBigDecimalPutTestData() {
Arguments.of("1.000")
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,40 @@ void testEmptyKeyConvertEntryTypeProcessor() {
when(mockConfig.getKey()).thenReturn("");
assertThrows(IllegalArgumentException.class, () -> new ConvertEntryTypeProcessor(pluginMetrics, mockConfig, expressionEvaluator));
}

@Test
void convert_type_on_value_in_array_element_converts_correctly() {
final String eventKey = "list-key/0/foo";

when(mockConfig.getType()).thenReturn(TargetType.fromOptionValue("long"));
when(mockConfig.getKey()).thenReturn(eventKey);

typeConversionProcessor = new ConvertEntryTypeProcessor(pluginMetrics, mockConfig, expressionEvaluator);

final Map<String, Object> eventData = new HashMap<>();

final List<Map<String, Object>> listElement = new ArrayList<>();
listElement.add(Map.of("foo", 10.0));

eventData.put("list-key", listElement);

final Event event = JacksonEvent.builder()
.withData(eventData)
.withEventType("event")
.build();

final List<Record<Event>> processedRecords = (List<Record<Event>>) typeConversionProcessor.doExecute(Collections.singletonList(new Record<>(event)));
assertThat(processedRecords.size(), equalTo(1));

final Event resultEvent = processedRecords.get(0).getData();

final Map<String, Object> resultEventData = resultEvent.toMap();

final Map<String, Object> expectedEventData = new HashMap<>();
final List<Map<String, Object>> expectedListElement = new ArrayList<>();
expectedListElement.add(Map.of("foo", 10L));
expectedEventData.put("list-key", expectedListElement);

assertThat(resultEventData, equalTo(expectedEventData));
}
}
Loading