forked from EsotericSoftware/kryo
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix EsotericSoftware#100: Add LocaleSerializer
For deserialization by default (and if available) the static `Locale.getInstance(String, String, String)` is used via reflection to make use of the Locale cache. If Locale.getInstance is not available it just falls back to the constructor. If the `Locale(String, String, String)` constructor should be used in any case the `LocaleSerializer(boolean)` has to be used with `useReflection` set to `false`.
- Loading branch information
Showing
2 changed files
with
93 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
|
||
package com.esotericsoftware.kryo.serializers; | ||
|
||
import java.lang.reflect.Method; | ||
import java.math.BigDecimal; | ||
import java.math.BigInteger; | ||
import java.nio.ByteBuffer; | ||
import java.util.Calendar; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
|
@@ -12,6 +14,7 @@ | |
import java.util.EnumSet; | ||
import java.util.GregorianCalendar; | ||
import java.util.List; | ||
import java.util.Locale; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
import java.util.Set; | ||
|
@@ -29,6 +32,8 @@ | |
|
||
import static com.esotericsoftware.kryo.Kryo.*; | ||
import static com.esotericsoftware.kryo.util.Util.*; | ||
import static com.esotericsoftware.minlog.Log.TRACE; | ||
import static com.esotericsoftware.minlog.Log.trace; | ||
|
||
/** Contains many serializer classes that are provided by {@link Kryo#addDefaultSerializer(Class, Class) default}. | ||
* @author Nathan Sweet <[email protected]> */ | ||
|
@@ -574,4 +579,76 @@ protected TreeSet createCopy (Kryo kryo, Collection original) { | |
return new TreeSet(((TreeSet)original).comparator()); | ||
} | ||
} | ||
|
||
/** | ||
* Serializer for {@link Locale}. | ||
* <p> | ||
* For deserialization by default (and if available) the static method <code>Locale.getInstance(String, String, String)</code> | ||
* is used via reflection to make use of the Locale cache.<br/> | ||
* To use the {@link Locale#Locale(String, String, String) Locale(String, String, String)} constructor instead the | ||
* {@link LocaleSerializer#LocaleSerializer(boolean) LocaleSerializer(boolean)} has to be used with <code>useReflection</code> | ||
* set to <code>false</code>. | ||
* </p> | ||
* | ||
* @author <a href="mailto:[email protected]">Martin Grotzke</a> | ||
*/ | ||
static public class LocaleSerializer extends Serializer<Locale> { | ||
|
||
private static Method getInstance; | ||
|
||
static { | ||
try { | ||
getInstance = Locale.class.getDeclaredMethod("getInstance", String.class, String.class, String.class); | ||
getInstance.setAccessible(true); | ||
} catch (final Exception e) { | ||
if (TRACE) trace("kryo", "java.util.Locale.getInstance is not available"); | ||
getInstance = null; | ||
} | ||
} | ||
|
||
private final boolean useReflection; | ||
|
||
/** | ||
* Creates a new instance with {@link #useReflection} set to <code>true</code>. | ||
* | ||
* @see #LocaleSerializer(boolean) | ||
*/ | ||
public LocaleSerializer() { | ||
this(true); | ||
} | ||
|
||
/** | ||
* Creates a new instance and activates the usage of reflection (for getting the | ||
* {@link Locale} during deserialization) if <code>true</code> was provided for <code>useReflection</code> | ||
* and if the static method <code>Locale.getInstance(String, String, String)</code> is available. | ||
* | ||
* @param useReflection asks to activate reflection usage. | ||
*/ | ||
public LocaleSerializer(final boolean useReflection) { | ||
setImmutable(true); | ||
this.useReflection = getInstance != null && useReflection; | ||
} | ||
|
||
@Override | ||
public void write (Kryo kryo, Output output, Locale object) { | ||
output.writeString(object.getLanguage()); | ||
output.writeString(object.getCountry()); | ||
output.writeString(object.getVariant()); | ||
} | ||
|
||
@Override | ||
public Locale read (Kryo kryo, Input input, Class<Locale> type) { | ||
final String language = input.readString(); | ||
final String country = input.readString(); | ||
final String variant = input.readString(); | ||
if(useReflection) { | ||
try { | ||
return (Locale) getInstance.invoke(null, language, country, variant); | ||
} catch (final Exception e) { | ||
throw new RuntimeException("Could not get Locale using Locale.getInstance", e); | ||
} | ||
} | ||
return new Locale(language, country, variant); | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,10 +8,12 @@ | |
import java.util.Collections; | ||
import java.util.Date; | ||
import java.util.EnumSet; | ||
import java.util.Locale; | ||
import java.util.TimeZone; | ||
|
||
import com.esotericsoftware.kryo.io.Input; | ||
import com.esotericsoftware.kryo.io.Output; | ||
import com.esotericsoftware.kryo.serializers.DefaultSerializers.LocaleSerializer; | ||
|
||
/** @author Nathan Sweet <[email protected]> */ | ||
public class DefaultSerializersTest extends KryoTestCase { | ||
|
@@ -279,6 +281,20 @@ public void testClassSerializer() { | |
assertEquals(TestEnum.class, kryo.readObject(in, Class.class)); | ||
} | ||
|
||
public void testLocaleUsingReflection() { | ||
doTestLocale(true); | ||
} | ||
|
||
public void testLocaleUsingConstructor() { | ||
doTestLocale(false); | ||
} | ||
|
||
private void doTestLocale (boolean useReflection) { | ||
kryo.setRegistrationRequired(true); | ||
kryo.register(Locale.class, new LocaleSerializer(useReflection)); | ||
roundTrip(5, 5, Locale.ENGLISH); | ||
} | ||
|
||
public enum TestEnum { | ||
a, b, c | ||
} | ||
|