src/share/classes/java/time/format/DateTimeParseContext.java

Print this page

        

*** 59,101 **** * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java.time.format; - import java.time.DateTimeException; import java.time.ZoneId; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; - import java.time.temporal.ChronoField; - import java.time.temporal.Queries; - import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; - import java.time.temporal.TemporalQuery; import java.util.ArrayList; - import java.util.HashMap; import java.util.Locale; - import java.util.Map; import java.util.Objects; /** * Context object used during date and time parsing. * <p> * This class represents the current state of the parse. * It has the ability to store and retrieve the parsed values and manage optional segments. * It also provides key information to the parsing methods. * <p> ! * Once parsing is complete, the {@link #toBuilder()} is typically used ! * to obtain a builder that can combine the separate parsed fields into meaningful values. * * <h3>Specification for implementors</h3> * This class is a mutable context intended for use from a single thread. * Usage of the class is thread-safe within standard parsing as a new instance of this class * is automatically created for each parse and parsing is single-threaded * * @since 1.8 */ ! final class DateTimeParseContext implements TemporalAccessor { /** * The formatter, not null. */ private DateTimeFormatter formatter; --- 59,94 ---- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java.time.format; import java.time.ZoneId; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; import java.time.temporal.TemporalField; import java.util.ArrayList; import java.util.Locale; import java.util.Objects; /** * Context object used during date and time parsing. * <p> * This class represents the current state of the parse. * It has the ability to store and retrieve the parsed values and manage optional segments. * It also provides key information to the parsing methods. * <p> ! * Once parsing is complete, the {@link #toParsed()} is used to obtain the data. ! * It contains a method to resolve the separate parsed fields into meaningful values. * * <h3>Specification for implementors</h3> * This class is a mutable context intended for use from a single thread. * Usage of the class is thread-safe within standard parsing as a new instance of this class * is automatically created for each parse and parsing is single-threaded * * @since 1.8 */ ! final class DateTimeParseContext { /** * The formatter, not null. */ private DateTimeFormatter formatter;
*** 304,313 **** --- 297,317 ---- */ private Parsed currentParsed() { return parsed.get(parsed.size() - 1); } + /** + * Gets the result of the parse. + * + * @return the result of the parse, not null + */ + Parsed toParsed() { + Parsed parsed = currentParsed(); + parsed.effectiveChrono = getEffectiveChronology(); + return parsed; + } + //----------------------------------------------------------------------- /** * Gets the first value that was parsed for the specified field. * <p> * This searches the results of the parse, returning the first value found
*** 366,508 **** currentParsed().zone = zone; } //----------------------------------------------------------------------- /** - * Returns a {@code DateTimeBuilder} that can be used to interpret - * the results of the parse. - * <p> - * This method is typically used once parsing is complete to obtain the parsed data. - * Parsing will typically result in separate fields, such as year, month and day. - * The returned builder can be used to combine the parsed data into meaningful - * objects such as {@code LocalDate}, potentially applying complex processing - * to handle invalid parsed data. - * - * @return a new builder with the results of the parse, not null - */ - DateTimeBuilder toBuilder() { - Parsed parsed = currentParsed(); - DateTimeBuilder builder = new DateTimeBuilder(); - for (Map.Entry<TemporalField, Long> fv : parsed.fieldValues.entrySet()) { - builder.addFieldValue(fv.getKey(), fv.getValue()); - } - builder.addObject(getEffectiveChronology()); - if (parsed.zone != null) { - builder.addObject(parsed.zone); - } - return builder; - } - - /** - * Resolves the fields in this context. - * - * @return this, for method chaining - * @throws DateTimeException if resolving one field results in a value for - * another field that is in conflict - */ - DateTimeParseContext resolveFields() { - Parsed data = currentParsed(); - outer: - while (true) { - for (Map.Entry<TemporalField, Long> entry : data.fieldValues.entrySet()) { - TemporalField targetField = entry.getKey(); - Map<TemporalField, Long> changes = targetField.resolve(this, entry.getValue()); - if (changes != null) { - resolveMakeChanges(data, targetField, changes); - data.fieldValues.remove(targetField); // helps avoid infinite loops - continue outer; // have to restart to avoid concurrent modification - } - } - break; - } - return this; - } - - private void resolveMakeChanges(Parsed data, TemporalField targetField, Map<TemporalField, Long> changes) { - for (Map.Entry<TemporalField, Long> change : changes.entrySet()) { - TemporalField changeField = change.getKey(); - Long changeValue = change.getValue(); - Objects.requireNonNull(changeField, "changeField"); - if (changeValue != null) { - Long old = currentParsed().fieldValues.put(changeField, changeValue); - if (old != null && old.longValue() != changeValue.longValue()) { - throw new DateTimeException("Conflict found: " + changeField + " " + old + - " differs from " + changeField + " " + changeValue + - " while resolving " + targetField); - } - } else { - data.fieldValues.remove(changeField); - } - } - } - - //----------------------------------------------------------------------- - // TemporalAccessor methods - // should only to be used once parsing is complete - @Override - public boolean isSupported(TemporalField field) { - if (currentParsed().fieldValues.containsKey(field)) { - return true; - } - return (field instanceof ChronoField == false) && field.isSupportedBy(this); - } - - @Override - public long getLong(TemporalField field) { - Long value = currentParsed().fieldValues.get(field); - if (value != null) { - return value; - } - if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.getFrom(this); - } - - @SuppressWarnings("unchecked") - @Override - public <R> R query(TemporalQuery<R> query) { - if (query == Queries.chronology()) { - return (R) currentParsed().chrono; - } else if (query == Queries.zoneId()) { - return (R) currentParsed().zone; - } else if (query == Queries.precision()) { - return null; - } - return query.queryFrom(this); - } - - //----------------------------------------------------------------------- - /** * Returns a string version of the context for debugging. * * @return a string representation of the context data, not null */ @Override public String toString() { return currentParsed().toString(); } - //----------------------------------------------------------------------- - /** - * Temporary store of parsed data. - */ - private static final class Parsed { - Chronology chrono = null; - ZoneId zone = null; - final Map<TemporalField, Long> fieldValues = new HashMap<>(); - private Parsed() { - } - protected Parsed copy() { - Parsed cloned = new Parsed(); - cloned.chrono = this.chrono; - cloned.zone = this.zone; - cloned.fieldValues.putAll(this.fieldValues); - return cloned; - } - @Override - public String toString() { - return fieldValues.toString() + "," + chrono + "," + zone; - } - } - } --- 370,384 ----