Serializers/test/dorkbox/serializers/KryoTest.kt

890 lines
33 KiB
Kotlin

/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.serializers
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.KryoException
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import com.esotericsoftware.kryo.serializers.DefaultSerializers
import dorkbox.serializers.TestClasses.ClassWithoutDefaultConstructor
import dorkbox.serializers.TestClasses.CounterHolder
import dorkbox.serializers.TestClasses.CounterHolderArray
import dorkbox.serializers.TestClasses.Email
import dorkbox.serializers.TestClasses.HashMapWithIntConstructorOnly
import dorkbox.serializers.TestClasses.HolderArray
import dorkbox.serializers.TestClasses.HolderList
import dorkbox.serializers.TestClasses.MyContainer
import dorkbox.serializers.TestClasses.Person
import dorkbox.serializers.TestClasses.Person.Gender
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import java.lang.reflect.Modifier
import java.math.BigDecimal
import java.net.URI
import java.sql.Time
import java.sql.Timestamp
import java.util.*
import java.util.concurrent.atomic.*
import java.util.regex.*
/**
* Test for [Kryo] serialization.
*
* @author [Martin Grotzke](mailto:martin.grotzke@javakaffee.de)
*/
class KryoTest {
@Volatile
private var _kryo: Kryo = Kryo()
@Before
fun beforeTest() {
_kryo = object : Kryo() { // @Override
// public Serializer<?> getDefaultSerializer( final Class type ) {
// if ( EnumSet.class.isAssignableFrom( type ) ) {
// return new EnumMapSerializer();
// }
// if ( EnumMap.class.isAssignableFrom( type ) ) {
// return new EnumMapSerializer();
// }
// return super.getDefaultSerializer( type );
// }
}
_kryo.isRegistrationRequired = false
_kryo.register(listOf("").javaClass, DefaultSerializers.CollectionsSingletonListSerializer())
_kryo.register(Pattern::class.java, RegexSerializer())
_kryo.register(EnumMap::class.java, EnumMapSerializer())
_kryo.register(UUID::class.java, DefaultSerializers.UUIDSerializer())
UnmodifiableCollectionsSerializer.registerSerializers(_kryo)
SynchronizedCollectionsSerializer.registerSerializers(_kryo)
}
@Test
@Throws(Exception::class)
fun testSingletonList() {
val obj: List<*> = listOf("foo")
val deserialized = deserialize(serialize(obj), obj.javaClass)
assertDeepEquals(deserialized, obj)
}
@Test
@Throws(Exception::class)
fun testCopySingletonList() {
val obj: List<*> = listOf("foo")
val copy = _kryo.copy(obj)
assertDeepEquals(copy, obj)
}
@Test
@Throws(Exception::class)
fun testSingletonSet() {
val obj: Set<*> = setOf("foo")
val deserialized = deserialize(serialize(obj), obj.javaClass)
assertDeepEquals(deserialized, obj)
}
@Test
@Throws(Exception::class)
fun testCopySingletonSet() {
val obj: Set<*> = setOf("foo")
val copy = _kryo.copy(obj)
assertDeepEquals(copy, obj)
}
@Test
@Throws(Exception::class)
fun testSingletonMap() {
val obj: Map<*, *> = Collections.singletonMap("foo", "bar")
val deserialized = deserialize(serialize(obj), obj.javaClass)
assertDeepEquals(deserialized, obj)
}
@Test
@Throws(Exception::class)
fun testCopySingletonMap() {
val obj: Map<*, *> = Collections.singletonMap("foo", "bar")
val copy = _kryo.copy(obj)
assertDeepEquals(copy, obj)
}
@Test
@Throws(Exception::class)
fun testEnumSet() {
val set: EnumSet<*> = EnumSet.allOf(Gender::class.java)
val deserialized = deserialize(serialize(set), set.javaClass)
assertDeepEquals(deserialized, set)
}
@Test
@Throws(Exception::class)
fun testEmptyEnumSet() {
val set: EnumSet<*> = EnumSet.allOf(Gender::class.java)
val deserialized = deserialize(serialize(set), set.javaClass)
assertDeepEquals(deserialized, set)
}
@Test
@Throws(Exception::class)
fun testCopyEnumSet() {
val set: EnumSet<*> = EnumSet.allOf(Gender::class.java)
val copy = _kryo.copy(set)
assertDeepEquals(copy, set)
}
@Test
@Throws(Exception::class)
fun testEnumMap() {
val map = EnumMap<Gender, String>(Gender::class.java)
val value = "foo"
map[Gender.FEMALE] = value
// Another entry with the same value - to check reference handling
map[Gender.MALE] = value
val deserialized = deserialize(serialize(map), map.javaClass)
assertDeepEquals(deserialized, map)
}
@Test(expected = KryoException::class)
@Throws(Exception::class)
fun testEmptyEnumMap() {
val map = EnumMap<Gender, String>(Gender::class.java)
val deserialized = deserialize(serialize(map), map.javaClass)
assertDeepEquals(deserialized, map)
}
@Test
@Throws(Exception::class)
fun testCopyEnumMap() {
val map = EnumMap<Gender, String>(Gender::class.java)
val value = "foo"
map[Gender.FEMALE] = value
val copy = _kryo.copy(map)
assertDeepEquals(copy, map)
}
/**
* test that insertion order is retained.
*/
@Test
@Throws(Exception::class)
fun testCopyForIterateMapSerializer() {
val map: MutableMap<Double, String> = LinkedHashMap()
// use doubles as e.g. integers hash to the value...
for (i in 0..9) {
map[java.lang.Double.valueOf(i.toString() + "." + Math.abs(i))] = "value: $i"
}
val deserialized: Map<Double, String> = deserialize(serialize(map), map.javaClass)
assertDeepEquals(deserialized, map)
}
@Test
@Throws(Exception::class)
fun testGregorianCalendar() {
val cal = TestClasses.Holder(Calendar.getInstance(Locale.ENGLISH))
val deserialized = deserialize(serialize(cal), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, cal)
val item = deserialized.item as Calendar
Assert.assertEquals(item.timeInMillis, cal.item.timeInMillis)
Assert.assertEquals(item.timeZone, cal.item.timeZone)
Assert.assertEquals(item.minimalDaysInFirstWeek.toLong(), cal.item.minimalDaysInFirstWeek.toLong())
Assert.assertEquals(item.firstDayOfWeek.toLong(), cal.item.firstDayOfWeek.toLong())
Assert.assertEquals(item.isLenient, cal.item.isLenient)
}
@Test
@Throws(Exception::class)
fun testCopyGregorianCalendar() {
val cal = TestClasses.Holder(Calendar.getInstance(Locale.ENGLISH))
val copy = _kryo.copy(cal)
assertDeepEquals(copy, cal)
Assert.assertEquals(copy.item.timeInMillis, cal.item.timeInMillis)
Assert.assertEquals(copy.item.timeZone, cal.item.timeZone)
Assert.assertEquals(copy.item.minimalDaysInFirstWeek.toLong(), cal.item.minimalDaysInFirstWeek.toLong())
Assert.assertEquals(copy.item.firstDayOfWeek.toLong(), cal.item.firstDayOfWeek.toLong())
Assert.assertEquals(copy.item.isLenient, cal.item.isLenient)
}
@Test
@Throws(Exception::class)
fun testJavaUtilDate() {
val cal = TestClasses.Holder(java.util.Date(System.currentTimeMillis()))
val deserialized = deserialize(serialize(cal), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, cal)
val item = deserialized.item as Date
Assert.assertEquals(item.time, cal.item.time)
}
@Test
@Throws(Exception::class)
fun testCopyJavaUtilDate() {
val cal = TestClasses.Holder(java.util.Date(System.currentTimeMillis()))
val copy = _kryo.copy(cal)
assertDeepEquals(copy, cal)
Assert.assertEquals(copy.item.time, cal.item.time)
}
@Test
@Throws(Exception::class)
fun testJavaSqlTimestamp() {
val cal = TestClasses.Holder(Timestamp(System.currentTimeMillis()))
val deserialized = deserialize(serialize(cal), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, cal)
val item = deserialized.item as Timestamp
Assert.assertEquals(item.time, cal.item.time)
}
@Test
@Throws(Exception::class)
fun testCopyJavaSqlTimestamp() {
val cal = TestClasses.Holder(Timestamp(System.currentTimeMillis()))
val copy = _kryo.copy(cal)
assertDeepEquals(copy, cal)
Assert.assertEquals(copy.item.time, cal.item.time)
}
@Test
@Throws(Exception::class)
fun testJavaSqlDate() {
val date = TestClasses.Holder(Date(System.currentTimeMillis()))
val deserialized = deserialize(serialize(date), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, date)
val item = deserialized.item as Date
Assert.assertEquals(item.time, date.item.time)
}
@Test
@Throws(Exception::class)
fun testCopyJavaSqlDate() {
val date = TestClasses.Holder(Date(System.currentTimeMillis()))
val copy = _kryo.copy(date)
assertDeepEquals(copy, date)
Assert.assertEquals(copy.item.time, date.item.time)
}
@Test
@Throws(Exception::class)
fun testJavaSqlTime() {
val time = TestClasses.Holder(Time(System.currentTimeMillis()))
val deserialized = deserialize(serialize(time), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, time)
val item = deserialized.item as Time
Assert.assertEquals(item.time, time.item.time)
}
@Test
@Throws(Exception::class)
fun testCopyJavaSqlTime() {
val time = TestClasses.Holder(Time(System.currentTimeMillis()))
val copy = _kryo.copy(time)
assertDeepEquals(copy, time)
Assert.assertEquals(copy.item.time, time.item.time)
}
@Test
@Throws(Exception::class)
fun testBitSet() {
val bitSet = BitSet(10)
bitSet.flip(2)
bitSet.flip(4)
val holder = TestClasses.Holder(bitSet)
val deserialized = deserialize(serialize(holder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, holder)
}
@Test
@Throws(Exception::class)
fun testCopyBitSet() {
val bitSet = BitSet(10)
bitSet.flip(2)
bitSet.flip(4)
val copy = _kryo.copy(bitSet)
assertDeepEquals(copy, bitSet)
}
@Test
@Throws(Exception::class)
fun testURI() {
val uri = TestClasses.Holder(URI("http://www.google.com"))
val deserialized = deserialize(serialize(uri), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, uri)
}
@Test
@Throws(Exception::class)
fun testCopyURI() {
val uri = TestClasses.Holder(URI("http://www.google.com"))
val copy = _kryo.copy(uri)
assertDeepEquals(copy, uri)
}
@Test
@Throws(Exception::class)
fun testUUID() {
val uuid = TestClasses.Holder(UUID.randomUUID())
val deserialized = deserialize(serialize(uuid), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, uuid)
}
@Test
@Throws(Exception::class)
fun testCopyUUID() {
val uuid = TestClasses.Holder(UUID.randomUUID())
val copy = _kryo.copy(uuid)
assertDeepEquals(copy, uuid)
}
@Test
@Throws(Exception::class)
fun testRegex() {
val pattern = TestClasses.Holder(Pattern.compile("regex"))
val deserialized = deserialize(serialize(pattern), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, pattern)
val patternWithFlags = TestClasses.Holder(Pattern.compile("\n", Pattern.MULTILINE or Pattern.CASE_INSENSITIVE))
val deserializedWithFlags = deserialize(serialize(patternWithFlags), TestClasses.Holder::class.java)
assertDeepEquals(deserializedWithFlags, patternWithFlags)
}
@Test
@Throws(Exception::class)
fun testCopyRegex() {
val pattern = TestClasses.Holder(Pattern.compile("regex"))
val copy = _kryo.copy(pattern)
assertDeepEquals(copy, pattern)
val patternWithFlags = TestClasses.Holder(Pattern.compile("\n", Pattern.MULTILINE or Pattern.CASE_INSENSITIVE))
val copyWithFlags = _kryo.copy(patternWithFlags)
assertDeepEquals(copyWithFlags, patternWithFlags)
}
@Test
@Throws(Exception::class)
fun testStringBuffer() {
val stringBuffer = StringBuffer("<stringbuffer>with some content \n& some lines...</stringbuffer>")
val deserialized = deserialize(serialize(stringBuffer), StringBuffer::class.java)
assertDeepEquals(deserialized, stringBuffer)
}
@Test
@Throws(Exception::class)
fun testStringBuilder() {
val stringBuilder = StringBuilder("<stringbuilder>with some content \n& some lines...</stringbuilder>")
val deserialized = deserialize(serialize(stringBuilder), StringBuilder::class.java)
assertDeepEquals(deserialized, stringBuilder)
}
@Test
@Throws(Exception::class)
fun testMapWithIntConstructorOnly() {
val map = HashMapWithIntConstructorOnly(5)
val deserialized = deserialize(serialize(map), HashMapWithIntConstructorOnly::class.java)
assertDeepEquals(deserialized, map)
}
@Test
@Throws(Exception::class)
fun testCurrency() {
val currency = Currency.getInstance("EUR")
val deserialized = deserialize(serialize(currency), Currency::class.java)
assertDeepEquals(deserialized, currency)
// Check that the transient field defaultFractionDigits is initialized correctly
Assert.assertEquals(deserialized.currencyCode, currency.currencyCode)
Assert.assertEquals(deserialized.defaultFractionDigits.toLong(), currency.defaultFractionDigits.toLong())
}
fun unmodifiableCollections(): Array<Array<Any>> {
val m = HashMap<String, String>()
m["foo"] = "bar"
return arrayOf(
arrayOf(Collections.unmodifiableList(ArrayList(mutableListOf("foo", "bar")))), arrayOf(
Collections.unmodifiableSet(
HashSet(
mutableListOf("foo", "bar")
)
)
), arrayOf(Collections.unmodifiableMap(m))
)
}
@Test
@Throws(Exception::class)
fun testUnmodifiableCollections() {
val collection: Any = unmodifiableCollections()
val holder = TestClasses.Holder(collection)
val deserialized = deserialize(serialize(holder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, holder)
}
@Test
@Throws(Exception::class)
fun testCopyUnmodifiableCollections() {
val collection: Any = unmodifiableCollections()
val unmodifiableCollection = TestClasses.Holder(collection)
val copy = _kryo.copy(unmodifiableCollection)
assertDeepEquals(copy, unmodifiableCollection)
}
fun synchronizedCollections(): Array<Array<Any>> {
val m = HashMap<String, String>()
m["foo"] = "bar"
return arrayOf(
arrayOf(Collections.synchronizedList(ArrayList(mutableListOf("foo", "bar")))), arrayOf(
Collections.synchronizedSet(
HashSet(
mutableListOf("foo", "bar")
)
)
), arrayOf(Collections.synchronizedMap(m))
)
}
@Test
@Throws(Exception::class)
fun testSynchronizedCollections() {
val collection: Any = synchronizedCollections()
val holder = TestClasses.Holder(collection)
val deserialized = deserialize(serialize(holder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, holder)
}
@Test
@Throws(Exception::class)
fun testCopySynchronizedCollections() {
val collection: Any = synchronizedCollections()
val synchronizedCollection = TestClasses.Holder(collection)
val copy = _kryo.copy(synchronizedCollection)
assertDeepEquals(copy, synchronizedCollection)
}
@Test
@Throws(Exception::class)
fun testJavaUtilCollectionsEmptyList() {
val emptyList = TestClasses.Holder(emptyList<String>())
val deserialized = deserialize(serialize(emptyList), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, emptyList)
}
@Test
@Throws(Exception::class)
fun testCopyJavaUtilCollectionsEmptyList() {
val emptyList = TestClasses.Holder(emptyList<String>())
val copy = _kryo.copy(emptyList)
assertDeepEquals(copy, emptyList)
}
@Test
@Throws(Exception::class)
fun testJavaUtilCollectionsEmptySet() {
val emptyList = TestClasses.Holder(emptySet<String>())
val deserialized = deserialize(serialize(emptyList), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, emptyList)
}
@Test
@Throws(Exception::class)
fun testCopyJavaUtilCollectionsEmptySet() {
val emptyList = TestClasses.Holder(emptySet<String>())
val copy = _kryo.copy(emptyList)
assertDeepEquals(copy, emptyList)
}
@Test
@Throws(Exception::class)
fun testJavaUtilCollectionsEmptyMap() {
val emptyMap = TestClasses.Holder(emptyMap<String, String>())
val deserialized = deserialize(serialize(emptyMap), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, emptyMap)
}
@Test
@Throws(Exception::class)
fun testCopyJavaUtilCollectionsEmptyMap() {
val emptyMap = TestClasses.Holder(emptyMap<String, String>())
val copy = _kryo.copy(emptyMap)
assertDeepEquals(copy, emptyMap)
}
@Test
@Throws(Exception::class)
fun testJavaUtilArraysAsListEmpty() {
val asListHolder = TestClasses.Holder<List<String>>(mutableListOf())
val deserialized = deserialize(serialize(asListHolder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, asListHolder)
}
@Test
@Throws(Exception::class)
fun testJavaUtilArraysAsListPrimitiveArrayElement() {
val values = intArrayOf(1, 2).toList()
val asListHolder = TestClasses.Holder<List<Int>>(values)
val deserialized = deserialize(serialize(asListHolder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, asListHolder)
}
@Test
@Throws(Exception::class)
fun testJavaUtilArraysAsListBoxedPrimitives() {
val values = arrayOf(1, 2)
val list = Arrays.asList(*values)
val asListHolder = TestClasses.Holder<List<Int>>(list)
val deserialized = deserialize(serialize(asListHolder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, asListHolder)
}
@Test
@Throws(Exception::class)
fun testJavaUtilArraysAsListString() {
val asListHolder = TestClasses.Holder<List<String>>(mutableListOf("foo", "bar"))
val deserialized = deserialize(serialize(asListHolder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, asListHolder)
}
@Test
@Throws(Exception::class)
fun testJavaUtilArraysAsListEmail() {
val asListHolder = TestClasses.Holder(Arrays.asList(Email("foo", "foo@example.org")))
val deserialized = deserialize(serialize(asListHolder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, asListHolder)
}
@Test
@Throws(Exception::class)
fun testCopyJavaUtilArraysAsList() {
val list: List<String> = mutableListOf("foo", "bar")
val copy = _kryo.copy(list)
assertDeepEquals(copy, list)
}
@Test
@Throws(Exception::class)
fun testClassSerializer() {
val clazz = TestClasses.Holder<Class<*>>(String::class.java)
val deserialized = deserialize(serialize(clazz), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, clazz)
}
@Test(expected = KryoException::class)
@Throws(Exception::class)
fun testInnerClass() {
// seems to be related to #15
val container = TestClasses.createContainer()
val deserialized = deserialize(serialize(container), TestClasses.Container::class.java)
assertDeepEquals(deserialized, container)
}
@Test
@Throws(Exception::class)
fun <T> testSharedObjectIdentity_CounterHolder() {
val sharedObject = AtomicInteger(42)
val holder1 = CounterHolder(sharedObject)
val holder2 = CounterHolder(sharedObject)
val holderHolder = CounterHolderArray(holder1, holder2)
_kryo.setReferences(true)
val deserialized = deserialize(serialize(holderHolder), CounterHolderArray::class.java)
assertDeepEquals(deserialized, holderHolder)
Assert.assertTrue(deserialized.holders[0].item === deserialized.holders[1].item)
}
protected fun createSharedObjectIdentityProviderData(): Array<Array<Any>> {
return arrayOf(
arrayOf(AtomicInteger::class.java.simpleName, AtomicInteger(42)), arrayOf(
Email::class.java.simpleName, Email("foo bar", "foo.bar@example.com")
)
)
}
@Test
@Throws(Exception::class)
fun <T> testSharedObjectIdentityWithArray() {
val data = createSharedObjectIdentityProviderData()
for (datum in data) {
val name = datum[0] as String
val sharedObject = datum[1] as T
val holder1 = TestClasses.Holder(sharedObject)
val holder2 = TestClasses.Holder(sharedObject)
val holderHolder = HolderArray(holder1, holder2)
_kryo.setReferences(true)
val deserialized = deserialize(serialize(holderHolder), HolderArray::class.java)
assertDeepEquals(deserialized, holderHolder)
Assert.assertTrue(deserialized.holders[0].item === deserialized.holders[1].item)
}
}
@Test
@Throws(Exception::class)
fun <T> testSharedObjectIdentity() {
val data = createSharedObjectIdentityProviderData()
for (datum in data) {
val name = datum[0] as String
val sharedObject = datum[1] as T
val holder1 = TestClasses.Holder(sharedObject)
val holder2 = TestClasses.Holder(sharedObject)
val holders = ArrayList(listOf(holder1, holder2))
val holderHolder = HolderList(holders)
_kryo.setReferences(true)
val deserialized = deserialize(serialize(holderHolder), HolderList::class.java)
assertDeepEquals(deserialized, holderHolder)
Assert.assertTrue(deserialized.holders[0].item === deserialized.holders[1].item)
}
}
protected fun createTypesAsSessionAttributesData(): Array<Array<Any>> {
return arrayOf(
arrayOf(Boolean::class.java, java.lang.Boolean.TRUE), arrayOf(
String::class.java, "42"
), arrayOf(StringBuilder::class.java, StringBuilder("42")), arrayOf(
StringBuffer::class.java, StringBuffer("42")
), arrayOf(Class::class.java, String::class.java), arrayOf(
Long::class.java, 42
), arrayOf(Int::class.java, 42), arrayOf(Char::class.java, 'c'), arrayOf(
Byte::class.java, "b".toByteArray()[0]
), arrayOf(Double::class.java, 42.0), arrayOf(
Float::class.java, 42f
), arrayOf(Short::class.java, 42.toShort()), arrayOf(
BigDecimal::class.java, BigDecimal(42)
), arrayOf(AtomicInteger::class.java, AtomicInteger(42)), arrayOf(
AtomicLong::class.java, AtomicLong(42)
), arrayOf(
Array<Int>::class.java, arrayOf(42)
), arrayOf(java.util.Date::class.java, java.util.Date(System.currentTimeMillis() - 10000)), arrayOf(
Calendar::class.java, Calendar.getInstance()
), arrayOf(Currency::class.java, Currency.getInstance("EUR")), arrayOf(
ArrayList::class.java, ArrayList(mutableListOf("foo"))
), arrayOf(
IntArray::class.java, intArrayOf(1, 2)
), arrayOf(LongArray::class.java, longArrayOf(1, 2)), arrayOf(
ShortArray::class.java, shortArrayOf(1, 2)
), arrayOf(FloatArray::class.java, floatArrayOf(1f, 2f)), arrayOf(
DoubleArray::class.java, doubleArrayOf(1.0, 2.0)
), arrayOf(IntArray::class.java, intArrayOf(1, 2)), arrayOf(
ByteArray::class.java, "42".toByteArray()
), arrayOf(CharArray::class.java, "42".toCharArray()), arrayOf(
Array<String>::class.java, arrayOf("23", "42")
), arrayOf(Array<Person>::class.java, arrayOf(TestClasses.createPerson("foo bar", Gender.MALE, 42)))
)
}
@Test
@Throws(Exception::class)
fun <T> testTypesAsSessionAttributes() {
val data = createTypesAsSessionAttributesData()
for (datum in data) {
val type = datum[0] as Class<T>
val instance = datum[1] as T
val deserialized = deserialize(serialize(instance!!), instance!!::class.java) as T
assertDeepEquals(deserialized, instance)
}
}
@Test
@Throws(Exception::class)
fun testTypesInContainerClass() {
val myContainer = MyContainer()
val deserialized = deserialize(serialize(myContainer), MyContainer::class.java)
assertDeepEquals(deserialized, myContainer)
}
@Test(expected = KryoException::class)
@Throws(Exception::class)
fun testClassWithoutDefaultConstructor() {
val obj = TestClasses.createClassWithoutDefaultConstructor("foo")
val deserialized = deserialize(serialize(obj), ClassWithoutDefaultConstructor::class.java)
assertDeepEquals(deserialized, obj)
}
@Test
@Throws(Exception::class)
fun testPrivateClass() {
val holder: TestClasses.Holder<*> = TestClasses.Holder<Any>(TestClasses.createPrivateClass("foo"))
val deserialized = deserialize(serialize(holder), TestClasses.Holder::class.java)
assertDeepEquals(deserialized, holder)
}
@Test
@Throws(Exception::class)
fun testCollections() {
val obj = EntityWithCollections()
val deserialized = deserialize(serialize(obj), EntityWithCollections::class.java)
assertDeepEquals(deserialized, obj)
}
@Test
@Throws(Exception::class)
fun testCyclicDependencies() {
_kryo.setReferences(true)
val p1 = TestClasses.createPerson("foo bar", Gender.MALE, 42, "foo.bar@example.org", "foo.bar@example.com")
val p2 = TestClasses.createPerson("bar baz", Gender.FEMALE, 42, "bar.baz@example.org", "bar.baz@example.com")
p1.addFriend(p2)
p2.addFriend(p1)
val deserialized = deserialize(serialize(p1), Person::class.java)
assertDeepEquals(deserialized, p1)
}
class EntityWithCollections {
private val _bars: Array<String>
private val _foos: List<String>?
private val _bazens: MutableMap<String, Int>?
init {
_bars = arrayOf("foo", "bar")
_foos = ArrayList(mutableListOf("foo", "bar"))
_bazens = HashMap()
_bazens["foo"] = 1
_bazens["bar"] = 2
}
override fun hashCode(): Int {
val prime = 31
var result = 1
result = prime * result + Arrays.hashCode(_bars)
result = prime * result + (_bazens?.hashCode() ?: 0)
result = prime * result + (_foos?.hashCode() ?: 0)
return result
}
override fun equals(obj: Any?): Boolean {
if (this === obj) {
return true
}
if (obj == null) {
return false
}
if (javaClass != obj.javaClass) {
return false
}
val other = obj as EntityWithCollections
if (!Arrays.equals(_bars, other._bars)) {
return false
}
if (_bazens == null) {
if (other._bazens != null) {
return false
}
} else if (_bazens != other._bazens) {
return false
}
if (_foos == null) {
if (other._foos != null) {
return false
}
} else if (_foos != other._foos) {
return false
}
return true
}
}
protected fun serialize(o: Any): ByteArray {
return serialize(_kryo, o)
}
protected fun <T> deserialize(`in`: ByteArray, clazz: Class<out T>): T {
return deserialize(_kryo, `in`, clazz)
}
companion object {
@Throws(Exception::class)
fun assertDeepEquals(one: Any?, another: Any?) {
assertDeepEquals(one, another, IdentityHashMap())
}
@Throws(Exception::class)
private fun assertDeepEquals(one: Any?, another: Any?, alreadyChecked: MutableMap<Any?, Any?>) {
if (one === another) {
return
}
if (one == null && another != null || one != null && another == null) {
Assert.fail("One of both is null: $one, $another")
}
if (alreadyChecked.containsKey(one)) {
return
}
alreadyChecked[one] = another
Assert.assertEquals(one!!.javaClass, another!!.javaClass)
if (one.javaClass.isPrimitive || one is String || one is Char || one is Boolean || one is Class<*>) {
Assert.assertEquals(one, another)
return
}
if (MutableMap::class.java.isAssignableFrom(one.javaClass)) {
val m1 = one as Map<*, *>?
val m2 = another as Map<*, *>?
Assert.assertEquals(m1!!.size.toLong(), m2!!.size.toLong())
val iter1 = m1.entries.iterator()
while (iter1.hasNext()) {
val (key, value) = iter1.next()
assertDeepEquals(value, m2[key], alreadyChecked)
}
return
}
if (Number::class.java.isAssignableFrom(one.javaClass)) {
Assert.assertEquals((one as Number?)!!.toLong(), (another as Number?)!!.toLong())
return
}
if (one is Currency) {
// Check that the transient field defaultFractionDigits is initialized correctly (that was issue #34)
val currency1 = one
val currency2 = another as Currency?
Assert.assertEquals(currency1.currencyCode, currency2!!.currencyCode)
Assert.assertEquals(currency1.defaultFractionDigits.toLong(), currency2.defaultFractionDigits.toLong())
}
if (MutableCollection::class.java.isAssignableFrom(one.javaClass)) {
val c1 = one as Collection<*>?
val c2 = another as Collection<*>?
Assert.assertEquals(c1!!.size.toLong(), c2!!.size.toLong())
val iter1 = c1.iterator()
val iter2 = c2.iterator()
while (iter1.hasNext()) {
assertDeepEquals(iter1.next(), iter2.next(), alreadyChecked)
}
Assert.assertFalse(iter2.hasNext())
return
}
var clazz: Class<*>? = one.javaClass
while (clazz != null) {
assertEqualDeclaredFields(clazz, one, another, alreadyChecked)
clazz = clazz.superclass
}
}
@Throws(Exception::class, IllegalAccessException::class)
private fun assertEqualDeclaredFields(clazz: Class<out Any>, one: Any, another: Any, alreadyChecked: MutableMap<Any?, Any?>) {
for (field in clazz.declaredFields) {
field.isAccessible = true
if (!Modifier.isTransient(field.modifiers)) {
assertDeepEquals(field[one], field[another], alreadyChecked)
}
}
}
fun serialize(kryo: Kryo, o: Any): ByteArray {
val output = Output(4096)
kryo.writeObject(output, o)
output.flush()
return output.buffer
}
fun <T> deserialize(kryo: Kryo, `in`: ByteArray, clazz: Class<out T>): T {
val input = Input(`in`)
return kryo.readObject(input, clazz)
}
}
}