Improve the way Json.name is fetched for codegen (#1059)

* Improve the way Json.name is fetched for codegen

* Remove the comment for jsonName

* Add a test for json names with quotation marks

* Fix the broken tests
This commit is contained in:
Nicklas Ansman Giertz
2020-01-10 21:32:23 -05:00
committed by Zac Sweers
parent 365e955381
commit cc4b5b3ad2
3 changed files with 28 additions and 9 deletions

View File

@@ -125,11 +125,7 @@ internal class AdapterGenerator(
"%T.of(%L)", "%T.of(%L)",
JsonReader.Options::class.asTypeName(), JsonReader.Options::class.asTypeName(),
nonTransientProperties nonTransientProperties
.map { .map { CodeBlock.of("%S", it.jsonName) }
// We manually put in quotes because we know the jsonName is already escaped.
val whitespaceSafeName = it.jsonName.replace(" ", "·")
CodeBlock.of("\"$whitespaceSafeName\"")
}
.joinToCode(", ") .joinToCode(", ")
) )
.build() .build()
@@ -495,7 +491,7 @@ internal class AdapterGenerator(
result.addStatement("%N.beginObject()", writerParam) result.addStatement("%N.beginObject()", writerParam)
nonTransientProperties.forEach { property -> nonTransientProperties.forEach { property ->
// We manually put in quotes because we know the jsonName is already escaped // We manually put in quotes because we know the jsonName is already escaped
result.addStatement("%N.name(\"%L\")", writerParam, property.jsonName) result.addStatement("%N.name(%S)", writerParam, property.jsonName)
result.addStatement("%N.toJson(%N, %N.%N)", result.addStatement("%N.toJson(%N, %N.%N)",
nameAllocator[property.delegateKey], writerParam, valueParam, property.name) nameAllocator[property.delegateKey], writerParam, valueParam, property.name)
} }

View File

@@ -48,6 +48,7 @@ import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target import java.lang.annotation.Target
import java.util.TreeSet import java.util.TreeSet
import javax.annotation.processing.Messager import javax.annotation.processing.Messager
import javax.lang.model.element.AnnotationMirror
import javax.lang.model.element.Element import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement import javax.lang.model.element.TypeElement
@@ -328,11 +329,13 @@ private fun List<AnnotationSpec>?.qualifiers(elements: Elements): Set<Annotation
} }
} }
/** Gross, but we can't extract values from AnnotationSpecs by member names alone. */
private fun List<AnnotationSpec>?.jsonName(): String? { private fun List<AnnotationSpec>?.jsonName(): String? {
if (this == null) return null if (this == null) return null
return find { it.className == JSON }?.let { return find { it.className == JSON }?.let { annotation ->
it.members[0].toString().removePrefix("name = \"").removeSuffix("\"") val mirror = requireNotNull(annotation.tag<AnnotationMirror>()) {
"Could not get the annotation mirror from the annotation spec"
}
mirror.elementValues.entries.single { it.key.simpleName.contentEquals("name") }.value.value as String
} }
} }

View File

@@ -87,6 +87,26 @@ class GeneratedAdaptersTest {
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class JsonAnnotationWithDollarSign(@Json(name = "\$foo") val bar: String) data class JsonAnnotationWithDollarSign(@Json(name = "\$foo") val bar: String)
@Test
fun jsonAnnotationWithQuotationMark() {
val adapter = moshi.adapter<JsonAnnotationWithQuotationMark>()
// Read
val json = """{"\"foo\"": "bar"}"""
val instance = adapter.fromJson(json)!!
assertThat(instance.bar).isEqualTo("bar")
// Write
val expectedJson = """{"\"foo\"":"baz"}"""
assertThat(adapter.toJson(
JsonAnnotationWithQuotationMark("baz"))).isEqualTo(expectedJson)
}
@JsonClass(generateAdapter = true)
data class JsonAnnotationWithQuotationMark(@Json(name = "\"foo\"") val bar: String)
@Test @Test
fun defaultValues() { fun defaultValues() {
val adapter = moshi.adapter<DefaultValues>() val adapter = moshi.adapter<DefaultValues>()