Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse composite patterns using ClassicFormat.parseObject backport(#40100) #40503

Merged
merged 6 commits into from
Apr 4, 2019

Conversation

pgomulka
Copy link
Contributor

Java-time fails parsing composite patterns when first pattern matches only the prefix of the input. It expects pattern in longest to shortest order. Because of this constructing just one DateTimeFormatter with appendOptional is not sufficient. Parsers have to be iterated and if the parsing fails, the next one in order should be used. In order to not degrade performance parsing should not be throw exceptions on failure. Format.parseObject was used as it only returns null when parsing failed and allows to check if full input was read.

closes #39916
backport #40100

@pgomulka pgomulka added >bug :Core/Infra/Core Core issues without another label backport labels Mar 27, 2019
@pgomulka pgomulka self-assigned this Mar 27, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra

Java-time fails parsing composite patterns when first pattern matches only the prefix of the input. It expects pattern in longest to shortest order. Because of this constructing just one DateTimeFormatter with appendOptional is not sufficient. Parsers have to be iterated and if the parsing fails, the next one in order should be used. In order to not degrade performance parsing should not be throw exceptions on failure. Format.parseObject was used as it only returns null when parsing failed and allows to check if full input was read.

closes elastic#39916
return (TemporalAccessor) object;
}
}
throw new DateTimeParseException("Failed to parse with all enclosed parsers", input, 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because we iterate over parsers we would not know exact failure reason for each parsers. Tests that assert about the exact reason (like position where it failed) had to be changed

Copy link
Member

@danielmitterdorfer danielmitterdorfer left a comment

Choose a reason for hiding this comment

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

Thanks! Looks mostly fine but I left a few minor comments.

try {
return doParse(input);
} catch (DateTimeParseException e) {
throw new IllegalArgumentException("failed to parse date field [" + input + "] with format [" + format + "]", e);
Copy link
Member

Choose a reason for hiding this comment

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

This means that this method will never throw DateTimeParseException as mentioned in the Javadoc of DateFormatter#parse. Can you please update the Javadoc there to reflect this change?

Copy link
Contributor Author

@pgomulka pgomulka Apr 2, 2019

Choose a reason for hiding this comment

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

Actually the javadoc for the interface could state RuntimeException to be absolutely correct, but it would be very imprecise.

  • JodaDateFormatter can throw java.time.DateTimeException as well as UnsupportedOperationException and IllegalArgumentException
  • JavaDateFormatter only IllegalArgumentException. NullPointerException is stated in the underlying doc for Format.parseObject but I don't expect this to be thrown as we already check for input not being empty and provide the position of parsing.

I will refactor the javadoc to state that IllegalArgumentException is expected to be thrown when parsing fails (that applies in both cases). But I wonder if we should ommit the DateTimeException and UnsupportedOperationException (thrown only by joda)

This problem also exists in master

Copy link
Member

Choose a reason for hiding this comment

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

I think there is no point in digging through the complete implementation of Java time and Joda time in order to come up with a Javadoc that documents all possible exceptions but rather document the ones that a user can "reasonably" expect when a date cannot be parsed which is in our case java.time.DateTimeException from JodaDateFormatter and IllegalArgumentException (from both) so they know how to deal with them.

IMHO it is ok to document both of them on the interface. Although one of them is in fact thrown by only one of the implementations, the exception type itself is available in the JDK and thus generic enough and we should expect users to program against the interface.

ZoneId zoneId = TemporalQueries.zone().queryFrom(accessor);
if (zoneId != null) {
timeZone = zoneId;
}

return DateFormatters.from(accessor).withZoneSameLocal(timeZone).toInstant().toEpochMilli();
}
} catch (IllegalArgumentException | DateTimeException e) {
throw new ElasticsearchParseException("failed to parse date field [{}] in format [{}]: [{}]", e, value, format, e.getMessage());
} catch (IllegalArgumentException | DateTimeException e) {;
Copy link
Member

Choose a reason for hiding this comment

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

Nit: There is an additional unnecessary semicolon at the end of the line.

} catch (IllegalArgumentException | DateTimeException e) {
throw new ElasticsearchParseException("failed to parse date field [{}] in format [{}]: [{}]", e, value, format, e.getMessage());
} catch (IllegalArgumentException | DateTimeException e) {;

Copy link
Member

Choose a reason for hiding this comment

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

Nit: Is there a reason for the additional empty line here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

accident when merging

Copy link
Member

@danielmitterdorfer danielmitterdorfer left a comment

Choose a reason for hiding this comment

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

Thanks for iterating. LGTM

@pgomulka pgomulka force-pushed the 6.7 branch 2 times, most recently from 29e67c5 to 358d761 Compare April 3, 2019 08:49
@pgomulka pgomulka merged commit a154751 into elastic:6.7 Apr 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport >bug :Core/Infra/Core Core issues without another label
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants