mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
Invoke defaults constructor in kotlin code gen (#896)
* Add Util#invokeDefaultConstructor * Add defaultPrimitiveValue This will be used to initialize required properties for later invocation of the default constructor * Move isTransient into PropertyGenerator We will need this in order to know how to invoke constructors even if they have transient parameters * Add notion of hasLocalIsPresentName to PropertyGenerator * Switch to using invokeDefaultConstructor for any default property types * Add code gen versions of default constructor test * Fix mismatched names * Use Arrays.copyOf * Unwrap InvocationTargetException * Use name allocator * Rename createMask to createDefaultValuesParametersMask, use it directly * Opportunistically clean up result variable holder Only needs to be made if we have non-parameter instances, otherwise we can just return directly * Fix mask name * Remove unnecessary mod * Switch to local lazily-initialized constructor reference Not working because of some issue in kotlinpoet I don't understand * Fix named usage * Clean up debugging dots * Add proguard/R8 rule for keeping defaults constructor in targets * Make constructor lookup property private * Add another defensive dot * Rework invokeDefaultConstructor to accept vararg args A little more idiomatic * Update proguard rules
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package com.squareup.moshi.kotlin
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.internal.Util
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultConstructorTest {
|
||||
|
||||
@Test fun minimal() {
|
||||
val expected = TestClass("requiredClass")
|
||||
val args = arrayOf("requiredClass", null, 0, null, 0, 0)
|
||||
val mask = Util.createDefaultValuesParametersMask(true, false, false, false, false, false)
|
||||
val constructor = Util.lookupDefaultsConstructor(TestClass::class.java)
|
||||
val instance = Util.invokeDefaultConstructor(TestClass::class.java, constructor, mask, *args)
|
||||
check(instance == expected) {
|
||||
"No match:\nActual : $instance\nExpected: $expected"
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun allSet() {
|
||||
val expected = TestClass("requiredClass", "customOptional", 4, "setDynamic", 5, 6)
|
||||
val args = arrayOf("requiredClass", "customOptional", 4, "setDynamic", 5, 6)
|
||||
val mask = Util.createDefaultValuesParametersMask(true, true, true, true, true, true)
|
||||
val constructor = Util.lookupDefaultsConstructor(TestClass::class.java)
|
||||
val instance = Util.invokeDefaultConstructor(TestClass::class.java, constructor, mask, *args)
|
||||
check(instance == expected) {
|
||||
"No match:\nActual : $instance\nExpected: $expected"
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun customDynamic() {
|
||||
val expected = TestClass("requiredClass", "customOptional")
|
||||
val args = arrayOf("requiredClass", "customOptional", 0, null, 0, 0)
|
||||
val mask = Util.createDefaultValuesParametersMask(true, true, false, false, false, false)
|
||||
val constructor = Util.lookupDefaultsConstructor(TestClass::class.java)
|
||||
val instance = Util.invokeDefaultConstructor(TestClass::class.java, constructor, mask, *args)
|
||||
check(instance == expected) {
|
||||
"No match:\nActual : $instance\nExpected: $expected"
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun minimal_codeGen() {
|
||||
val expected = TestClass("requiredClass")
|
||||
val json = """{"required":"requiredClass"}"""
|
||||
val instance = Moshi.Builder().build().adapter<TestClass>(TestClass::class.java)
|
||||
.fromJson(json)!!
|
||||
check(instance == expected) {
|
||||
"No match:\nActual : $instance\nExpected: $expected"
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun allSet_codeGen() {
|
||||
val expected = TestClass("requiredClass", "customOptional", 4, "setDynamic", 5, 6)
|
||||
val json = """{"required":"requiredClass","optional":"customOptional","optional2":4,"dynamicSelfReferenceOptional":"setDynamic","dynamicOptional":5,"dynamicInlineOptional":6}"""
|
||||
val instance = Moshi.Builder().build().adapter<TestClass>(TestClass::class.java)
|
||||
.fromJson(json)!!
|
||||
check(instance == expected) {
|
||||
"No match:\nActual : $instance\nExpected: $expected"
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun customDynamic_codeGen() {
|
||||
val expected = TestClass("requiredClass", "customOptional")
|
||||
val json = """{"required":"requiredClass","optional":"customOptional"}"""
|
||||
val instance = Moshi.Builder().build().adapter<TestClass>(TestClass::class.java)
|
||||
.fromJson(json)!!
|
||||
check(instance == expected) {
|
||||
"No match:\nActual : $instance\nExpected: $expected"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TestClass(
|
||||
val required: String,
|
||||
val optional: String = "optional",
|
||||
val optional2: Int = 2,
|
||||
val dynamicSelfReferenceOptional: String = required,
|
||||
val dynamicOptional: Int = createInt(),
|
||||
val dynamicInlineOptional: Int = createInlineInt()
|
||||
)
|
||||
|
||||
private fun createInt(): Int {
|
||||
return 3
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun createInlineInt(): Int {
|
||||
return 3
|
||||
}
|
Reference in New Issue
Block a user