-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Issue 1994 #2031
base: main
Are you sure you want to change the base?
Issue 1994 #2031
Changes from all commits
08ff7cd
b8b3b51
6a87ad4
bedcb10
7c58d0a
f5aaecb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -203,6 +203,17 @@ public float getAsFloat() { | |
*/ | ||
@Override | ||
public long getAsLong() { | ||
|
||
if (isNumber()) { | ||
final BigInteger val = getAsBigInteger(); | ||
|
||
if (val.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { | ||
throw new NumberFormatException("Expected a Long but was " + getAsNumber()); | ||
} else if (val.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) { | ||
throw new NumberFormatException("Expected a Long but was " + getAsNumber()); | ||
} | ||
} | ||
|
||
return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString()); | ||
} | ||
|
||
|
@@ -214,6 +225,17 @@ public long getAsLong() { | |
*/ | ||
@Override | ||
public short getAsShort() { | ||
|
||
if (isNumber()) { | ||
final BigInteger val = getAsBigInteger(); | ||
|
||
if (val.compareTo(BigInteger.valueOf(Short.MAX_VALUE)) > 0) { | ||
throw new NumberFormatException("Expected a Short but was " + getAsNumber()); | ||
} else if (val.compareTo(BigInteger.valueOf(Short.MIN_VALUE)) < 0) { | ||
throw new NumberFormatException("Expected a Short but was " + getAsNumber()); | ||
} | ||
} | ||
|
||
return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString()); | ||
} | ||
|
||
|
@@ -225,11 +247,39 @@ public short getAsShort() { | |
*/ | ||
@Override | ||
public int getAsInt() { | ||
|
||
if (isNumber()) { | ||
final BigInteger val = getAsBigInteger(); | ||
|
||
if (val.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { | ||
throw new NumberFormatException("Expected an Integer but was " + getAsNumber()); | ||
} else if (val.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) { | ||
throw new NumberFormatException("Expected an Integer but was " + getAsNumber()); | ||
} | ||
} | ||
|
||
return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString()); | ||
} | ||
|
||
/** | ||
* convenience method to get this element as a primitive byte. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These methods can all throw NumberFormatException, even before this change. I think it is the javadoc of the overridden methods in |
||
* | ||
* @return get this element as a primitive byte. | ||
* @throws NumberFormatException if the value contained is not a valid integer. | ||
*/ | ||
@Override | ||
public byte getAsByte() { | ||
|
||
if (isNumber()) { | ||
final BigInteger val = getAsBigInteger(); | ||
|
||
if (val.compareTo(BigInteger.valueOf(Byte.MAX_VALUE)) > 0) { | ||
throw new NumberFormatException("Expected a Byte but was " + getAsNumber()); | ||
} else if (val.compareTo(BigInteger.valueOf(Byte.MIN_VALUE)) < 0) { | ||
throw new NumberFormatException("Expected a Byte but was " + getAsNumber()); | ||
} | ||
} | ||
|
||
return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString()); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
import java.io.CharArrayReader; | ||
import java.io.CharArrayWriter; | ||
import java.io.StringReader; | ||
import java.math.BigInteger; | ||
|
||
import junit.framework.TestCase; | ||
|
||
|
@@ -98,6 +99,81 @@ public void testParseReader() { | |
assertEquals("c", e.getAsJsonObject().get("b").getAsString()); | ||
} | ||
|
||
public void testParseLongToInt() { | ||
JsonObject jsonObject = new JsonObject(); | ||
jsonObject.addProperty("foo", 10000000000L); | ||
|
||
try { | ||
jsonObject.get("foo").getAsInt(); | ||
fail(); | ||
} catch (NumberFormatException expected) { | ||
} | ||
} | ||
|
||
public void testParseIntegerTypes() { | ||
|
||
JsonObject jsonObject = new JsonObject(); | ||
|
||
jsonObject.addProperty("bigIntegerU", BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(200L)) ); | ||
jsonObject.addProperty("bigIntegerL", BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.valueOf(200L)) ); | ||
jsonObject.addProperty("longU", Integer.MAX_VALUE+143L); | ||
jsonObject.addProperty("longL", Integer.MIN_VALUE-143L); | ||
jsonObject.addProperty("integerU", Short.MAX_VALUE+32); | ||
jsonObject.addProperty("integerL", Short.MIN_VALUE-32); | ||
jsonObject.addProperty("shortU", Byte.MAX_VALUE+17); | ||
jsonObject.addProperty("shortL", Byte.MIN_VALUE-17); | ||
|
||
try { | ||
jsonObject.get("bigIntegerU").getAsLong(); | ||
fail("Big Integer values greater than Long.MAX_VALUE should not parse as a Long"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to write |
||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("bigIntegerL").getAsLong(); | ||
fail("Big Integer values smaller than Long.MIN_VALUE should not parse as a Long"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("longU").getAsInt(); | ||
fail("Long values larger than Integer.MAX_VALUE should not parse as an Integer"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("longL").getAsInt(); | ||
fail("Long values smaller than Integer.MIN_VALUE should not parse as an Integer"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("integerU").getAsShort(); | ||
fail("Integer values larger than Short.MAX_VALUE should not parse as a Short"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("integerL").getAsShort(); | ||
fail("Integer values smaller than Short.MIN_VALUE should not parse as a Short"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("shortU").getAsByte(); | ||
fail("Short values larger than Byte.MAX_VALUE should not parse as a Byte"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
try { | ||
jsonObject.get("shortL").getAsByte(); | ||
fail("Short values smaller than Byte.MIN_VALUE should not parse as a Byte"); | ||
} catch (NumberFormatException expected) { | ||
} | ||
|
||
assertTrue(jsonObject.isJsonObject()); | ||
} | ||
|
||
public void testReadWriteTwoObjects() throws Exception { | ||
Gson gson = new Gson(); | ||
CharArrayWriter writer = new CharArrayWriter(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is suddenly very expensive if
value
is already aLong
.getAsBigInteger()
will convert it to a string which it will then parse back into a newBigInteger
object. If this method is called more than once, it will do the same thing every time. I think it would be worth addinginstanceof
checks to bypass this for whenvalue
isLong
or any of the smallerjava.lang
types, and likewise in the other cases. Also, you're checkingisNumber()
here, so it looks as if you could reasonably move the true-case from theisNumber() ?
code below.Also we can borrow an idea from the implementation of
BigInteger.longValueExact()
for a simpler overflow check. (Since that method was added in Java 8 we unfortunately can't use it directly.)I'm imagining code something like this: