You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by "Alan M. Feldstein (JIRA)" <ji...@apache.org> on 2006/03/17 20:35:00 UTC
[jira] Commented: (AXIS2-492) new UnsignedLong( 0xffffffffffffffffL
) should not throw a NumberFormatException
[ http://issues.apache.org/jira/browse/AXIS2-492?page=comments#action_12370871 ]
Alan M. Feldstein commented on AXIS2-492:
-----------------------------------------
Index: modules/codegen/test/org/apache/axis2/schema/populate/derived/DerivedTypeUnsignedLongPopulateTest.java
===================================================================
--- modules/codegen/test/org/apache/axis2/schema/populate/derived/DerivedTypeUnsignedLongPopulateTest.java (revision 386676)
+++ modules/codegen/test/org/apache/axis2/schema/populate/derived/DerivedTypeUnsignedLongPopulateTest.java (working copy)
@@ -25,6 +25,7 @@
"1",
"0",
"26758223334334" ,
+ "18446744073709551615",
"-1" ,
"-267582233"
@@ -35,7 +36,8 @@
"<DerivedUnsignedLong xmlns=\"http://soapinterop.org/xsd\">"+values[1]+"</DerivedUnsignedLong>",
"<DerivedUnsignedLong xmlns=\"http://soapinterop.org/xsd\">"+values[2]+"</DerivedUnsignedLong>",
"<DerivedUnsignedLong xmlns=\"http://soapinterop.org/xsd\">"+values[3]+"</DerivedUnsignedLong>",
- "<DerivedUnsignedLong xmlns=\"http://soapinterop.org/xsd\">"+values[4]+"</DerivedUnsignedLong>"
+ "<DerivedUnsignedLong xmlns=\"http://soapinterop.org/xsd\">"+values[4]+"</DerivedUnsignedLong>",
+ "<DerivedUnsignedLong xmlns=\"http://soapinterop.org/xsd\">"+values[5]+"</DerivedUnsignedLong>"
};
@@ -49,11 +51,11 @@
// force others to implement this method
public void testPopulate() throws Exception {
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < 4; i++) {
checkValue(xmlString[i],values[i]);
}
- for (int i = 3; i < values.length; i++) {
+ for (int i = 4; i < values.length; i++) {
try {
checkValue(xmlString[i],values[i]);
fail();
Index: modules/adb/src/org/apache/axis2/databinding/types/UnsignedLong.java
===================================================================
--- modules/adb/src/org/apache/axis2/databinding/types/UnsignedLong.java (revision 386676)
+++ modules/adb/src/org/apache/axis2/databinding/types/UnsignedLong.java (working copy)
@@ -15,6 +15,10 @@
*/
package org.apache.axis2.databinding.types;
+// Consider removing this.
+// All operations behave as if BigIntegers were represented in two's-complement notation.
+// In its place, consider using primitive type long (which is already the right size) to hold the data.
+// This class can hide the fact that the data is stored in a signed entity, by careful implementation of the class' methods.
import java.math.BigInteger;
/**
@@ -22,7 +26,7 @@
*
* @see <a href="http://www.w3.org/TR/xmlschema-2/#unsignedLong">XML Schema 3.3.21</a>
*/
-public class UnsignedLong extends java.lang.Number {
+public class UnsignedLong extends java.lang.Number implements Comparable {
private static final long serialVersionUID = -5919942584284897583L;
@@ -40,17 +44,41 @@
setValue(value);
}
- public UnsignedLong(long lValue) throws NumberFormatException {
+ public UnsignedLong(long lValue) throws IllegalArgumentException {
+ // new UnsignedLong( 0xffffffffffffffffL )
+ // should not throw any Exception because, as an UnsignedLong, it is in range and nonnegative.
setValue(BigInteger.valueOf(lValue));
}
public UnsignedLong(String stValue) throws NumberFormatException {
- setValue(new BigInteger(stValue));
+
+ // If stValue starts with a minus sign, that will be acceptable to the BigInteger constructor,
+ // but it is not acceptable to us.
+ // Once encoded into binary, it is too late to detect that the client intended a negative integer.
+ // That detection must be performed here.
+ try {
+ if (stValue.charAt(0) == '\u002d')
+ {
+ throw new NumberFormatException("A String that starts with a minus sign is not a valid representation of an UnsignedLong.");
+ }
+ setValue(new BigInteger(stValue));
+ }
+
+ catch ( NumberFormatException numberFormatException ) {
+ throw numberFormatException;
+ }
+
+ catch ( IndexOutOfBoundsException indexOutOfBoundsException ) {
+ // This could happen if stValue is empty when we attempt to detect a minus sign.
+ // From the client's point of view, the empty String should cause a NumberFormatException.
+ throw new NumberFormatException("An empty string is not a valid representation of an UnsignedLong.");
+ }
+
}
private void setValue(BigInteger val) {
if (!UnsignedLong.isValid(val)) {
- throw new NumberFormatException(
+ throw new IllegalArgumentException(
// Messages.getMessage("badUnsignedLong00") +
String.valueOf(val) + "]");
}
@@ -58,8 +86,15 @@
}
public static boolean isValid(BigInteger value) {
- return !(value.compareTo(BigInteger.ZERO) == -1 || // less than zero
- value.compareTo(MAX) == 1);
+
+ // Converts this BigInteger to a long.
+ // This conversion is analogous to a narrowing primitive conversion from long to int as defined in the Java Language Specification:
+ // if this BigInteger is too big to fit in a long, only the low-order 64 bits are returned.
+ // Note that this conversion can lose information about the overall magnitude of the BigInteger value as well as return a result with the opposite sign.
+ long unsignedLongValue = value.longValue();
+
+ return !(compare(unsignedLongValue, BigInteger.ZERO.longValue()) < 0 || // less than zero
+ compare(unsignedLongValue, MAX.longValue()) > 0);
}
public String toString() {
@@ -117,4 +152,88 @@
return lValue.floatValue();
}
+ /**
+ * @return the value 0 if the argument is an UnsignedLong numerically equal to this UnsignedLong; a value less than 0 if the argument is an UnsignedLong numerically greater than this UnsignedLong; and a value greater than 0 if the argument is an UnsignedLong numerically less than this UnsignedLong.
+ */
+ public int compareTo( Object o )
+ throws ClassCastException, NullPointerException
+ {
+ int retVal = 0; // arbitrary default value in case of exception; required return value in case this object is equal to the specified object
+
+ try {
+ if ( o == null )
+ {
+ throw new NullPointerException( "Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException." );
+ }
+ if ( ! ( o instanceof UnsignedLong ) )
+ {
+ throw new ClassCastException( "The argument is not an UnsignedLong." );
+ }
+ // Only need to change retVal if this object is not equal to the specified object.
+ retVal = compare( longValue(), ( (UnsignedLong) o ).longValue() );
+ }
+
+ catch ( NullPointerException nullPointerException ) {
+ throw nullPointerException;
+ }
+
+ catch ( ClassCastException classCastException ) {
+ throw classCastException;
+ }
+
+ finally {
+ return retVal;
+ }
+
+ }
+
+ /**
+ * @return the value 0 if thatLong is a long numerically equal to thisLong; a value less than 0 if thatLong is a long numerically greater than thisLong; and a value greater than 0 if thatLong is a long numerically less than thisLong (unsigned comparison).
+ */
+ private static int compare( long thisLong, long thatLong )
+ {
+ // To avoid infinite recursion, do not instantiate UnsignedLong in this method, which may be called during UnsignedLong instantiation.
+
+ if ( thisLong == thatLong )
+ {
+ return 0;
+ }
+ else
+ {
+ boolean isLessThan; // This is less than that.
+
+ // Prepare the most significant half of the data for comparison.
+ // The shift distance can be any number from 1 to 32 inclusive (1 is probably fastest).
+ // A shift distance of one is sufficient to move the significant data off of the sign bit, allowing for a signed comparison of positive numbers (i.e. an unsigned comparison).
+ long thisHalfLong = ( thisLong & 0xffffffff00000000L ) >>> 1;
+ long thatHalfLong = ( thatLong & 0xffffffff00000000L ) >>> 1;
+
+ if ( thisHalfLong == thatHalfLong )
+ {
+ // We must also look at the least significant half of the data.
+
+ // Prepare the least significant half of the data for comparison.
+ thisHalfLong = ( thisLong & 0x00000000ffffffffL );
+ thatHalfLong = ( thatLong & 0x00000000ffffffffL );
+
+ // We already know that the data is not equal.
+ isLessThan = thisHalfLong < thatHalfLong;
+ }
+ else
+ {
+ // The answer is in the most significant half of the data.
+ isLessThan = thisHalfLong < thatHalfLong;
+ }
+
+ if ( isLessThan )
+ {
+ return -1; // Returns a negative integer as this object is less than than the specified object.
+ }
+ else
+ {
+ return 1; // Returns a positive integer as this object is greater than than the specified object.
+ }
+ }
+ }
+
}
> new UnsignedLong( 0xffffffffffffffffL ) should not throw a NumberFormatException
> --------------------------------------------------------------------------------
>
> Key: AXIS2-492
> URL: http://issues.apache.org/jira/browse/AXIS2-492
> Project: Apache Axis 2.0 (Axis2)
> Type: Bug
> Components: databinding
> Versions: 0.95
> Environment: Java 2 Platform SE 5.0
> Reporter: Alan M. Feldstein
>
> new UnsignedLong( 0xffffffffffffffffL )
> should not throw any Exception because, as an UnsignedLong, it is in range and nonnegative.
> Constructor
> UnsignedLong(long lValue)
> should never throw a NumberFormatException because that indicates that the application has attempted to convert a string to one of the numeric types.
> There is no string involved.
> IllegalArgumentException would be more correct.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira