This questions has many answers and I have seen them. I have code that has been working but today suddenly it starting throwing java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
for the line
return null == input.get(keyName) ? 0L : (long) input.get(keyName);
Error is coming from (long) input.get(keyName). I wonder why it starting breaking all of sudden. (long) input.get(keyName) this looks good to me.
I thought of doing ((Integer) input.get(keyName)).longValue() but was getting java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer as map sometimes contains long values. Any suggestions
Stacktrace:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
at accountservice.adapter.batch.testJob.SyncDriverPartitioner.getLongValueFromMap(SyncDriverPartitioner.java:78) ~[classes/:?]
at accountservice.adapter.batch.testJob.SyncDriverPartitioner.partition(SyncDriverPartitioner.java:47) ~[classes/:?]
at accountservice.adapter.batch.testJob.SyncDriverPartitioner$$FastClassBySpringCGLIB$$6f3315e4.invoke(<generated>) ~[classes/:?]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.18.RELEASE.jar:4.3.18.RELEASE]
You can take advantage of the fact that all numeric primitive wrappers extend java.lang.Number:
return null == input.get(keyName) ? 0L : ((Number) input.get(keyName)).longValue();
As to why it started giving errors suddenly; really the only likely reason is that up until it started failing, you were always putting java.lang.Long objects in the input Map, and it changed so you're also putting java.lang.Integer in them now.
It's quite easy for that to happen with auto-boxing and numeric constants:
long v = 42;
input.put("key", v); // Puts a java.lang.Long in the map
input.put("key", 42); // Puts a java.lang.Integer in the map
input.put("key", 42L); // Puts a java.lang.Long in the map
You can avoid it by declare your Map type-safely (Map<String, Long>). If you do that, input.put("key", 42) will give a compile-time error.
Rather than casting an int to a long I would suggest:
return null == input.get(keyName) ? 0L : Integer.toUnsignedLong(input.get(keyName))
At least this way you should get some more information about why it cannot be converted to a long rather than just a ClassCastException
Answer Update
Based on your comments I guess you are going to have to check type of the entry in Map before processing it, I would suggest the following:
Object keyValue = input.get(keyName);
if (null == keyValue) return 0L;
String valueType = keyValue.getClass().getTypeName();
if (valueType.equals(Long.class.getTypeName())) {
return (long) keyValue;
}
if (valueType.equals(Integer.class.getTypeName())) {
return Integer.toUnsignedLong((int) keyValue);
}
throw new TypeMismatchException(String.format("Type '%s' is not supported...", valueType));
This will let you define different operations for different types of entry, it is extendable to any types you want to support. You can tweak the exception thrown as well to provide you relevant information.
The snippet above shows you the actual type so that you can extend your code to support that type, or work out why something of that type got into your map.
It should be noted that it would probably be better to do this when data is entered into the map, not when it's taken out of the map. In which case you should be able to change your map to a type . It's always better to sanitise your imputes than trying to deal with a mishmash of mixed data types at a later date.
Related
I'm trying to create a feed management system. I have created a simple get and post request for the servlet. I'm able to store the data in the datastore successfully as milliseconds.
But when I retrieve it
long milliseconds = entity.getProperty("timestamp");
I get some error like this
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
What will be the reason for this issue?
Well, apparently in
long milliseconds = entity.getProperty("timestamp");
entity returns a String, which you assign to a long. This requires a typecast.
Note that Entity (or its superclass, PropertyContainer) explicitly states
The value returned may not be the same type as originally set via setProperty
So - what to do? If you know that you're getting a String, and you want to interpret it as a long: Use the proper conversion method (which is not a typecast).
long longValue = Long.parseLong(stringValue);
...but prepare for NumberFormatExceptions in cases where you convert actual, non-numeric Strings.
Apparently, you are trying to retrieve a String of number format which you want to cast to a long value. The first thing you will have to do is to check whether the value obtained from entity.getProperty("timestamp") returns a number. There's is a special library called Apache Commons Lang 3 that allows to check if your string is of numeric format. If it's the case, then it's a simple implicit cast to long value that you should do. Your code should look as follows,ASSUMING ENTITY IS NOT NULL:
import org.apache.commons.lang3.math.NumberUtils;
if(NumberUtils.isCreatable(entity.getProperty("timestamp")){
long milliseconds = Long.parseLong(entity.getProperty("timestamp"));
}
else{
//print the information you want to identify the value of the property
//for example:
System.out.println("The following value cannot be parsed to long : " +
entity.getProperty("timestamp"));
}
I'm experiencing a ClassCastException with the following piece of code.
Set<Long> purchaseIds = confirmationCodeToPurchase
.entrySet()
.stream()
.map(Map.Entry::getValue)
.map(purchase -> (Long)purchase.getPurchaseId())
.collect(Collectors.toSet()))
confirmationCodeToPurchase is a map from a confirmation code (String) to a Purchase type.
I'm extracting just the values of the map (the purchases), getting the purchaseId of each, and putting them into a set.
I get this error:
java.lang.ClassCastException: java.lang.Long cannot be cast to Purchase
and the line at which it errors is the collection line. .collect(Collectors.toSet()))
From your error description, it looks like your method purchase.getPurchaseId() returns an object that is not of type Long. That's why you get a class cast exception. Instead of casting, you can build the Long object from the return value of this method, assuming it is either String or an integer type.
Replace
.map(purchase -> (Long)purchase.getPurchaseId())
with
.map(purchase -> Long.valueOf(purchase.getPurchaseId()))
I am trying to insert object into Firestore using Android Studio, it gives an error message:
java.lang.IllegalArgumentException: Invalid data. Unsupported type: java.math.BigDecimal
How can I insert BigDecimal into Firestore?
Check Firestore's supported types. If you need anything else, convert to a supported type, then convert back when you read. Typically, you'd use String for BigDecimal. If you need comparisons, zero-pad to your theoretical maximum, or store in another field as Double.
You could do something like this (in Kotlin):
class Model() {
#get:PropertyName("value")
#set:PropertyName("value")
var firestoreValue: String = "0"
var value: BigDecimal
#Exclude get() = firestoreValue.toBigDecimal()
#Exclude set(value) { firestoreValue = value.toPlainString() }
}
Haven't found a better solution so far. Would be nice if it was possible to implement converters (like TypeAdapters for Gson) for unsupported types.
I have an aggregation:
AggregationResults<Integer> result = mongoTemplate.aggregate(
Aggregation.newAggregation(
Aggregation.group().count().as("value"),
Aggregation.project("value").andExclude("_id"),
MyData.class, Integer.class);
In the mongo shell, when I don't have to map an object, I get: { "value" : 2 }
However, I get the following error when trying to map this lone value: org.springframework.data.mapping.model.MappingException: No mapping metadata found for java.lang.Integer
Can I get around having to create a new output type class, when I only want to get a single java primitive?
Note: I'm going this approach instead of db.collection.count() for the sharding inaccuracies stated here - https://docs.mongodb.com/manual/reference/method/db.collection.count/#sharded-clusters
AggregationResults<DBObject> result = mongoTemplate.aggregate(
Aggregation.newAggregation(
Aggregation.group().count().as("value"),
Aggregation.project("value").andExclude("_id"),
MyData.class, DBObject.class);
int count = (Integer) result.getUniqueMappedResult().get("value");
So, not exactly what I wanted, because I still have to traverse over an object, but it's not any more code than I had before and I didn't need to make another class as the outputType.
In my code
List<Fdjobs> fdjobs=new ArrayList<Fdjobs>();
fdjobs = (ArrayList<Fdjobs>)genericDao.namedQuery(Fdjobs.QUERYJOBS, hm);
Integer deactivateValue=new Integer(0);
for (Fdjobs job : fdjobs) {
job.setActiveJob(deactivateValue);
job.addFDJobHistory();
genericDao.update(job);
}
if the size of the result list fdjobs is zero i dont get ant error but if the size is more than zero i am getting the error
[Ljava.lang.Object; cannot be cast to com.duncansolutions.databus.bean.Fdjobs
nameQuery() method not returning the Type
ArrayList<Fdjobs>
please debug it. you can use
ArrayList<Object>
for this.
The error is simple: you get a Object[] ([Ljava.lang.Object) instead of a Fdjobs object in the List returned from your namedQuery.
So the bug is either in your for-each loop or in namedQuery which depends on what you want to achieve.