-
Notifications
You must be signed in to change notification settings - Fork 1.1k
SerialVersionUID on class MessageHistory Breaking change : from version 5.5.2 to latest #3737
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
We can and an explicit As a workaround I only see a way to copy/paste a WDYT? |
I think we can set the explicit Thoughts? |
Thanks, @onobc ! I think this is brilliant. Here is a result of that command for me:
would you mind to confirm from your side? |
@german22 you could also try to run w/ PR branch to verify. |
Hi, Thanks a lot for your help. |
@onobc , here is the value for the current class:
|
Fixes #3737 * Add an explicit `serialVersionUID` to `MessageHistory` to avoid class version conflicts in the future. See related GH issue for the workaround **Cherry-pick to `5.5.x`**
Fixes #3737 * Add an explicit `serialVersionUID` to `MessageHistory` to avoid class version conflicts in the future. See related GH issue for the workaround **Cherry-pick to `5.5.x`**
Here is the code sample for the suggested workaround. It is a custom deserializer that allows a configurable set of "alternative" The one annoyance of the workaround is that you have to set the deserializer on whatever store you are using that is currently failing to deser the objects.
UsageThis assumes a JDBC message store is being used (adjust accordingly). VersionTolerantJavaDeserializer deser = new VersionTolerantJavaDeserializer();
deser.allowSerialVersionUID(MessageHistory.class, 1426799817181873282L);
JdbcMessageStore messageStore = ...
messageStore.setDeserializer(deser);
Message<MessageHistory> oldMsg = messageStore.getMessage(oldMsgId); Workaround
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import org.springframework.core.NestedIOException;
import org.springframework.core.serializer.Deserializer;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* A {@link Deserializer} implementation that reads an input stream using Java serialization in a manner that
* allows {@link Serializable} classes to be deserialized with more than one {@code serialVersionUID}.
*
* @author Chris Bono
*/
public class VersionTolerantJavaDeserializer implements Deserializer<Object> {
private final MultiValueMap<Class<?>, Long> alternativeSerialVersionUIDs = new LinkedMultiValueMap<>();
/**
* Allows an alternative {@code serialVersionUID} to be used when deserializing a class.
* @param clazz the class
* @param serialVersionUID the alternate uid to allow
*/
public void allowSerialVersionUID(Class<?> clazz, long serialVersionUID) {
this.alternativeSerialVersionUIDs.add(clazz, serialVersionUID);
}
@Override
public Object deserialize(InputStream inputStream) throws IOException {
VersionTolerantObjectInputStream objectInputStream = new VersionTolerantObjectInputStream(inputStream);
try {
return objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to deserialize object type", ex);
}
}
private final class VersionTolerantObjectInputStream extends ObjectInputStream {
private VersionTolerantObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
String className = resultClassDescriptor.getName();
Class<?> localClass = Class.forName(className);
if (!alternativeSerialVersionUIDs().containsKey(localClass)) {
return resultClassDescriptor;
}
ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
if (localClassDescriptor == null) {
return resultClassDescriptor;
}
final long localSerialVersionUID = localClassDescriptor.getSerialVersionUID();
final long streamSerialVersionUID = resultClassDescriptor.getSerialVersionUID();
if (streamSerialVersionUID != localSerialVersionUID && alternativeSerialVersionUIDs().get(localClass)
.contains(streamSerialVersionUID)) {
return localClassDescriptor;
}
return resultClassDescriptor;
}
private MultiValueMap<Class<?>, Long> alternativeSerialVersionUIDs() {
return VersionTolerantJavaDeserializer.this.alternativeSerialVersionUIDs;
}
}
} Let us know how it goes @german22 |
Uh oh!
There was an error while loading. Please reload this page.
In what version(s) of Spring Integration are you seeing this issue?
After the version 5.5.2 until now
bug
The Class MessageHistory is a serializable class that doesn't have a SerialVersionUID defined, because of that it was taken the default SerialVersionUID created with the previous version.
Now this class was updated in the commit :
af9e69c
Where the equals/hashCode was implemented
Because of that, after the version 5.5.2 the serialVersionUID changed
This change of serialVersionUID makes the previos version incompatible with the new one, because the serialVersionUID matching fails when it tries to deserialize the class.
To Reproduce
Use spring integration with the version 5.5.1 to store a new record, and then update the version to the 5.5.2 or latest to read this record, and it will fails
Expected behavior
Deserialize the class MessageHistory stored in previous versions to the 5.5.2
Is it possible to fix this problem ?
Is there any workaround that we can implement in the meantime ?
Thanks a lot
The text was updated successfully, but these errors were encountered: