Last active
December 21, 2015 21:48
-
-
Save magro/6370466 to your computer and use it in GitHub Desktop.
A custom kryo serializer for the Spring Security User class - for memcached-session-manager's kryo serialization.
Can be registered as customConverter in the msm config (see https://code.google.com/p/memcached-session-manager/wiki/SetupAndConfiguration), s.th. like: <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" ... tra…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.javakaffee.web.msm.serializer.kryo; | |
import java.nio.ByteBuffer; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.List; | |
import org.springframework.security.core.GrantedAuthority; | |
import org.springframework.security.core.userdetails.User; | |
import com.esotericsoftware.kryo.Kryo; | |
import com.esotericsoftware.kryo.serialize.IntSerializer; | |
import com.esotericsoftware.kryo.serialize.SimpleSerializer; | |
import com.esotericsoftware.kryo.serialize.StringSerializer; | |
/** | |
* Provides a custom kryo serializer for the Spring Security User class. | |
* <p> | |
* This is needed because the User class internally contains a collection | |
* of {@link GrantedAuthority}, which is actually a TreeSet with a | |
* Comparator. During deserialization kryo creates a TreeSet *without* | |
* any comparator and therefore expects that the contained items are | |
* Comparable, which is not the case for SimpleGrantedAuthority - ClassCastException. | |
* </p> | |
* <p> | |
* Motivated by <a href="http://code.google.com/p/memcached-session-manager/issues/detail?id=145"> | |
* issue #145: Deserialization fails on ConcurrentHashMap in Spring User object | |
* </a>. | |
* </p> | |
* @author Martin Grotzke | |
*/ | |
public class SpringSecurityUserRegistration implements KryoCustomization { | |
@Override | |
public void customize(final Kryo kryo) { | |
kryo.register( User.class, new SpringSecurityUserSerializer( kryo ) ); | |
} | |
static class SpringSecurityUserSerializer extends SimpleSerializer<User> { | |
private final Kryo _kryo; | |
public SpringSecurityUserSerializer(final Kryo kryo) { | |
_kryo = kryo; | |
} | |
@Override | |
public User read(final ByteBuffer buffer) { | |
final String password = StringSerializer.get(buffer); | |
final String username = StringSerializer.get(buffer); | |
final int size = IntSerializer.get(buffer, true); | |
final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(size); | |
for (int i = 0; i < size; i++) { | |
authorities.add((GrantedAuthority)_kryo.readClassAndObject(buffer)); | |
} | |
final boolean accountNonExpired = buffer.get() == 1; | |
final boolean accountNonLocked = buffer.get() == 1; | |
final boolean credentialsNonExpired = buffer.get() == 1; | |
final boolean enabled = buffer.get() == 1; | |
return new User(username, password, enabled, accountNonExpired, credentialsNonExpired, | |
accountNonLocked, authorities); | |
} | |
@Override | |
public void write(final ByteBuffer buffer, final User user) { | |
StringSerializer.put(buffer, user.getPassword()); | |
StringSerializer.put(buffer, user.getUsername()); | |
final Collection<GrantedAuthority> authorities = user.getAuthorities(); | |
IntSerializer.put(buffer, authorities.size(), true); | |
for (final GrantedAuthority item : authorities) { | |
_kryo.writeClassAndObject(buffer, item); | |
} | |
put(buffer, user.isAccountNonExpired()); | |
put(buffer, user.isAccountNonLocked()); | |
put(buffer, user.isCredentialsNonExpired()); | |
put(buffer, user.isEnabled()); | |
} | |
private void put(final ByteBuffer buffer, final boolean value) { | |
buffer.put(value ? (byte)1 : (byte)0); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, Martin, i add config transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
customConverter="de.javakaffee.web.msm.serializer.kryo.SpringSecurityUserRegistration"
in tomcat config,and i get this error.
INFO: Could not store session 5E8DA4A26B75BE055E19E55CF6DC64E7-n1 in memcached.
java.util.concurrent.ExecutionException: com.esotericsoftware.kryo.SerializationException: Unable to serialize object of type: java.util.concurrent.ConcurrentHashMap
at de.javakaffee.web.msm.BackupSessionService$SynchronousExecutorService.submit(BackupSessionService.java:348)
at de.javakaffee.web.msm.BackupSessionService.backupSession(BackupSessionService.java:205)
at de.javakaffee.web.msm.MemcachedSessionService.backupSession(MemcachedSessionService.java:1040)
at de.javakaffee.web.msm.RequestTrackingHostValve.backupSession(RequestTrackingHostValve.java:230)
at de.javakaffee.web.msm.RequestTrackingHostValve.invoke(RequestTrackingHostValve.java:159)
at de.javakaffee.web.msm.RequestTrackingHostValve.invoke(RequestTrackingHostValve.java:124)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2442)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2431)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: com.esotericsoftware.kryo.SerializationException: Unable to serialize object of type: java.util.concurrent.ConcurrentHashMap
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:524)
at com.esotericsoftware.kryo.ObjectBuffer.writeObject(ObjectBuffer.java:251)
at de.javakaffee.web.msm.serializer.kryo.KryoTranscoder.serializeAttributes(KryoTranscoder.java:303)
at de.javakaffee.web.msm.TranscoderService.serializeAttributes(TranscoderService.java:155)
at de.javakaffee.web.msm.BackupSessionTask.serializeAttributes(BackupSessionTask.java:176)
at de.javakaffee.web.msm.BackupSessionTask.call(BackupSessionTask.java:110)
at de.javakaffee.web.msm.BackupSessionTask.call(BackupSessionTask.java:51)
at de.javakaffee.web.msm.BackupSessionService$SynchronousExecutorService.submit(BackupSessionService.java:346)
... 17 more
Caused by: com.esotericsoftware.kryo.SerializationException: Unable to serialize object of type: org.springframework.security.core.context.SecurityContextImpl
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:493)
at com.esotericsoftware.kryo.serialize.MapSerializer.writeObjectData(MapSerializer.java:104)
at de.javakaffee.kryoserializers.CopyForIterateMapSerializer.writeObjectData(CopyForIterateMapSerializer.java:56)
at com.esotericsoftware.kryo.Serializer.writeObject(Serializer.java:43)
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:520)
... 24 more
Caused by: com.esotericsoftware.kryo.SerializationException: Serialization trace:
principal (org.springframework.security.authentication.UsernamePasswordAuthenticationToken)
authentication (org.springframework.security.core.context.SecurityContextImpl)
at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:191)
at com.esotericsoftware.kryo.serialize.ReferenceFieldSerializer.writeObjectData(ReferenceFieldSerializer.java:52)
at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:175)
at com.esotericsoftware.kryo.serialize.ReferenceFieldSerializer.writeObjectData(ReferenceFieldSerializer.java:52)
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:489)
... 28 more
Caused by: java.lang.NullPointerException
at com.esotericsoftware.kryo.serialize.StringSerializer.put(StringSerializer.java:29)
at de.javakaffee.web.msm.serializer.kryo.SpringSecurityUserRegistration$SpringSecurityUserSerializer.write(SpringSecurityUserRegistration.java:68)
at de.javakaffee.web.msm.serializer.kryo.SpringSecurityUserRegistration$SpringSecurityUserSerializer.write(SpringSecurityUserRegistration.java:39)
at com.esotericsoftware.kryo.serialize.SimpleSerializer.writeObjectData(SimpleSerializer.java:17)
at com.esotericsoftware.kryo.serialize.FieldSerializer.writeObjectData(FieldSerializer.java:175)
... 32 more
Could you help me ? thx.