Jackcess addRow() cannot insert a Java 'long' value - java

I'm trying to add a row with id number 3791318595.
long l = 3791318595L;
myTable.addRow(l,"testing");
however Jackcess transforms it into an integer and cuts to its max value:
2,147,483,647.
How can I correctly add the above number with Jackcess?

If the "id number" field in the Access table is defined as Number (Long Integer) then the short answer to your question is:
You can't.
A Long Integer in Access is a 32-bit signed integer whose maximum value is (2^31)-1 as you have seen. That is, a Long Integer in Access corresponds to int (not long) in Java. The value you are trying to insert into the Access field simply will not fit "as is", so there is no way that Jackcess (or any other application) can do it.
If your "id numbers" are all positive integers then one possible workaround would be to have your code mimic unsigned 32-bit integers by wrapping values between 2,147,483,648 and 4,294,967,296 to their non-positive signed values:
long unsignedAdjustment = 4294967296L; // 2^32
long l = 3791318595L; // our test value
if (l > unsignedAdjustment) {
System.out.println("Error: ID value too large to fit, even if wrapped to non-positive integer.");
}
else {
int signedID = 0;
if (l > 2147483647L) { // (2^31)-1
signedID = (int) (l - unsignedAdjustment);
}
else {
signedID = (int) l;
}
myTable.addRow(signedID, "testing");
}
That would store the row in the Access table with an "id number" of -503,648,701. Of course...
it would be up to your code to perform the corresponding conversion when retrieving rows, and
this approach has obvious implications for searching and ordering by "id number"
...but if the "id number" is really just a unique row identifier then it may not be too much of an inconvenience.

Related

Convert string to byte getting number format exception

public class HelloWorld{
public static void main(String []args){
String str = "100.00";
Short sObj2 = Short.valueOf(str);
System.out.println(sObj2);
}
}
Getting below exception :
Exception in thread "main" java.lang.NumberFormatException: For input string: "100.00"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Short.parseShort(Short.java:118)
at java.lang.Short.valueOf(Short.java:174)
at java.lang.Short.valueOf(Short.java:200)
at HelloWorld.main(HelloWorld.java:5)
How to resolve above issue?
First a Short is not a byte (your question summary indicates you are trying to convert a string to a byte). A Short holds integer values from -32,768 to 32,767 (inclusive). Trying to parse a floating point value into an integer datatype causes this exception.
If you simply want code that will run without an exception, either of the following should work:
public class HelloWorld{
public static void main(String []args){
String str = "100";
Short sObj2 = Short.valueOf(str);
System.out.println(sObj2);
}
}
This first example makes it run by changing the string to an integer value.
or
public class HelloWorld{
public static void main(String []args){
String str = "100.00";
Double sObj2 = Double.valueOf(str);
System.out.println(sObj2);
}
}
This second one works by parsing a string representing a floating point value into a variable type that supports floating points.
Try this
String str = "100";
Short sObj2 = Short.valueOf(str);
or if you want to deal with decimal values,
String str = "100.00";
Float fObj2 = Float.valueOf(str);
To begin with, as your post title suggests, you want to convert from a String data type to a byte data type. This doesn't necessarily include just displaying the a value which doesn't generate a NumberFormatException error. I'm assuming you actually want to work with those particular data types.
To throw a small twist into things, you want to convert all this from a string representation of a numerical value which can be from either a float or double data type ("100.00"). It's this decimal point within the numerical string that throws a glitch into things when doing any conversion and therefore needs to be handled before doing any such thing.
Some things to consider:
As a String, you can represent any number you like in any format you like. It can be as big as you want and it can be as small as you want. I can even be a number that is imaginary or doesn't exist, but the bottom line is....it will always be a String and you can do such things with String data types. Converting a String numerical value to an actual numerical data type such as byte, short, integer, long, double, float, etc is a different ball game altogether. Some String numerical values are easy to convert and yet some require more specific attention to detail.
A byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
A short data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive).
The int (integer) data type is a 32-bit signed two's complement integer, which has a minimum value of -2147483648 and a maximum value of 2147483647.
The long data type is a 64-bit two's complement integer. The signed long has a minimum value of -9223372036854775808 and a maximum value of 9223372036854775807.
At the end of it all these four data types all maintain integer values with each data type also maintaining a minimum and maximum of values. You need to also consider this to some extent when doing data type conversions. If you are going to create a conversion method to convert from one data type to another you need to ensure that you do not exceed that minimum and maximum allowable value for the data type you want to convert to. Not a big deal if you want to convert a byte data type to a short data type or a short to an integer since we know that the lesser will always play in the larger but this is not necessarily so when a larger is to play in a lesser (short to byte).
Your conversion method needs to check the value to convert so as to ensure it will actually fit into the desired data type. Java has constants to assist you with this so that you don't have to remember these minimums and maximums, for example: Integer.MIN_VALUE and Integer.MAX_VALUE or Byte.MIN_VALUE and Byte.MAX_VALUE.
When dealing with numerical strings you may also want to ensure that the string you're dealing with is actually a string representation of a numerical value and not a alphanumeric value such as that of a Hexidecimal string or just a plain out entry error whereas a character other than a digit has crept into the string somehow. In my opinion, the string: "100.00" is a string representation of both a alphanumeric value (because of the period) and a numeric value since it is a string representation of a double data type. What it will truly be depends upon how you handle the period (decimal point) in the string within your conversion method.
Let's take another look at that string value ("100.00"). Another thing you may want to consider is, what if our string value was: "100.74"? How do you want to handle this particular value? Do you want to Round Down to 100 or *Round Up to 101 before you convert it to a data type that requires a integer value?
Let's convert the String representation of the value "100.00" to a short data type. Now keep in mind that the methods I provide below by default will always convert a string representation of a double data type (if supplied) downwards, for example 100.45 or 100.99 will be 100. If you want to properly round up or down for this type of value then supply a boolean true in the optional roundUpDown argument:
private short StringToShort(final String input, final boolean... roundUpDown) {
// Make sure there no dead whitespaces...
String inputValue = input.replaceAll(" ", "");
int i = 0; // default return value is 0
// If inputValue contains nothing ("") then return 0
if(inputValue.equals("")) { return 0; }
// Is inputValue an actual numerical value?
// Throws an exception if not.
// Handles negative and decimal point...
if (!inputValue.matches("-?\\d+(\\.\\d+)?")) {
throw new IllegalArgumentException("\nStringToShort() Method Error!\n"
+ "The value supplied is not numeric (" + inputValue + ").\n");
}
// Was the optional roundUpDown argument supplied?
boolean round = false; // default is false
if (roundUpDown.length > 0) { round = roundUpDown[0]; }
// Convert the String to a Integer value
if (inputValue.contains(".")) {
// Must be a double type representation supplied
Double value = Double.parseDouble(inputValue);
if (round) { i = (int) Math.round(value); }
else { i = (int) value.intValue(); }
}
else {
// Must be a Integer type representation supplied
i = Integer.parseInt(inputValue);
}
// Is the Integer value now too small or too
// large to be a Short data type?
if (i > Short.MAX_VALUE || i < Short.MIN_VALUE) {
throw new IllegalArgumentException("\nStringToShort() Method Error!\n"
+ "The value supplied is too small or too large (" + inputValue + ").\n"
+ "Only values from " + Short.MIN_VALUE + " to " + Short.MAX_VALUE
+ " are allowed!\n");
}
// Finally, cast and return a short data type...
return (short) i;
}
If you read all the comments within the code you can see that we've covered all the issues discussed above. Now, according to your post title, you wanted to convert to byte. Well, it's pretty much the very same method but with perhaps five or so small changes done, see if you can spot them:
private byte StringToByte(final String input, final boolean... roundUpDown) {
// Make sure there no dead whitespaces...
String inputValue = input.replaceAll(" ", "");
int i = 0; // default return value is 0
// If inputValue contains nothing ("") then return 0
if(inputValue.equals("")) { return 0; }
// Is inputValue an actual numerical value?
// Throws an exception if not.
// Handles negative and decimal point...
if (!inputValue.matches("-?\\d+(\\.\\d+)?")) {
throw new IllegalArgumentException("\nStringToByte() Method Error!\n"
+ "The value supplied is not numeric (" + inputValue + ").\n");
}
// Was the optional roundUpDown argument supplied?
boolean round = false; // default is false
if (roundUpDown.length > 0) { round = roundUpDown[0]; }
// Convert the String to a Integer value
if (inputValue.contains(".")) {
// Must be a double type representation supplied
Double value = Double.parseDouble(inputValue);
if (round) { i = (int) Math.round(value); }
else { i = (int) value.intValue(); }
}
else {
// Must be a Integer type representation supplied
i = Integer.parseInt(inputValue);
}
// Is the Integer value now too small or too
// large to be a Byte data type?
if (i > Byte.MAX_VALUE || i < Byte.MIN_VALUE) {
throw new IllegalArgumentException("\nStringToByte() Method Error!\n"
+ "The value supplied is too small or too large (" + inputValue + ").\n"
+ "Only values from " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE
+ " are allowed!\n");
}
// Finally, cast and return a byte data type...
return (byte) i;
}

Oracle ojdbc driver returns float result for integer values in NUMBER type column

I have Oracle 10g database and Java application based on Spring 4.1.6 framework, which extracts some data out of Oracle. I faced an issue, that ojdbc driver returns float result for integer values in NUMBER type column. ResultSet metadata identifies object type as BigDecimal.
Column definition:
MINUTES NUMBER with no precision and scale
Actual value is "70"
I have checked with Oracle 10, 11 and 12 ojdbc drivers and every time the same Java code returns "70.0000000000000000000000000000000000002 as value of this column in a row. I have also checked with Oracle SQL Developer 4.1.1 and it shows the same incorrect float value.
Toad however shows correct value "70".
Any ideas ? Please note again: **This issue is reproduced in Oracle SQL Developer 4.1.1 **
Update - Java code below :
for (int j = 1; j <= count; j++) {
Object field = resultSet.getObject(j);
if (field != null) {
bufferedWriter.write(field.toString());
}
if (j < count) {
bufferedWriter.write(delimiter);
}
}
The NUMBER datatype stores fixed and floating-point numbers. When you specify numeric fields, it is a good idea to specify the precision and scale. This provides extra integrity checking on input.
NUMBER (precision, scale)
But, if a precision is not specified the column stores values as given i.e. maximum scale and maximum precision(up to 38 digits of precision). As given, it will behave as Float in java. Example of sample input given below :
Input Stored As
7,456,123.89 7456123.89
A lot more info at Oracle Data Type.
Especially this section :
Internal Numeric Format
Oracle Database stores numeric data in variable-length format. Each value is stored in scientific notation, with 1 byte used to store the exponent and up to 20 bytes to store the mantissa. The resulting value is limited to 38 digits of precision. Oracle Database does not store leading and trailing zeros. For example, the number 412 is stored in a format similar to 4.12 x 102, with 1 byte used to store the exponent(2) and 2 bytes used to store the three significant digits of the mantissa(4,1,2). Negative numbers include the sign in their length.
So, If you want to store Integer value only, change the column definition to NUMBER(10,0) which is as close as you can get to Integer in java. Otherwise, strip the trailing zeros from BigDecimal
Code edited :
for (int j = 1; j <= count; j++) {
BigDecimal field = (BigDecimal)resultSet.getObject(j);
if (field != null) {
bufferedWriter.write(field.stripTrailingZeros().toString());
}
if (j < count) {
bufferedWriter.write(delimiter);
}
}
Or Explicitly cast to Integer (to lose decimal part)
for (int j = 1; j <= count; j++) {
Integer field = (Integer)resultSet.getObject(j);
if (field != null) {
bufferedWriter.write(field.toString());
}
if (j < count) {
bufferedWriter.write(delimiter);
}
}

Generating a unique integer ID from a String

I need to generate a unique integer id for a string.
Reason:
I have a database application that can run on different databases. This databases contains parameters with parameter types that are generated from external xml data.
the current situation is that i use the ordinal number of the Enum. But when a parameter is inserted or removed, the ordinals get mixed up:
(FOOD = 0 , TOYS = 1) <--> (FOOD = 0, NONFOOD = 1, TOYS = 2)
The ammount of Parameter types is between 200 and 2000, so i am scared a bit using hashCode() for a string.
P.S.: I am using Java.
Thanks a lot
I would use a mapping table in the database to map these Strings to an auto increment value. These mapping should then be cached in the application.
Use a cryptographic hash. MD5 would probably be sufficient and relatively fast. It will be unique enough for your set of input.
How can I generate an MD5 hash?
The only problem is that the hash is 128 bits, so a standard 64-bit integer won't hold it.
If you need to be absolute certain that the id are unique (no collissions) and your strings are up to 32 chars, and your number must be of no more than 10 digits (approx 32 bits), you obviously cannot do it by a one way function id=F(string).
The natural way is to keep some mapping of the string to unique numbers (typically a sequence), either in the DB or in the application.
If you know the type of string values (length, letter patterns), you can count the total number of strings in this set and if it fits within 32 bits, the count function is your integer value.
Otherwise, the string itself is your integer value (integer in math terms, not Java).
By Enum you mean a Java Enum? Then you could give each enum value a unique int by your self instead of using its ordinal number:
public enum MyEnum {
FOOD(0),
TOYS(1),
private final int id;
private MyEnum(int id)
{
this.id = id;
}
}
I came across this post that's sensible: How to convert string to unique identifier in Java
In it the author describes his implementation:
public static long longHash(String string) {
long h = 98764321261L;
int l = string.length();
char[] chars = string.toCharArray();
for (int i = 0; i < l; i++) {
h = 31*h + chars[i];
}
return h;
}

How to check if number fits primitive type in java?

I need do to some input validation but run into a question and I do not seem to find an answer (even with Google). The problem is simple: I have 2 positive integers on the input, and I need to check if their product fits int type in Java.
One of my attempts was to compare product with Integer.MAX_VALUE, but it seems if the product is too big for integer, value becomes negative.
I wanted to reason that product is too big by change in sign, but it seems if the product is "way too big" it will become positive again.
Could someone advise me how to detect if number becomes too big?
Many thanks in advance!
If you are doing a UI, you are presumably in no particular hurry. So you could use a BigInteger and then test the product against MAX_VALUE.
Cast the value to int and see if the value is the same. A simple check looks like
double d =
long l =
BigInteger bi =
if (d == (int) d) // can be represented as an int.
if (l == (int) l) // can be represented as an int.
int i = bi.intValue();
if (bi.equals(BigInteger.valueOf(i)))
If the value is the same when cast back, there is no loss of information and you can use an int value.
Searched and found the following:
Java is cavalier about overflow. There are no compile-time warnings or run-time exceptions to let you know when your calculations have become too big to store back in an int or long. There is no warning for float or double overflow either.
/**
* multiplies the two parameters, throwing a MyOverflowException if the result is not an int.
* #param a multiplier
* #param b multiplicand
* #result product
*/
public static int multSafe(int a, int b) throws MyOverflowException
{
long result = (long)a * (long)b;
int desiredhibits = - ((int)( result >>> 31 ) & 1);
int actualhibits = (int)( result >>> 32 );
if ( desiredhibits == actualhibits )
{
return(int)result;
}
else
{
throw new MyOverflowException( a + " * " + b + " = " + result );
}
}
You could create a BigInteger from your input value and use its intValue() method to convert. If the BigInteger is too big to fit in an int, only the low-order 32 bits are returned. So you need to compare the resulting value to your input value to ensure it was not truncated.

Checking if value of int[] can be long

I have an array of ints ie. [1,2,3,4,5] . Each row corresponds to decimal value, so 5 is 1's, 4 is 10's, 3 is 100's which gives value of 12345 that I calculate and store as long.
This is the function :
public long valueOf(int[]x) {
int multiplier = 1;
value = 0;
for (int i=x.length-1; i >=0; i--) {
value += x[i]*multiplier;
multiplier *= 10;
}
return value;
}
Now I would like to check if value of other int[] does not exceed long before I will calculate its value with valueOf(). How to check it ?
Should I use table.length or maybe convert it to String and send to
public Long(String s) ?
Or maybe just add exception to throw in the valueOf() function ?
I hope you know that this is a horrible way to store large integers: just use BigInteger.
But if you really want to check for exceeding some value, just make sure the length of the array is less than or equal to 19. Then you could compare each cell individually with the value in Long.MAX_VALUE. Or you could just use BigInteger.
Short answer: All longs fit in 18 digits. So if you know that there are no leading zeros, then just check x.length<=18. If you might have leading zeros, you'll have to loop through the array to count how many and adjust accordingly.
A flaw to this is that some 19-digit numbers are valid longs, namely those less than, I believe it comes to, 9223372036854775807. So if you wanted to be truly precise, you'd have to say length>19 is bad, length<19 is good, length==19 you'd have to check digit-by-digit. Depending on what you're up to, rejecting a subset of numbers that would really work might be acceptable.
As others have implied, the bigger question is: Why are you doing this? If this is some sort of data conversion where you're getting numbers as a string of digits from some external source and need to convert this to a long, cool. If you're trying to create a class to handle numbers bigger than will fit in a long, what you're doing is both inefficient and unnecessary. Inefficient because you could pack much more than one decimal digit into an int, and doing so would give all sorts of storage and performance improvements. Unnecessary because BigInteger already does this. Why not just use BigInteger?
Of course if it's a homework problem, that's a different story.
Are you guaranteed that every value of x will be nonnegative?
If so, you could do this:
public long valueOf(int[]x) {
int multiplier = 1;
long value = 0; // Note that you need the type here, which you did not have
for (int i=x.length-1; i >=0; i--) {
next_val = x[i]*multiplier;
if (Long.MAX_LONG - next_val < value) {
// Error-handling code here, however you
// want to handle this case.
} else {
value += next_val
}
multiplier *= 10;
}
return value;
}
Of course, BigInteger would make this much simpler. But I don't know what your problem specs are.

Categories

Resources