Author: fanningpj
Date: Wed Jun 17 20:21:49 2026
New Revision: 1935462

Log:
reject double leading sign in lexLong and lexInteger. Thanks to aizu-m. This 
closes #55

Modified:
   
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/util/XsTypeConverter.java
   xmlbeans/trunk/src/test/java/misc/checkin/XsTypeConverterTest.java

Modified: 
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/util/XsTypeConverter.java
==============================================================================
--- 
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/util/XsTypeConverter.java 
    Wed Jun 17 20:20:27 2026        (r1935461)
+++ 
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/util/XsTypeConverter.java 
    Wed Jun 17 20:21:49 2026        (r1935462)
@@ -275,11 +275,7 @@ public final class XsTypeConverter {
     // ======================== integer ========================
     public static BigInteger lexInteger(CharSequence cs)
         throws NumberFormatException {
-        if (cs.length() > 1) {
-            if (cs.charAt(0) == '+' && cs.charAt(1) == '-') {
-                throw new NumberFormatException("Illegal char sequence '+-'");
-            }
-        }
+        rejectSignAfterPlus(cs);
         final String v = cs.toString();
 
         //TODO: consider special casing zero and one to return static values
@@ -304,10 +300,25 @@ public final class XsTypeConverter {
     // ======================== long ========================
     public static long lexLong(CharSequence cs)
         throws NumberFormatException {
+        rejectSignAfterPlus(cs);
         final String v = cs.toString();
         return Long.parseLong(trimInitialPlus(v));
     }
 
+    // trimInitialPlus drops a single leading '+', then Long.parseLong /
+    // new BigInteger accept their own leading sign, so "++5" and "+-5" slip
+    // through as 5 and -5. Neither is in the xsd integer lexical space
+    // ([\-+]?[0-9]+ allows one sign). lexInt/lexShort/lexByte already reject
+    // the second sign in parseIntXsdNumber.
+    private static void rejectSignAfterPlus(CharSequence cs) {
+        if (cs.length() > 1 && cs.charAt(0) == '+') {
+            final char c = cs.charAt(1);
+            if (c == '+' || c == '-') {
+                throw new NumberFormatException("Illegal char sequence '+" + c 
+ "'");
+            }
+        }
+    }
+
     public static long lexLong(CharSequence cs, Collection<XmlError> errors) {
         try {
             return lexLong(cs);
@@ -432,7 +443,7 @@ public final class XsTypeConverter {
     }
 
     public static String printBoolean(boolean value) {
-        return (value ? "true" : "false");
+        return Boolean.toString(value);
     }
 
 
@@ -469,7 +480,7 @@ public final class XsTypeConverter {
         String uri = nscontext.getNamespaceURI(prefix);
 
         if (uri == null) {
-            if (prefix != null && prefix.length() > 0) {
+            if (prefix != null && !prefix.isEmpty()) {
                 throw new InvalidLexicalValueException("Can't resolve prefix: 
" + prefix);
             }
 
@@ -495,7 +506,7 @@ public final class XsTypeConverter {
         final String uri = qname.getNamespaceURI();
         assert uri != null; //qname is not allowed to have null uri values
         final String prefix;
-        if (uri.length() > 0) {
+        if (!uri.isEmpty()) {
             prefix = nsContext.getPrefix(uri);
             if (prefix == null) {
                 String msg = "NamespaceContext does not provide" +
@@ -513,9 +524,9 @@ public final class XsTypeConverter {
                                         String localpart,
                                         String prefix) {
         if (prefix != null &&
-            uri != null &&
-            uri.length() > 0 &&
-            prefix.length() > 0) {
+                uri != null &&
+                !uri.isEmpty() &&
+                !prefix.isEmpty()) {
             return (prefix + NAMESPACE_SEP + localpart);
         } else {
             return localpart;
@@ -587,8 +598,7 @@ public final class XsTypeConverter {
                                                    int builtin_type_code) {
         GDateBuilder gDateBuilder = new GDateBuilder(d);
         gDateBuilder.setBuiltinTypeCode(builtin_type_code);
-        GDate value = gDateBuilder.toGDate();
-        return value;
+        return gDateBuilder.toGDate();
     }
 
 
@@ -596,20 +606,18 @@ public final class XsTypeConverter {
                                                    int builtin_type_code) {
         GDateBuilder gDateBuilder = new GDateBuilder(c);
         gDateBuilder.setBuiltinTypeCode(builtin_type_code);
-        GDate value = gDateBuilder.toGDate();
-        return value;
+        return gDateBuilder.toGDate();
     }
 
     public static GDateSpecification getGDateValue(CharSequence v,
                                                    int builtin_type_code) {
         GDateBuilder gDateBuilder = new GDateBuilder(v);
         gDateBuilder.setBuiltinTypeCode(builtin_type_code);
-        GDate value = gDateBuilder.toGDate();
-        return value;
+        return gDateBuilder.toGDate();
     }
 
     private static String trimInitialPlus(String xml) {
-        if (xml.length() > 0 && xml.charAt(0) == '+') {
+        if (!xml.isEmpty() && xml.charAt(0) == '+') {
             return xml.substring(1);
         } else {
             return xml;

Modified: xmlbeans/trunk/src/test/java/misc/checkin/XsTypeConverterTest.java
==============================================================================
--- xmlbeans/trunk/src/test/java/misc/checkin/XsTypeConverterTest.java  Wed Jun 
17 20:20:27 2026        (r1935461)
+++ xmlbeans/trunk/src/test/java/misc/checkin/XsTypeConverterTest.java  Wed Jun 
17 20:21:49 2026        (r1935462)
@@ -167,6 +167,25 @@ public class XsTypeConverterTest {
     }
 
     @Test
+    void lexLongRejectsDoubleSign() {
+        // trimInitialPlus drops the leading '+', then Long.parseLong accepts 
its
+        // own sign, so "++5"/"+-5" used to parse as 5/-5 instead of being 
rejected.
+        assertEquals(5L, XsTypeConverter.lexLong("+5"));
+        assertEquals(-5L, XsTypeConverter.lexLong("-5"));
+        assertThrows(NumberFormatException.class, () -> 
XsTypeConverter.lexLong("++5"));
+        assertThrows(NumberFormatException.class, () -> 
XsTypeConverter.lexLong("+-5"));
+    }
+
+    @Test
+    void lexIntegerRejectsDoubleSign() {
+        // "+-5" was already caught; "++5" leaked through as 5.
+        assertEquals(java.math.BigInteger.valueOf(5), 
XsTypeConverter.lexInteger("+5"));
+        assertEquals(java.math.BigInteger.valueOf(-5), 
XsTypeConverter.lexInteger("-5"));
+        assertThrows(NumberFormatException.class, () -> 
XsTypeConverter.lexInteger("++5"));
+        assertThrows(NumberFormatException.class, () -> 
XsTypeConverter.lexInteger("+-5"));
+    }
+
+    @Test
     void lexDecimalRejectsEmptyString() {
         // an empty value used to read charAt(-1) in trimTrailingZeros and
         // throw StringIndexOutOfBoundsException instead of 
NumberFormatException.


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

Reply via email to