Support more kinds of properties in KotlinJsonAdapter

This makes it possible to have synthetic properties that have no
state.

Also test properties that are synthetic and have no backing field.

Closes: https://github.com/square/moshi/issues/299
This commit is contained in:
jwilson
2017-05-07 16:18:12 -04:00
parent e59dbf4f96
commit 494992dab8
2 changed files with 59 additions and 15 deletions

View File

@@ -115,12 +115,6 @@ internal class KotlinJsonAdapter<T>(
val adapter: JsonAdapter<P>,
val property: KProperty1<K, P>,
val parameter: KParameter?) {
init {
if (property !is KMutableProperty1 && parameter == null) {
throw IllegalArgumentException("No constructor or var property for ${property}")
}
}
fun get(value: K) = property.get(value)
fun set(result: K, value: P) {
@@ -171,11 +165,13 @@ object KotlinJsonAdapterFactory : JsonAdapter.Factory {
for (property in rawType.kotlin.memberProperties) {
if (Modifier.isTransient(property.javaField?.modifiers ?: 0)) continue
val parameter = parametersByName[property.name]
if (property !is KMutableProperty1 && parameter == null) continue
property.isAccessible = true
var allAnnotations = property.annotations
var jsonAnnotation = property.findAnnotation<Json>()
val parameter = parametersByName[property.name]
if (parameter != null) {
allAnnotations += parameter.annotations
if (jsonAnnotation == null) {

View File

@@ -445,15 +445,17 @@ class KotlinJsonAdapterTest {
}
}
@Test fun unsettableProperty() {
@Test fun unsettablePropertyIgnored() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory).build()
try {
moshi.adapter(UnsettableProperty::class.java)
fail()
} catch(expected: IllegalArgumentException) {
assertThat(expected).hasMessage("No constructor or var property for " +
"val ${UnsettableProperty::class.qualifiedName}.a: kotlin.Int")
}
val jsonAdapter = moshi.adapter(UnsettableProperty::class.java)
val encoded = UnsettableProperty()
encoded.b = 5
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("{\"b\":5}")
val decoded = jsonAdapter.fromJson("{\"a\":4,\"b\":6}")!!
assertThat(decoded.a).isEqualTo(-1)
assertThat(decoded.b).isEqualTo(6)
}
class UnsettableProperty {
@@ -461,6 +463,52 @@ class KotlinJsonAdapterTest {
var b: Int = -1
}
@Test fun getterOnlyNoBackingField() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory).build()
val jsonAdapter = moshi.adapter(GetterOnly::class.java)
val encoded = GetterOnly(3, 5)
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("{\"a\":3,\"b\":5}")
val decoded = jsonAdapter.fromJson("{\"a\":4,\"b\":6}")!!
assertThat(decoded.a).isEqualTo(4)
assertThat(decoded.b).isEqualTo(6)
assertThat(decoded.total).isEqualTo(10)
}
class GetterOnly(var a: Int, var b: Int) {
val total : Int
get() = a + b
}
@Test fun getterAndSetterNoBackingField() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory).build()
val jsonAdapter = moshi.adapter(GetterAndSetter::class.java)
val encoded = GetterAndSetter(3, 5)
assertThat(jsonAdapter.toJson(encoded)).isEqualTo("{\"a\":3,\"b\":5,\"total\":8}")
// Whether b is 6 or 7 is an implementation detail. Currently we call constructors then setters.
val decoded1 = jsonAdapter.fromJson("{\"a\":4,\"b\":6,\"total\":11}")!!
assertThat(decoded1.a).isEqualTo(4)
assertThat(decoded1.b).isEqualTo(7)
assertThat(decoded1.total).isEqualTo(11)
// Whether b is 6 or 7 is an implementation detail. Currently we call constructors then setters.
val decoded2 = jsonAdapter.fromJson("{\"a\":4,\"total\":11,\"b\":6}")!!
assertThat(decoded2.a).isEqualTo(4)
assertThat(decoded2.b).isEqualTo(7)
assertThat(decoded2.total).isEqualTo(11)
}
class GetterAndSetter(var a: Int, var b: Int) {
var total : Int
get() = a + b
set(value) {
b = value - a
}
}
@Test fun nonPropertyConstructorParameter() {
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory).build()
try {