To start with there are packages from IBM & Legstar to generate Java classes from Cobol Copybooks. My own package JRecord is could also be used, but it is orientated to files rather than on-line processing.
Basically the last character of the field holds the sign + number. I am guessing the data is coming from the mainframe; So for US - Ebcdic (CP037 / IBM237) the last digit will be
0 1 2 3 4 5 6 7 8 9
positive { A B C D E F G H I
negative } J K L M N O P Q R
So for +123 it will be 00000012C (C = +3) and -123 will be 00000012L.
To make matters worse, +0 and -0 are different in different EBCIDIC dialects and ASCII as well. So you either need to know exactly which version of Ebcidic is being used or you need to do the conversion at byte level.
The fromZoned method in JRecord Conversion does the conversion:
private static int positiveDiff = 'A' - '1';
private static int negativeDiff = 'J' - '1';
private static char positive0EbcdicZoned = '{';
private static char negative0EbcdicZoned = '}';
public static String fromZoned(String numZoned) {
String ret;
String sign = "";
char lastChar, ucLastChar;
if (numZoned == null || ((ret = numZoned.trim()).length() == 0) || ret.equals("-")) {
return "";
}
lastChar = ret.charAt(ret.length() - 1);
ucLastChar = Character.toUpperCase(lastChar);
switch (ucLastChar) {
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I':
lastChar = (char) (ucLastChar - positiveDiff);
break;
case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R':
sign = "-";
lastChar = (char) (ucLastChar - negativeDiff);
break;
default:
if (lastChar == positive0EbcdicZoned) {
lastChar = '0';
} else if (lastChar == negative0EbcdicZoned) {
lastChar = '0';
sign = "-";
}
}
ret = sign + ret.substring(0, ret.length() - 1) + lastChar;
return ret;
}
But it is easier to do at byte level it should be like the following (Code is not tested though):
private static final byte HIGH_NYBLE = (byte) 0xf0;
private static final byte LOW_NYBLE = (byte) 0x0f;
private static final byte ZONED_POSITIVE_NYBLE_OR = (byte) 0xCF;
private static final byte ZONED_NEGATIVE_NYBLE_OR = (byte) 0xDF;
private static final byte ZONED_NEGATIVE_NYBLE_VALUE = (byte) 0xD0;
signByte = bytes[bytes.length - 1];
negative = false;
if (((byte) (signByte & HIGH_NYBLE)) == ZONED_NEGATIVE_NYBLE_VALUE) {
negative = true;
}
long result = 0;
for (int i = 0; i < bytes.length; i++) {
result = result * 10 + (bytes[i] & LOW_NYBLE);
}
if (negative) {
result = -1 * result;
}