java- ClassCastException- BigInt cannot be cast to Long - java

I have two columns in my table are which is BigInt data type (NODEID and ULNODEID) and I want to keep it that way. I am using MYSQL workbench 8.0 for these table.
I want to get the value of my nodeid using the function below:
public long get_urlnodeid(long nodeID) {
try {
String sql = "select NODEID from urllink where ULNODEID="+nodeID;
if (em == null) {
throw new Exception("could not found URL object.");
}
return (long) em.createNativeQuery(sql).getSingleResult();
} catch (Exception e) {
msg = CoreUtil.wrapMsg(CoreUtil.FUNC_ERROR,
this.getClass().getName(), "get", e.getMessage());
}
return 0;
}
It throws an exception saying Big Integer cannot be cast to java.lang.Long
Is there a way I can retrieve the value while keeping it in long?

Just look at the Java doc for BigInteger:
public long longValue()
Converts this BigInteger to a long. This conversion is analogous to a narrowing primitive conversion from long to int as defined in section 5.1.3 of 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.
So you'd want something like this:
return ((BigInteger)em.createNativeQuery(sql).getSingleResult()).longValue();
I would recommend adding some type checking.
--
Another option, if you have full control of your application, and you expect values that go beyond the range of long, is to have your method return BigInteger instead of long:
public BigInteger get_urlnodeid(long nodeID) {
And:
return (BigInteger) em.createNativeQuery(sql).getSingleResult();
Of course then the rest of your application that calls this method has to work with BigInteger as well.
Please be aware that using BigInteger instead of long is much less performant, so only use this if performance is not an issue or if you are absolutely sure that values will be so big that this is absolutely necessary.

Related

Handle long min value condition

When I ran a program, long min value is getting persisted instead of original value coming from the backend.
I am using the code:
if (columnName.equals(Fields.NOTIONAL)) {
orderData.notional(getNewValue(data));
As output of this, i am getting long min value, instead of original value.
I tried using this method to handle the scenario
public String getNewValue(Object data) {
return ((Long)data).getLong("0")==Long.MIN_VALUE?"":((Long)data).toString();
}
but doesn't work.
Please suggest
EDITED: I misread the code in the question; rereading it, I now get what the author is trying to do, and cleaned up the suggestion as a consequence.
(Long) data).getLong("0") is a silly way to write null, because that doesn't do anything. It retrieves the system property named '0', and then attempts to parse it as a Long value. As in, if you start your VM with java -D0=1234 com.foo.YourClass, that returns 1234. I don't even know what you're attempting to accomplish with this call. Obviously it is not equal to Long.MIN_VALUE, thus the method returns ((Long) data).toString(). If data is in fact a Long representing MIN_VALUE, you'll get the digits of MIN_VALUE, clearly not what you wanted.
Try this:
public String getNewValue(Object data) {
if (data instanceof Number) {
long v = ((Number) data).longValue();
return v == Long.MIN_VALUE ? "" : data.toString();
}
// what do you want to return if the input isn't a numeric object at all?
return "";

java.lang.Integer cannot be cast to java.lang.Long

I'm supposed to receive long integer in my web service.
long ipInt = (long) obj.get("ipInt");
When I test my program and put ipInt value = 2886872928, it give me success.
However, when I test my program and put ipInt value = 167844168, it give me error :
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
The error is point to the above code.
FYI, my data is in JSON format :
{
"uuID": "user001",
"ipInt": 16744168,
"latiTude": 0,
"longiTude": 0,
}
Is there any suggestion so that I can ensure my code able to receive both ipInteger value?
Both Integer and Long are subclasses of Number, so I suspect you can use:
long ipInt = ((Number) obj.get("ipInt")).longValue();
That should work whether the value returned by obj.get("ipInt") is an Integer reference or a Long reference. It has the downside that it will also silently continue if ipInt has been specified as a floating point number (e.g. "ipInt": 1.5) in the JSON, where you might want to throw an exception instead.
You could use instanceof instead to check for Long and Integer specifically, but it would be pretty ugly.
We don't know what obj.get() returns so it's hard to say precisely, but when I use such methods that return Number subclasses, I find it safer to cast it to Number and call the appropriate xxxValue(), rather than letting the auto-unboxing throw the ClassCastException:
long ipInt = ((Number)obj.get("ipInt")).longValue();
That way, you're doing explicit unboxing to a long, and are able to cope with data that could include a ., which would return a Float or Double instead.
Long.valueOf(jo.get("ipInt").toString());
Is ok.
in kotlin I simply use this:
val myInt: Int = 10
val myLong = myInt.toLong()
You mention the current approach works when you provide a value outside the range of integer, but fails when you are within the integer range. That is an odd behavior for an API, because it seems you need to check the return type yourself. You can do that. The usual way is with instanceof. Something like,
long ipInt;
Object o = obj.get("ipInt");
if (o instanceof Integer) {
ipInt = ((Integer) o).intValue();
} else if (o instanceof Long) {
ipInt = ((Long) o).longValue();
}
public static void main(String[] args) {
JSONObject jo = JSON.parseObject(
"{ \"uuID\": \"user001\", \"ipInt\": 16744168, \"latiTude\": 0, \"longiTude\": 0}");
System.out.println(jo);
long sellerId1 = Long.valueOf(jo.get("ipInt").toString());
//Long sellerId1 = (long)jo.get("ipInt");
System.out.println(sellerId1);
}

Java : What is the best way to check variable type in runtime?

I want to know the best way to check variable type at runtime.
public Iterator<?> read(String entityName, String propertyName, Object propertyValue) {
String query = "select * from " + entityName + " where " + propertyName + "=";
try {
int value = Integer.parseInt((String)propertyValue);
query=query+value;
} catch (NumberFormatException e) {
// failed
}
try {
String value = (String)propertyValue;
query=query+"'"+value+"'";
} catch (ClassCastException e) {
// failed
}
try {
float value = Float.parseFloat((String)propertyValue);
query=query+value;
} catch (NumberFormatException e) {
// failed
}
//Creating JDBC connection and execute query
Iterator<Element> result=queryConn.execute();
return result;
}
I need to check the variable type is int, float or String during runtime. Is there any other best way to do this?
Or Do I need to write seperate method for each variable type?
try this code :
if(floatVariable instanceof Float){}
if(intVariable instanceof Integer){}
if(stringVariable instanceof String){}
There are many ways to handle this scenario.
Use function overloading for different data types
Use instanceof operator to determine data type
Try to cast property value in any numeric data type, if successfully castes then ignore single quotes otherwise apply single quotes
since you are getting object as input you can always check using instanceof keyword.And instead of using primitives try using classes like(Integer.class).And one more thing is you should use PreparedStatement always.Your code is prone to SqlInjection.
Is there any other best way to do this?
I would recommend that you name the columns you want to select in your actual query. If you take this approach, you can parse each column as the appropriate type without worrying about type casting issues. If, for example, the first column selected were an integer type, then you would just call Integer.parseInt() without worrying about having the wrong type.
And here is an argument why using SELECT * is an anti-pattern:
If you use SELECT * as your query, then we don't even know how many columns are being returned. To even take a guess at that, we would have to analyze how many columns your code seems to expect. But, what would happen if someone were to change the schema, thereby possibly changing the order in which the RDBMS returns columns? Then your entire application logic might have to change.

How to convert Session attribute converting to long in java?

long orgId = (Long)request.getSession().getAttribute("orgId");
I am not able to convert the object that I am getting from request.getSession().getAttribute("orgId")
to long variable
So I need to convert it to long.
Could anyway help.
This way is not the best way to proceed, it's too prone to error (and you are assuming orgId value is present as session's attribute and unboxing, in case orgId is null/not present, will throw an exception).
final long orgId;
Object sessionValue = request.getSession().getAttribute("orgId");
if(sessionValue != null) {
if(sessionValue instanceof Long)
{
orgId = ((Long)sessionValue).longValue();
}
else if(if(sessionValue instanceof String) {
orgId = Long.parseLong((String)sessionValue);
}
else {
// you can set orgId = 0, throw exception, do custom conversion
}
}
else {
// manage missed value
}
It depends upon the type of the "orgId" attribute. If it really is a Long, your code should work. If you've for instance added it as a String, you need to convert it to a long with Long.parseLong:
long orgId = Long.parseLong((String)request.getSession().getAttribute("orgId"));
This the common way to do this
String strOrgId = (String) request.getSession().getAttribute("orgId");
Then parse this value to Long
long orgId = Long.parseLong(strOrgId);
It depends on how is your "orgId" stored in session attributes, as a String instance or a Long instance.
Following code is little bit redundant but will work for both cases:
Object attribute = request.getSession().getAttribute("orgId");
long orgId = Long.parseLong(String.valueOf(attribute));
I had a similar problem.. I stored a long in the session, and when I wanted to get the attribute it was automatically deserialized to an Integer OR Long dependent on their size. This was really annoying..
So in my case the solution was to convert to a string and than parse it to a Long:
Object orgIdObject = session.getAttribute("orgId");
Long orgId;
// first, make a null check. you'll never know
if (orgIdObject == null) {
// if value is null, set to -1 or throw and error..
orgId = -1L;
} else {
// convert to string, and then parse to long
orgId = Long.valueOf(orgIdObject.toString());
}
In this way, it does not matter if the Object is a String, Integer or Long. It works with all that types.
Happy Coding,
Kalasch

In Java, calling a PostgreSQL function, why I'm getting an error informing that the function doesn't exists?

I have this procedure in the database:
CREATE OR REPLACE FUNCTION replacePageRelevance(id INT, value REAL) RETURNS VOID AS $$
BEGIN
INSERT INTO pageRelevance VALUES (id,value);
EXCEPTION WHEN unique_violation THEN
UPDATE pageRelevance SET relevance = value WHERE pageId = id;
END
$$
LANGUAGE plpgsql;
And this code that calls this function:
try (CallableStatement cstm = conn.prepareCall(PAGE_RELEVANCE_SQL)) {
for (Map.Entry<Integer, Double> entry : weightMap.entrySet()) {
cstm.setInt(1, entry.getKey());
cstm.setDouble(2, entry.getValue());
cstm.addBatch();
}
cstm.executeBatch();
} catch (SQLException e) {
LOGGER.error("Error discovering pages relevance: " + e.getNextException());
}
}
This is not working, I'm getting an error informing that function replacepagerelevance(integer, double precision) doesn't exists.. Why?
The generated call is this: SELECT replacePageRelevance('882','8.0'). If I execute this in pgAdmin, it works, but not from Java.
It's because your PL/pgSQL function is defined as:
replacePageRelevance(id INT, value REAL)
REAL is a single precision floating point, but on Java side you're trying to use it as double precision and there is no implicit casting for such situation.
You should rather use CallableStatement.setFloat for single precision REAL datatype, however it's not co clear, becuase reading Java API:
Sets the designated parameter to the given Java float value. The
driver converts this to an SQL FLOAT value when it sends it to the
database.
Since FLOAT is a synonym for DOUBLE PRECISION in Postgres it runs with same effect as CallableStatement.setDouble producing error message (that's weird).
Of course you could just change your function to replacePageRelevance(id INT, value DOUBLE PRECISION) and as I checked it works well with your code.
Nevertheless, If you want to keep REAL in your function), then use explicit cast like this:
String PAGE_RELEVANCE_SQL = "{call replacePageRelevance(?, ?::real)}";

Categories