Skip to content

Normalize Slack form element presentational data | Attempt 2#258

Merged
omotnyk merged 2 commits intomasterfrom
normalize_data_before_validation
Dec 8, 2021
Merged

Normalize Slack form element presentational data | Attempt 2#258
omotnyk merged 2 commits intomasterfrom
normalize_data_before_validation

Conversation

@omotnyk
Copy link
Copy Markdown
Contributor

@omotnyk omotnyk commented Dec 7, 2021

Same as #256 but fixed stackoverflow error during normalization caused by cyclic constructor calls in with methods.

@omotnyk omotnyk force-pushed the normalize_data_before_validation branch from f86d507 to e923f50 Compare December 7, 2021 19:24
Comment on lines +31 to +36
return SlackFormTextElement.builder()
.from(element)
.setPlaceholder(normalizePlaceholder(element))
.setLabel(normalizeLabel(element))
.setHint(normalizeHint(element))
.build();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Replaced with calls with builder here.

Comment on lines +45 to +50
return SlackFormTextareaElement.builder()
.from(element)
.setPlaceholder(normalizePlaceholder(element))
.setLabel(normalizeLabel(element))
.setHint(normalizeHint(element))
.build();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Replaced with calls with builder here.

Comment on lines +60 to +66
return SlackFormSelectElement.builder()
.from(element)
.setPlaceholder(normalizePlaceholder(element))
.setLabel(normalizeLabel(element))
.setOptionGroups(normalizeOptionGroups(element))
.setOptions(normalizeOptions(element))
.build();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Replaced with calls with builder here.

Comment on lines +56 to +66
if (shouldNormalizePlaceholder(element)
|| shouldNormalizeLabel(element, SlackDialogFormElementLengthLimits.MAX_LABEL_LENGTH)
|| shouldNormalize(element.getOptionGroups(), SlackDialogFormElementLengthLimits.MAX_OPTION_GROUPS_NUMBER)
|| shouldNormalizeOptions(element)) {
return SlackFormSelectElement.builder()
.from(element)
.setPlaceholder(normalizePlaceholder(element))
.setLabel(normalizeLabel(element))
.setOptionGroups(normalizeOptionGroups(element))
.setOptions(normalizeOptions(element))
.build();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll describe the stack overflow problem with an example. Let's say we have the old code here:

    if (shouldNormalizePlaceholder(element)
        || shouldNormalizeLabel(element, SlackDialogFormElementLengthLimits.MAX_LABEL_LENGTH)
        || shouldNormalize(element.getHint(), SlackDialogFormElementLengthLimits.MAX_HINT_LENGTH)) {
      return SlackFormTextElement.copyOf(element)
          .withPlaceholder(normalizePlaceholder(element))
          .withLabel(normalizeLabel(element))
          .withHint(normalizeHint(element));
    }
    return element;

What we do here is define whether we should normalize any data first and then normalize it. The problem is actually obvious but still tricky. Let's say we have a very long label that should be normalized. In this case, when SlackFormSelectElement is created we do next:

  1. Check if we should normalize any field.
  2. Determine that we should normalize some fields(label).
  3. Start normalization process:
    1. Normalize placeholer and then call withPlaceholder.
    2. Normalize label and then call withLabel.
    3. Normalize the rest.
    4. Build the final normalized object.

The flow I described above is what I think is happening. What was actually happening is we were entering an endless loop upon calling withPlaceholder because unlike builder, this method creates the actual SlackFormSelectElement so it calls method annotated with @Value.Check, which then initiates the normalization process once again. SInce we didn't normalize the label yet, we determine that label still has to be normalized and run SlackFormTextElement.copyOf(element).withPlaceholder(normalizePlaceholder(element)).withLabel(normalizeLabel(element)) once again, which results in doing this again, and then again, and again.

This issue wasn't caught at first because it depends on the order of the checks and normalization as well as on the data to be normalized. If we place withLabel before withPlaceholder and try to build the object with a long label, everything works fine because on the call to withLabel method we have a fully normalized object that passes all the checks.

Copy link
Copy Markdown
Contributor

@zmarushchak-hs zmarushchak-hs left a comment

Choose a reason for hiding this comment

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

LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants