On Tue, Nov 3, 2026 at 5:22 PM Mark Thomas via dev
<[email protected]> wrote:
>
> On 03/11/2026 14:55, Mark Thomas via dev wrote:
> > On 03/11/2026 14:51, markt.apache.org via dev wrote:
> >> This is an automated email from the ASF dual-hosted git repository.
> >>
> >> markt-asf pushed a commit to branch main
> >> in repository https://gitbox.apache.org/repos/asf/tomcat.git
> >>
> >>
> >> The following commit(s) were added to refs/heads/main by this push:
> >>       new 221d759137 Review "Parse exponent-only numbers in the JSON
> >> parser"
> >> 221d759137 is described below
> >>
> >> commit 221d7591378bc50f6eebbb172e75b8386d7f69c0
> >> Author: Mark Thomas <[email protected]>
> >> AuthorDate: Tue Nov 3 14:51:15 2026 +0000
> >>
> >>      Review "Parse exponent-only numbers in the JSON parser"
> >>      Describe behaviour change in changelog
> >>      Treat out of range number as a ParseException
> >
> > The AI chnaged the generated code. I still need to confirm that JavaCC
> > produces the same result.
>
> Close enough (JavaCC adds various odds and end that are all effectvely
> NO-OPs) that I'm not going to update the generated code.

When my model hacks this, it usually also uses javacc on its own to
verify the added code is equivalent. I think this is nice since it
works and it does not ruin the formatting/cleanups.

Rémy

