[
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