Kryo serialized bytes into Object giving exceptions

123 views
Skip to first unread message

Sheena Chawla

unread,
May 26, 2021, 5:01:59 AM5/26/21
to kryo-users
Hi all,

I am trying to serialise nested hashmaps via Kryo writeObject and the resultant bytes are casted into java.lang.Object and sent to a different service via HTTPS call. 
While deserialising the object into bytes, it gives String casting exception. 
'java.lang.String can't be cast into [B'

I tried to convert byte array into string and then cast that String into Object and then pass it, but that is taking longer time than what Kryo serialisers take.

Any idea on how can this serialization be handled then? 

P.S - The serialization and deserialization work perfectly fine when not casted in Object and casting it in object is the only way I have for now.


Thomas Heigl

unread,
May 26, 2021, 5:50:12 AM5/26/21
to kryo-...@googlegroups.com
Hi Sheena,

Please share a minimal example of your deserialization code. It's not possible to diagnose this issue from the information you provided so far.

Thomas

--
You received this message because you are subscribed to the "kryo-users" group.
http://groups.google.com/group/kryo-users
---
You received this message because you are subscribed to the Google Groups "kryo-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kryo-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kryo-users/50e33b35-bd7f-4a38-b1fd-1c5faa90553dn%40googlegroups.com.

Sheena Chawla

unread,
May 26, 2021, 10:34:01 AM5/26/21
to kryo-users

Request Class:
@JsonInclude(Include.NON_NULL)
public class ComputeRequest {
private Map<String, Object> additionalProperties = new HashMap();

public ComputeRequest() {
}

public String toString() {
return ToStringBuilder.reflectionToString(this);
}

public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}

public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperties(String name, Object value) {
this.additionalProperties.put(name, value);
}
}


Serialization Logic:
Map<String, String> eqData = (ConcurrentHashMap) ctx.get(EnhancerConstants.EVENT_QUERY_RESULT_LIST);
Map<String, byte[]> eqMap = new HashMap<>();
for (Map.Entry<String, String> entry : eqData.entrySet()) { 
  List<?> results = (List<?>) ctx.get(key);
  if (results != null && results.size() != 0) {
     byte[] serialisedResults = KryoClassRegistration.kryoContext.serialze(results); //
Using Kryo Serialization here
     eqMap.putIfAbsent(key, serialisedResults);
    }
 }
request.setAdditionalProperties(EnhancerConstants.AUDIT_EVENT_QUERY_KRYO, eqMap); //This class is mentioned above, the value is set as an Object rather than bytes


Deserialization Logic:

Map<String, byte[]> eqData = (HashMap<String, byte[]>) (request.getAdditionalProperties().get(EnhancerConstants.AUDIT_EVENT_QUERY_KRYO)); // Here Object is casted into byte[]
for (Map.Entry<String, byte[]> result : eqData.entrySet()) {
try {
  String key = result.getKey();
  List<?> value = (ArrayList) KryoClassRegistration.kryoContext.deserialze(ArrayList.class, result.getValue()); 
//Using Kryo Deserialization here
  ctx.put(key, value);
} catch (Exception err) {
 // This is giving exception  "java.lang.String can't be cast into [B"
}
}
Serialization and deserialization logics are in 2 different services and the only way to send these data is in additional property which is String, Object.
Also, the logic works fine when bytes are directly deserialised rather than having Object hop in between.

Let me know if I was able to make my query clear.

Thanks,

thomas...@gmail.com

unread,
May 26, 2021, 11:45:22 AM5/26/21
to kryo-users
I'm guessing that the map received in EnhancerConstants.AUDIT_EVENT_QUERY_KRYO is not really a map Map<String, byte[]>, but a Map<String, String>. If you can, debug this, set a breakpoint in your deserialization code and take a look at what the map really contains. Or simply log the map contents.

I'm pretty sure that this problem has nothing to do with Kryo at all but your code fails at exactly this line, when you access result.getValue() and your code casts it to a byte[]:

> List<?> value = (ArrayList) KryoClassRegistration.kryoContext.deserialze(ArrayList.class, result.getValue()); 

Sheena Chawla

unread,
May 26, 2021, 1:33:30 PM5/26/21
to kryo-users
Yup, the map is Map<String, String> though I tried to cast it in Map<String, byte[]> and the cast is successful as well but when I start to access the result.getValue(), this error comes up. Do you suggest any way of handling it? 
I have tried to cast the byte array to string and then backforth but it takes up lot of time, so any better way suggested? Does Kryo have any other datatype which it can serialise too?

Thanks

Thomas Heigl

unread,
May 26, 2021, 2:25:04 PM5/26/21
to kryo-...@googlegroups.com
Casting doesn't do anything. You can't cast a Map<String, String> to a Map<String, byte[]> and expect it to work. It's still a Map<String, String> just with a wrong type signature.

You can try to convert the String back to a byte array (String.getBytes() or String.getBytes(StandardCharsets.UTF_8)) and deserialize that.

Thomas


You received this message because you are subscribed to a topic in the Google Groups "kryo-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kryo-users/UJCB_6dPtQc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kryo-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kryo-users/68cdbf6f-85b8-4e4a-a60f-0f5add02750cn%40googlegroups.com.

Sheena Chawla

unread,
May 27, 2021, 12:39:59 AM5/27/21
to kryo-users
I am not casting specifically to Map<String, String>. All I did was casting Map<String, byte[]> to Object, not even a Map but just Object. This internally, when trying to cast the Object back to Map<String, byte[]> makes it Map<String, String> rather than byte[]. 
Also, I have tried casting Map<String, byte[]> to Map<String, String> explicitly but the performance is bad, so wanted to check if there is any other way that you suggest so that performance is not compromised or if I am missing out on something?

Thanks

Joachim Durchholz

unread,
May 27, 2021, 2:33:31 AM5/27/21
to kryo-...@googlegroups.com
Am 26.05.21 um 19:33 schrieb Sheena Chawla:
> Yup, the map is Map<String, String> though I tried to cast it in
> Map<String, byte[]> and the cast is successful as well

In Java, casts check just the main type (Map), not the generic
parameters (<String, String>).

This is due to "type erasure"; at runtime, generic types like
Map<String, String> are represented as Map<?,?>, and that's what the
runtime cast can check.

Regards,
Jo

Joachim Durchholz

unread,
May 27, 2021, 2:35:30 AM5/27/21
to kryo-...@googlegroups.com
Am 27.05.21 um 06:39 schrieb Sheena Chawla:
> I am not casting specifically to Map<String, String>. All I did was
> casting Map<String, byte[]> to Object, not even a Map but just Object.
> This internally, when trying to cast the Object back to Map<String,
> byte[]> makes it Map<String, String> rather than byte[].
> Also, I have tried casting Map<String, byte[]> to Map<String, String>
> explicitly but the performance is bad,

A cast does not do much, it's essentially just a run-time check of the
object type (ignoring generic parameters because of type erasure).
If there was a performance problem, it must have some other reason.
Either cast happening inside a tight loop, or something completely
unrelated.

Regards,
Jo

Sheena Chawla

unread,
May 27, 2021, 5:24:49 AM5/27/21
to kryo-users
But that's actually causing runtime exception - 'java.lang.string can't be cast into [B' . Performance problem is when bytes are not sent as bytes but as string and then converting back string to bytes. 
Or there is something that I am missing here?

Sheena Chawla

unread,
May 27, 2021, 5:28:27 AM5/27/21
to kryo-users
List<?> value = (ArrayList) KryoClassRegistration.kryoContext.deserialze(ArrayList.class, result.getValue()); // when bytes[]  are passed for deserialization

Joachim Durchholz

unread,
May 27, 2021, 6:56:16 PM5/27/21
to kryo-...@googlegroups.com
You need to understand generics, and how type erasure makes compile-time
and run-time type information different.

At compile time, it's a Map<String, String>, or a Map<String, byte[]>,
or Object.

At runtime, it is always Map, or (equivalently) Map<?,?>.

Casting does not change the run-time type of the object, it will still
be a Map.

A cast from Object to Map<String, byte[]> will make the Java compiler
insert a check that the run-time object is indeed a Map, but it will not
check the data elements. I.e. the runtime type is Map<?,?> - it's a Map,
but the key and values could be any type, the JVM does not know (the
information about the key and value types is "erased", that's what "type
erasure" means).

Since Java is supposed to be a safe language, the type checks happen
whenever a specific key or value is accessed.
Actually the checks will *always* happen. If you have a
Map<String,byte[]>, when writing a value the byte[] will be cast to
Object (which is zero-cost) and cast back to byte[] when your code reads
from the Map and assigns to a byte[] variable.

Conversions between String and byte[] happen if and only if you
explicitly write that in your code, there's no automatic conversion for
that.

Am 27.05.21 um 11:24 schrieb Sheena Chawla:
> --
> You received this message because you are subscribed to the "kryo-users"
> group.
> http://groups.google.com/group/kryo-users
> <http://groups.google.com/group/kryo-users>
> ---
> You received this message because you are subscribed to the Google
> Groups "kryo-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to kryo-users+...@googlegroups.com
> <mailto:kryo-users+...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/kryo-users/a6b11ba6-40ea-4420-9800-7c5e7fae26ccn%40googlegroups.com
> <https://groups.google.com/d/msgid/kryo-users/a6b11ba6-40ea-4420-9800-7c5e7fae26ccn%40googlegroups.com?utm_medium=email&utm_source=footer>.

Reply all
Reply to author
Forward
0 new messages