> Mark
>
> >
> > Mark
> >
> >> ---
> >>   java/org/apache/tomcat/util/json/JSONParser.java   | 12 ++++--
> >>   java/org/apache/tomcat/util/json/JSONParser.jjt    |  8 +++-
> >>   .../apache/tomcat/util/json/TestJSONParser.java    | 48 ++++++++++++
> >> ++++++++++
> >>   webapps/docs/changelog.xml                         | 17 ++++++++
> >>   4 files changed, 81 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/java/org/apache/tomcat/util/json/JSONParser.java b/java/
> >> org/apache/tomcat/util/json/JSONParser.java
> >> index 534692eb20..7abfab60a4 100644
> >> --- a/java/org/apache/tomcat/util/json/JSONParser.java
> >> +++ b/java/org/apache/tomcat/util/json/JSONParser.java
> >> @@ -448,10 +448,16 @@ public class JSONParser implements
> >> JSONParserConstants {
> >>                           }
> >>                       }
> >>                   } else {
> >> -                    {
> >> -                        if ("" != null) {
> >> -                            return new java.math.BigDecimal(t.image);
> >> +                    try {
> >> +                        {
> >> +                            if ("" != null) {
> >> +                                return new
> >> java.math.BigDecimal(t.image);
> >> +                            }
> >>                           }
> >> +                    } catch (NumberFormatException nfe) {
> >> +                        // The grammar admits exponents that
> >> BigDecimal can't represent. Report them as a parse
> >> +                        // error rather than letting an unchecked
> >> exception escape the parser.
> >> +                        throw new ParseException("Exponent out of
> >> range in number [" + t.image + "]");
> >>                       }
> >>                   }
> >>                   break;
> >> diff --git a/java/org/apache/tomcat/util/json/JSONParser.jjt b/java/
> >> org/apache/tomcat/util/json/JSONParser.jjt
> >> index c50f41935a..89c05f3ae8 100644
> >> --- a/java/org/apache/tomcat/util/json/JSONParser.jjt
> >> +++ b/java/org/apache/tomcat/util/json/JSONParser.jjt
> >> @@ -413,7 +413,13 @@ Number number(): {
> >>               if (nativeNumbers) {
> >>                   return Double.valueOf(t.image);
> >>               } else {
> >> -                return new java.math.BigDecimal(t.image);
> >> +                try {
> >> +                    return new java.math.BigDecimal(t.image);
> >> +                } catch (NumberFormatException nfe) {
> >> +                    // The grammar admits exponents that BigDecimal
> >> can't represent. Report them as a parse error
> >> +                    // rather than letting an unchecked exception
> >> escape the parser.
> >> +                    throw new ParseException("Exponent out of range
> >> in number [" + t.image + "]");
> >> +                }
> >>               }
> >>           }
> >>       ) | (
> >> diff --git a/test/org/apache/tomcat/util/json/TestJSONParser.java b/
> >> test/org/apache/tomcat/util/json/TestJSONParser.java
> >> index 9771bbf0bb..47f0588cb8 100644
> >> --- a/test/org/apache/tomcat/util/json/TestJSONParser.java
> >> +++ b/test/org/apache/tomcat/util/json/TestJSONParser.java
> >> @@ -111,6 +111,54 @@ public class TestJSONParser {
> >>           Assert.assertEquals(BigInteger.ONE, result.get("1E+5"));
> >>       }
> >> +    /*
> >> +     * The exponent of a number must be one that BigDecimal can
> >> represent. A larger exponent must be reported as a
> >> +     * ParseException rather than as an unchecked NumberFormatException.
> >> +     */
> >> +    @Test
> >> +    public void testExponentOutOfRangeIsParseException() {
> >> +        for (String number : new String[] { "1e-2147483649",
> >> "1e2147483649", "1.5e-2147483649", "-1E2147483649" }) {
> >> +            try {
> >> +                new JSONParser("[" + number + "]").parse();
> >> +                Assert.fail("A ParseException was expected for " +
> >> number);
> >> +            } catch (ParseException e) {
> >> +                Assert.assertTrue(e.getMessage(),
> >> e.getMessage().contains(number));
> >> +            }
> >> +        }
> >> +    }
> >> +
> >> +    @Test
> >> +    public void testExponentOutOfRangeAsKeyIsParseException() {
> >> +        Assert.assertThrows(ParseException.class, () -> new
> >> JSONParser("{1e2147483649:1}").parseObject());
> >> +    }
> >> +
> >> +    @Test
> >> +    public void testLargestExponentsAccepted() throws ParseException {
> >> +        JSONParser parser = new JSONParser("[1e2147483647,
> >> 1e-2147483647]");
> >> +        List<Object> values = parser.parseArray();
> >> +        Assert.assertEquals(new BigDecimal("1e2147483647"),
> >> values.get(0));
> >> +        Assert.assertEquals(new BigDecimal("1e-2147483647"),
> >> values.get(1));
> >> +    }
> >> +
> >> +    @Test
> >> +    public void testExponentWithLeadingZeros() throws ParseException {
> >> +        Assert.assertEquals(new BigDecimal("1E5"), new
> >> JSONParser("1e05").parse());
> >> +    }
> >> +
> >> +    /*
> >> +     * Bare words that start with a number but are not numbers are
> >> not affected by the exponent-only number syntax.
> >> +     */
> >> +    @Test
> >> +    public void testBareWordKeysStartingWithNumber() throws
> >> ParseException {
> >> +        Map<String, Object> result = new JSONParser("{1e5x:1,
> >> 12abc:2, 1e:3, 3E2:4}").parseObject();
> >> +        Assert.assertEquals(BigInteger.valueOf(1), result.get("1e5x"));
> >> +        Assert.assertEquals(BigInteger.valueOf(2), result.get("12abc"));
> >> +        Assert.assertEquals(BigInteger.valueOf(3), result.get("1e"));
> >> +        // An exponent-only number is a number, so its key is the
> >> normalised form of the number
> >> +        Assert.assertEquals(BigInteger.valueOf(4), result.get("3E+2"));
> >> +        Assert.assertEquals(4, result.size());
> >> +    }
> >> +
> >>       private static String nest(int depth) {
> >>           StringBuilder result = new StringBuilder(depth * 2);
> >>           for (int i = 0; i < depth; i++) {
> >> diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
> >> index 7c0def85ae..27de6fa631 100644
> >> --- a/webapps/docs/changelog.xml
> >> +++ b/webapps/docs/changelog.xml
> >> @@ -613,6 +613,23 @@
> >>           closes the entire connection. These frames are already
> >> permitted when
> >>           the stream is closed in the other direction. (remm)
> >>         </fix>
> >> +      <fix>
> >> +        The JSON parser now accepts numbers that have an exponent but no
> >> +        fraction, such as <code>1e5</code>, as required by RFC 8259.
> >> Note that
> >> +        when the lenient dialect is used, a bare object key that is
> >> such a
> >> +        number (for example <code>{1e5:1}</code>) is now a number and
> >> the key
> >> +        is the string form of the parsed number (<code>1E+5</code>)
> >> rather than
> >> +        the original text, as already happened for bare keys that
> >> have both a
> >> +        fraction and an exponent. Quoted keys are not affected.
> >> Numbers with an
> >> +        exponent that is too large or too small to be represented are
> >> now
> >> +        rejected with a <code>ParseException</code> rather than an
> >> unchecked
> >> +        <code>NumberFormatException</code>. (remm)
> >> +      </fix>
> >> +      <fix>
> >> +        With native numbers enabled, the JSON parser now returns
> >> integers that
> >> +        do not fit in a <code>long</code> as <code>BigInteger</code>
> >> rather than
> >> +        failing with an unchecked <code>NumberFormatException</code>.
> >> (remm)
> >> +      </fix>
> >>         <fix>
> >>           The JSON parser now rejects input with a nesting depth
> >> greater than
> >>           1000 with a <code>ParseException</code>. Previously, deeply
> >> nested
> >>
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: [email protected]
> >> For additional commands, e-mail: [email protected]
> >>
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [email protected]
> > For additional commands, e-mail: [email protected]
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to