Jackson Data Binding Source Code

Jackson is "the Java JSON library" or "the best JSON parser for Java". Or simply as "JSON for Java".

  • Jackson Data Binding module allows you to converts JSON to and from POJO (Plain Old Java Object) using property accessor or using annotations.
  • Jackson Databind Source Code files are provided in the source packge (jackson-databind-2.14.0-sources.jar). You can download it at Jackson Maven Website.

    You can also browse Jackson Databind Source Code below:

    ✍: FYIcenter.com

    com/fasterxml/jackson/databind/util/StdDateFormat.java

    package com.fasterxml.jackson.databind.util;
    
    import java.text.DateFormat;
    import java.text.FieldPosition;
    import java.text.ParseException;
    import java.text.ParsePosition;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import com.fasterxml.jackson.core.io.NumberInput;
    
    /**
     * Jackson's internal {@link DateFormat} implementation used by standard Date
     * serializers and deserializers to implement default behavior: does <b>NOT</b>
     * fully implement all aspects expected by {@link DateFormat} and as a consequence
     * <b>SHOULD NOT</b> to be used by code outside core Jackson databind functionality.
     * In particular, {@code ParsePosition} argument of {@link #parse(String, ParsePosition)}
     * and {@link #format(Date, StringBuffer, FieldPosition)} methods is fully ignored;
     * Jackson itself never calls these methods.
     *<p>
     * For serialization defaults to using
     * an ISO-8601 compliant format (format String "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
     * and for deserialization, both ISO-8601 and RFC-1123.
     *<br>
     * Note that `Z` in format String refers to ISO-8601 time offset notation which produces
     * values like "-08:00" -- that is, full minute/hour combo without colon, and not using `Z`
     * as alias for "+00:00".
     * Inclusion of colon as separator, as default setting, started in Jackson 2.11:
     * prior versions omitted it.
     * Note that it is possible to enable/disable use of colon in time offset by using method
     * {@link #withColonInTimeZone} for creating new differently configured format instance,
     * and configuring {@code ObjectMapper} with it.
     *<p>
     * TODO: in Jackson 2.14 or later, should change behavior to fail if {@link ParsePosition}
     * is specified by caller (at least with non-0 offset).
     */
    @SuppressWarnings("serial")
    public class StdDateFormat
        extends DateFormat
    {
        /* 24-Jun-2017, tatu: Finally rewrote deserialization to use basic Regex
         *   instead of SimpleDateFormat; partly for better concurrency, partly
         *   for easier enforcing of specific rules. Heavy lifting done by Calendar,
         *   anyway.
         */
        protected final static String PATTERN_PLAIN_STR = "\\d\\d\\d\\d[-]\\d\\d[-]\\d\\d";
    
        protected final static Pattern PATTERN_PLAIN = Pattern.compile(PATTERN_PLAIN_STR);
    
        protected final static Pattern PATTERN_ISO8601;
        static {
            Pattern p = null;
            try {
                p = Pattern.compile(PATTERN_PLAIN_STR
                        +"[T]\\d\\d[:]\\d\\d(?:[:]\\d\\d)?" // hours, minutes, optional seconds
                        +"(\\.\\d+)?" // optional second fractions
                        +"(Z|[+-]\\d\\d(?:[:]?\\d\\d)?)?" // optional timeoffset/Z
                );
            } catch (Throwable t) {
                throw new RuntimeException(t);
            }
            PATTERN_ISO8601 = p;
        }
    
        /**
         * Defines a commonly used date format that conforms
         * to ISO-8601 date formatting standard, when it includes basic undecorated
         * timezone definition.
         */
        public final static String DATE_FORMAT_STR_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSX";
    
        /**
         * ISO-8601 with just the Date part, no time: needed for error messages
         */
        protected final static String DATE_FORMAT_STR_PLAIN = "yyyy-MM-dd";
    
        /**
         * This constant defines the date format specified by
         * RFC 1123 / RFC 822. Used for parsing via `SimpleDateFormat` as well as
         * error messages.
         */
        protected final static String DATE_FORMAT_STR_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
    
        /**
         * For error messages we'll also need a list of all formats.
         */
        protected final static String[] ALL_FORMATS = new String[] {
            DATE_FORMAT_STR_ISO8601,
            "yyyy-MM-dd'T'HH:mm:ss.SSS", // ISO-8601 but no timezone
            DATE_FORMAT_STR_RFC1123,
            DATE_FORMAT_STR_PLAIN
        };
    
        /**
         * By default we use UTC for everything, with Jackson 2.7 and later
         * (2.6 and earlier relied on GMT)
         */
        protected final static TimeZone DEFAULT_TIMEZONE;
        static {
            DEFAULT_TIMEZONE = TimeZone.getTimeZone("UTC"); // since 2.7
        }
    
        protected final static Locale DEFAULT_LOCALE = Locale.US;
    
        protected final static DateFormat DATE_FORMAT_RFC1123;
    
        /* Let's construct "blueprint" date format instances: cannot be used
         * as is, due to thread-safety issues, but can be used for constructing
         * actual instances more cheaply (avoids re-parsing).
         */
        static {
            // Another important thing: let's force use of default timezone for
            // baseline DataFormat objects
            DATE_FORMAT_RFC1123 = new SimpleDateFormat(DATE_FORMAT_STR_RFC1123, DEFAULT_LOCALE);
            DATE_FORMAT_RFC1123.setTimeZone(DEFAULT_TIMEZONE);
        }
    
        /**
         * A singleton instance can be used for cloning purposes, as a blueprint of sorts.
         */
        public final static StdDateFormat instance = new StdDateFormat();
    
        /**
         * Blueprint "Calendar" instance for use during formatting. Cannot be used as is,
         * due to thread-safety issues, but can be used for constructing actual instances 
         * more cheaply by cloning.
         *
         * @since 2.9.1
         */
        protected static final Calendar CALENDAR = new GregorianCalendar(DEFAULT_TIMEZONE, DEFAULT_LOCALE);
    
        /**
         * Caller may want to explicitly override timezone to use; if so,
         * we will have non-null value here.
         */
        protected transient TimeZone _timezone;
    
        protected final Locale _locale;
    
        /**
         * Explicit override for leniency, if specified.
         *<p>
         * Cannot be `final` because {@link #setLenient(boolean)} returns
         * `void`.
         *
         * @since 2.7
         */
        protected Boolean _lenient;
    
        /**
         * Lazily instantiated calendar used by this instance for serialization ({@link #format(Date)}).
         *
         * @since 2.9.1
         */
        private transient Calendar _calendar;
    
        private transient DateFormat _formatRFC1123;
    
        /** 
         * Whether the TZ offset must be formatted with a colon between hours and minutes ({@code HH:mm} format)
         *<p>
         * Defaults to {@code true} since 2.11: earlier versions defaulted to {@code false}
         * for backwards compatibility reasons
         *
         * @since 2.9.1
         */
        private boolean _tzSerializedWithColon = true;
    
        /*
        /**********************************************************
        /* Life cycle, accessing singleton "standard" formats
        /**********************************************************
         */
    
        public StdDateFormat() {
            _locale = DEFAULT_LOCALE;
        }
    
        @Deprecated // since 2.7
        public StdDateFormat(TimeZone tz, Locale loc) {
            _timezone = tz;
            _locale = loc;
        }
    
        protected StdDateFormat(TimeZone tz, Locale loc, Boolean lenient) {
            this(tz, loc, lenient, false);
        }
    
        /**
         * @since 2.9.1
         */
        protected StdDateFormat(TimeZone tz, Locale loc, Boolean lenient,
                boolean formatTzOffsetWithColon) {
            _timezone = tz;
            _locale = loc;
            _lenient = lenient;
            _tzSerializedWithColon = formatTzOffsetWithColon;
        }
    
        public static TimeZone getDefaultTimeZone() {
            return DEFAULT_TIMEZONE;
        }
        
        /**
         * Method used for creating a new instance with specified timezone;
         * if no timezone specified, defaults to the default timezone (UTC).
         */
        public StdDateFormat withTimeZone(TimeZone tz) {
            if (tz == null) {
                tz = DEFAULT_TIMEZONE;
            }
            if ((tz == _timezone) || tz.equals(_timezone)) {
                return this;
            }
            return new StdDateFormat(tz, _locale, _lenient, _tzSerializedWithColon);
        }
    
        /**
         * "Mutant factory" method that will return an instance that uses specified
         * {@code Locale}:
         * either {@code this} instance (if setting would not change), or newly
         * constructed instance with different {@code Locale} to use.
         */
        public StdDateFormat withLocale(Locale loc) {
            if (loc.equals(_locale)) {
                return this;
            }
            return new StdDateFormat(_timezone, loc, _lenient, _tzSerializedWithColon);
        }
    
        /**
         * "Mutant factory" method that will return an instance that has specified leniency
         * setting: either {@code this} instance (if setting would not change), or newly
         * constructed instance.
         *
         * @since 2.9
         */
        public StdDateFormat withLenient(Boolean b) {
            if (_equals(b, _lenient)) {
                return this;
            }
            return new StdDateFormat(_timezone, _locale, b, _tzSerializedWithColon);
        }
    
        /**
         * "Mutant factory" method that will return an instance that has specified
         * handling of colon when serializing timezone (timezone either written
         * like {@code +0500} or {@code +05:00}):
         * either {@code this} instance (if setting would not change), or newly
         * constructed instance with desired setting for colon inclusion.
         *<p>
         * NOTE: does NOT affect deserialization as colon is optional accepted
         * but not required -- put another way, either serialization is accepted
         * by this class.
         *
         * @since 2.9.1
         */
        public StdDateFormat withColonInTimeZone(boolean b) {
            if (_tzSerializedWithColon == b) {
                return this;
            }
            return new StdDateFormat(_timezone, _locale, _lenient, b);
         }
        
        @Override
        public StdDateFormat clone() {
            // Although there isn't that much state to share, we do need to
            // orchestrate a bit, mostly since timezones may be changed
            return new StdDateFormat(_timezone, _locale, _lenient, _tzSerializedWithColon);
        }
    
        /**
         * Method for getting a non-shared DateFormat instance
         * that uses specified timezone and can handle simple ISO-8601
         * compliant date format.
         * 
         * @since 2.4
         *
         * @deprecated Since 2.9
         */
        @Deprecated // since 2.9
        public static DateFormat getISO8601Format(TimeZone tz, Locale loc) {
            DateFormat df = new SimpleDateFormat(DATE_FORMAT_STR_ISO8601, loc);
            df.setTimeZone(DEFAULT_TIMEZONE);
            return df;
        }
    
        /**
         * Method for getting a non-shared DateFormat instance
         * that uses specific timezone and can handle RFC-1123
         * compliant date format.
         * 
         * @since 2.4
         *
         * @deprecated Since 2.9
         */
        @Deprecated // since 2.9
        public static DateFormat getRFC1123Format(TimeZone tz, Locale loc) {
            return _cloneFormat(DATE_FORMAT_RFC1123, DATE_FORMAT_STR_RFC1123,
                    tz, loc, null);
        }
    
        /*
        /**********************************************************
        /* Public API, configuration
        /**********************************************************
         */
    
        @Override // since 2.6
        public TimeZone getTimeZone() {
            return _timezone;
        }
    
        @Override
        public void setTimeZone(TimeZone tz)
        {
            // DateFormats are timezone-specific (via Calendar contained),
            // so need to reset instances if timezone changes:
            if (!tz.equals(_timezone)) {
                _clearFormats();
                _timezone = tz;
            }
        }
    
        /**
         * Need to override since we need to keep track of leniency locally,
         * and not via underlying {@link Calendar} instance like base class
         * does.
         */
        @Override // since 2.7
        public void setLenient(boolean enabled) {
            Boolean newValue = Boolean.valueOf(enabled);
            if (!_equals(newValue, _lenient)) {
                _lenient = newValue;
                // and since leniency settings may have been used:
                _clearFormats();
            }
        }
    
        @Override // since 2.7
        public boolean isLenient() {
            // default is, I believe, true
            return (_lenient == null) || _lenient.booleanValue();
        }
    
        /**
         * Accessor for checking whether this instance would include colon
         * within timezone serialization or not: if {code true}, timezone offset
         * is serialized like {@code -06:00}; if {code false} as {@code -0600}.
         *<p>
         * NOTE: only relevant for serialization (formatting), as deserialization
         * (parsing) always accepts optional colon but does not require it, regardless
         * of this setting.
         *
         * @return {@code true} if a colon is to be inserted between the hours and minutes 
         * of the TZ offset when serializing as String; otherwise {@code false}
         *
         * @since 2.9.1
         */
        public boolean isColonIncludedInTimeZone() {
            return _tzSerializedWithColon;
        }
    
        /*
        /**********************************************************
        /* Public API, parsing
        /**********************************************************
         */
    
        @Override
        public Date parse(String dateStr) throws ParseException
        {
            dateStr = dateStr.trim();
            ParsePosition pos = new ParsePosition(0);
            Date dt = _parseDate(dateStr, pos);
            if (dt != null) {
                return dt;
            }
            StringBuilder sb = new StringBuilder();
            for (String f : ALL_FORMATS) {
                if (sb.length() > 0) {
                    sb.append("\", \"");
                } else {
                    sb.append('"');
                }
                sb.append(f);
            }
            sb.append('"');
            throw new ParseException
                (String.format("Cannot parse date \"%s\": not compatible with any of standard forms (%s)",
                               dateStr, sb.toString()), pos.getErrorIndex());
        }
    
        // 24-Jun-2017, tatu: I don't think this ever gets called. So could... just not implement?
        @Override
        public Date parse(String dateStr, ParsePosition pos)
        {
            try {
                return _parseDate(dateStr, pos);
            } catch (ParseException e) {
                // may look weird but this is what `DateFormat` suggest to do...
            }
            return null;
        }
    
        protected Date _parseDate(String dateStr, ParsePosition pos) throws ParseException
        {
            if (looksLikeISO8601(dateStr)) { // also includes "plain"
                return parseAsISO8601(dateStr, pos);
            }
            // Also consider "stringified" simple time stamp
            int i = dateStr.length();
            while (--i >= 0) {
                char ch = dateStr.charAt(i);
                if (ch < '0' || ch > '9') {
                    // 07-Aug-2013, tatu: And [databind#267] points out that negative numbers should also work
                    if (i > 0 || ch != '-') {
                        break;
                    }
                }
            }
            if ((i < 0)
                // let's just assume negative numbers are fine (can't be RFC-1123 anyway); check length for positive
                    && (dateStr.charAt(0) == '-' || NumberInput.inLongRange(dateStr, false))) {
                return _parseDateFromLong(dateStr, pos);
            }
            // Otherwise, fall back to using RFC 1123. NOTE: call will NOT throw, just returns `null`
            return parseAsRFC1123(dateStr, pos);
        }
    
        /*
        /**********************************************************
        /* Public API, writing
        /**********************************************************
         */
        
        @Override
        public StringBuffer format(Date date, StringBuffer toAppendTo,
                FieldPosition fieldPosition)
        {
            TimeZone tz = _timezone;
            if (tz == null) {
                tz = DEFAULT_TIMEZONE;
            }
            _format(tz, _locale, date, toAppendTo);
            return toAppendTo;
        }
        
        protected void _format(TimeZone tz, Locale loc, Date date,
                StringBuffer buffer)
        {
            Calendar cal = _getCalendar(tz);
            cal.setTime(date);
            // [databind#2167]: handle range beyond [1, 9999]
            final int year = cal.get(Calendar.YEAR);
    
            // Assuming GregorianCalendar, special handling needed for BCE (aka BC)
            if (cal.get(Calendar.ERA) == GregorianCalendar.BC) {
                _formatBCEYear(buffer, year);
            } else {
                if (year > 9999) {
                    // 22-Nov-2018, tatu: Handling beyond 4-digits is not well specified wrt ISO-8601, but
                    //   it seems that plus prefix IS mandated. Padding is an open question, but since agreeement
                    //   for max length would be needed, we ewould need to limit to arbitrary length
                    //   like five digits (erroring out if beyond or padding to that as minimum).
                    //   Instead, let's just print number out as is and let decoder try to make sense of it.
                    buffer.append('+');
                }
                pad4(buffer, year);
            }
            buffer.append('-');
            pad2(buffer, cal.get(Calendar.MONTH) + 1);
            buffer.append('-');
            pad2(buffer, cal.get(Calendar.DAY_OF_MONTH));
            buffer.append('T');
            pad2(buffer, cal.get(Calendar.HOUR_OF_DAY));
            buffer.append(':');
            pad2(buffer, cal.get(Calendar.MINUTE));
            buffer.append(':');
            pad2(buffer, cal.get(Calendar.SECOND));
            buffer.append('.');
            pad3(buffer, cal.get(Calendar.MILLISECOND));
    
            int offset = tz.getOffset(cal.getTimeInMillis());
            if (offset != 0) {
                int hours = Math.abs((offset / (60 * 1000)) / 60);
                int minutes = Math.abs((offset / (60 * 1000)) % 60);
                buffer.append(offset < 0 ? '-' : '+');
                pad2(buffer, hours);
                if( _tzSerializedWithColon ) {
                    buffer.append(':');
                }
                pad2(buffer, minutes);
            } else {
                // 24-Jun-2017, tatu: While `Z` would be conveniently short, older specs
                //   mandate use of full `+0000`
                // 06-Mar-2020, tatu: Actually statement should read "for compatibility reasons"
                //   and not standards (unless it is wrt RFC-1123). This will change in 3.0 at latest
    //            formatted.append('Z');
                if( _tzSerializedWithColon ) {
                    buffer.append("+00:00");
                } else {
                    buffer.append("+0000");
                }
            }
        }
    
        protected void _formatBCEYear(StringBuffer buffer, int bceYearNoSign) {
            // Ok. First of all, BCE 1 output (given as value `1` in era BCE) needs to become
            // "+0000", but rest (from `2` up, in that era) need minus sign.
            if (bceYearNoSign == 1) {
                buffer.append("+0000");
                return;
            }
            final int isoYear = bceYearNoSign - 1;
            buffer.append('-');
            // as with CE, 4 digit variant needs padding; beyond that not (although that part is
            // open to debate, needs agreement with receiver)
            // But `pad4()` deals with "big" numbers now so:
            pad4(buffer, isoYear);
        }
    
        private static void pad2(StringBuffer buffer, int value) {
            int tens = value / 10;
            if (tens == 0) {
                buffer.append('0');
            } else {
                buffer.append((char) ('0' + tens));
                value -= 10 * tens;
            }
            buffer.append((char) ('0' + value));
        }
    
        private static void pad3(StringBuffer buffer, int value) {
            int h = value / 100;
            if (h == 0) {
                buffer.append('0');
            } else {
                buffer.append((char) ('0' + h));
                value -= (h * 100);
            }
            pad2(buffer, value);
        }
    
        private static void pad4(StringBuffer buffer, int value) {
            int h = value / 100;
            if (h == 0) {
                buffer.append('0').append('0');
            } else {
                if (h > 99) { // [databind#2167]: handle above 9999 correctly
                    buffer.append(h);
                } else {
                    pad2(buffer, h);
                }
                value -= (100 * h);
            }
            pad2(buffer, value);
        }
        
        /*
        /**********************************************************
        /* Std overrides
        /**********************************************************
         */
    
        @Override
        public String toString() {
            return String.format("DateFormat %s: (timezone: %s, locale: %s, lenient: %s)",
                    getClass().getName(), _timezone, _locale, _lenient);
        }
    
        public String toPattern() { // same as SimpleDateFormat
            StringBuilder sb = new StringBuilder(100);
            sb.append("[one of: '")
                .append(DATE_FORMAT_STR_ISO8601)
                .append("', '")
                .append(DATE_FORMAT_STR_RFC1123)
                .append("' (")
                ;
            sb.append(Boolean.FALSE.equals(_lenient) ?
                    "strict" : "lenient")
                .append(")]");
            return sb.toString();
        }
    
        @Override // since 2.7[.2], as per [databind#1130]
        public boolean equals(Object o) {
            return (o == this);
        }
    
        @Override // since 2.7[.2], as per [databind#1130]
        public int hashCode() {
            return System.identityHashCode(this);
        }
    
        /*
        /**********************************************************
        /* Helper methods, parsing
        /**********************************************************
         */
    
        /**
         * Helper method used to figure out if input looks like valid
         * ISO-8601 string.
         */
        protected boolean looksLikeISO8601(String dateStr)
        {
            if (dateStr.length() >= 7 // really need 10, but...
                && Character.isDigit(dateStr.charAt(0))
                && Character.isDigit(dateStr.charAt(3))
                && dateStr.charAt(4) == '-'
                && Character.isDigit(dateStr.charAt(5))
                ) {
                return true;
            }
            return false;
        }
    
        private Date _parseDateFromLong(String longStr, ParsePosition pos) throws ParseException
        {
            long ts;
            try {
                ts = NumberInput.parseLong(longStr);
            } catch (NumberFormatException e) {
                throw new ParseException(String.format(
                        "Timestamp value %s out of 64-bit value range", longStr),
                        pos.getErrorIndex());
            }
            return new Date(ts);
        }
    
        protected Date parseAsISO8601(String dateStr, ParsePosition pos)
            throws ParseException
        {
            try {
                return _parseAsISO8601(dateStr, pos);
            } catch (IllegalArgumentException e) {
                throw new ParseException(String.format("Cannot parse date \"%s\", problem: %s",
                        dateStr, e.getMessage()),
                        pos.getErrorIndex());
            }
        }
    
        protected Date _parseAsISO8601(String dateStr, ParsePosition bogus)
            throws IllegalArgumentException, ParseException
        {
            final int totalLen = dateStr.length();
            // actually, one short-cut: if we end with "Z", must be UTC
            TimeZone tz = DEFAULT_TIMEZONE;
            if ((_timezone != null) && ('Z' != dateStr.charAt(totalLen-1))) {
                tz = _timezone;
            }
            Calendar cal = _getCalendar(tz);
            cal.clear();
            String formatStr;
            if (totalLen <= 10) {
                Matcher m = PATTERN_PLAIN.matcher(dateStr);
                if (m.matches()) {
                    int year = _parse4D(dateStr, 0);
                    int month = _parse2D(dateStr, 5)-1;
                    int day = _parse2D(dateStr, 8);
    
                    cal.set(year, month, day, 0, 0, 0);
                    cal.set(Calendar.MILLISECOND, 0);
                    return cal.getTime();
                }
                formatStr = DATE_FORMAT_STR_PLAIN;
            } else {
                Matcher m = PATTERN_ISO8601.matcher(dateStr);
                if (m.matches()) {
                    // Important! START with optional time zone; otherwise Calendar will explode
                    
                    int start = m.start(2);
                    int end = m.end(2);
                    int len = end-start;
                    if (len > 1) { // 0 -> none, 1 -> 'Z'
                        // NOTE: first char is sign; then 2 digits, then optional colon, optional 2 digits
                        int offsetSecs = _parse2D(dateStr, start+1) * 3600; // hours
                        if (len >= 5) {
                            offsetSecs += _parse2D(dateStr, end-2) * 60; // minutes
                        }
                        if (dateStr.charAt(start) == '-') {
                            offsetSecs *= -1000;
                        } else {
                            offsetSecs *= 1000;
                        }
                        cal.set(Calendar.ZONE_OFFSET, offsetSecs);
                        // 23-Jun-2017, tatu: Not sure why, but this appears to be needed too:
                        cal.set(Calendar.DST_OFFSET, 0);
                    }
                    
                    int year = _parse4D(dateStr, 0);
                    int month = _parse2D(dateStr, 5)-1;
                    int day = _parse2D(dateStr, 8);
    
                    // So: 10 chars for date, then `T`, so starts at 11
                    int hour = _parse2D(dateStr, 11);
                    int minute = _parse2D(dateStr, 14);
    
                    // Seconds are actually optional... so
                    int seconds;
                    if ((totalLen > 16) && dateStr.charAt(16) == ':') {
                        seconds = _parse2D(dateStr, 17);
                    } else {
                        seconds = 0;
                    }
                    cal.set(year, month, day, hour, minute, seconds);
    
                    // Optional milliseconds
                    start = m.start(1) + 1;
                    end = m.end(1);
                    int msecs = 0;
                    if (start >= end) { // no fractional
                        cal.set(Calendar.MILLISECOND, 0);
                    } else {
                        // first char is '.', but rest....
                        msecs = 0;
                        final int fractLen = end-start;
                        switch (fractLen) {
                        default: // [databind#1745] Allow longer fractions... for now, cap at nanoseconds tho
    
                            if (fractLen > 9) { // only allow up to nanos
                                throw new ParseException(String.format(
    "Cannot parse date \"%s\": invalid fractional seconds '%s'; can use at most 9 digits",
                                           dateStr, m.group(1).substring(1)
                                           ), start);
                            }
                            // fall through
                        case 3:
                            msecs += (dateStr.charAt(start+2) - '0');
                        case 2:
                            msecs += 10 * (dateStr.charAt(start+1) - '0');
                        case 1:
                            msecs += 100 * (dateStr.charAt(start) - '0');
                            break;
                        case 0:
                            break;
                        }
                        cal.set(Calendar.MILLISECOND, msecs);
                    }
                    return cal.getTime();
                }
                formatStr = DATE_FORMAT_STR_ISO8601;
            }
    
            throw new ParseException
            (String.format("Cannot parse date \"%s\": while it seems to fit format '%s', parsing fails (leniency? %s)",
                           dateStr, formatStr, _lenient),
                    // [databind#1742]: Might be able to give actual location, some day, but for now
                    //  we can't give anything more indicative
                    0);
        }
    
        private static int _parse4D(String str, int index) {
            return (1000 * (str.charAt(index) - '0'))
                    + (100 * (str.charAt(index+1) - '0'))
                    + (10 * (str.charAt(index+2) - '0'))
                    + (str.charAt(index+3) - '0');
        }
    
        private static int _parse2D(String str, int index) {
            return (10 * (str.charAt(index) - '0'))
                    + (str.charAt(index+1) - '0');
        }
    
        protected Date parseAsRFC1123(String dateStr, ParsePosition pos)
        {
            if (_formatRFC1123 == null) {
                _formatRFC1123 = _cloneFormat(DATE_FORMAT_RFC1123, DATE_FORMAT_STR_RFC1123,
                        _timezone, _locale, _lenient);
            }
            return _formatRFC1123.parse(dateStr, pos);
        }
    
        /*
        /**********************************************************
        /* Helper methods, other
        /**********************************************************
         */
    
        private final static DateFormat _cloneFormat(DateFormat df, String format,
                TimeZone tz, Locale loc, Boolean lenient)
        {
            if (!loc.equals(DEFAULT_LOCALE)) {
                df = new SimpleDateFormat(format, loc);
                df.setTimeZone((tz == null) ? DEFAULT_TIMEZONE : tz);
            } else {
                df = (DateFormat) df.clone();
                if (tz != null) {
                    df.setTimeZone(tz);
                }
            }
            if (lenient != null) {
                df.setLenient(lenient.booleanValue());
            }
            return df;
        }
    
        protected void _clearFormats() {
            _formatRFC1123 = null;
        }
    
        protected Calendar _getCalendar(TimeZone tz) {
            Calendar cal = _calendar;
            if (cal == null ) {
                _calendar = cal = (Calendar)CALENDAR.clone();
            }
            if (!cal.getTimeZone().equals(tz) ) {
                cal.setTimeZone(tz);
            }
            cal.setLenient(isLenient());
            return cal;
        }
        
        protected static <T> boolean _equals(T value1, T value2) {
            if (value1 == value2) {
                return true;
            }
            return (value1 != null) && value1.equals(value2);
        }
    }
    

    com/fasterxml/jackson/databind/util/StdDateFormat.java

     

    Or download all of them as a single archive file:

    File name: jackson-databind-2.14.0-sources.jar
    File size: 1187952 bytes
    Release date: 2022-11-05
    Download 
    

     

    Jackson Annotations Source Code

    Download and Install Jackson Binary Package

    Downloading and Reviewing jackson-*.jar

    ⇑⇑ Jackson - Java JSON library

    2022-03-29, 81088👍, 0💬