Repository: square/moshi
Issue: Codegen @Json wrong name generation when using special characters

When using something like:

```Kotlin
data class TimeStamp(@Json(name = "\\$date") val millis: Long)
```

In the generated adapter the name gets converted to:

```Kotlin
JsonReader.Options.of("$date")
```

Which causes an Unresolved reference error when compiling, since the compiler is looking for a variable named 'date'

Changed files:
kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TargetProperty.kt
kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/AdapterGenerator.kt

diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/AdapterGenerator.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/AdapterGenerator.kt
index 7008b9b..813c3a3 100644
--- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/AdapterGenerator.kt
+++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/AdapterGenerator.kt
@@ -303,7 +303,7 @@ internal class AdapterGenerator(
 
     result.addStatement("%N.beginObject()", writerParam)
     propertyList.forEach { property ->
-      result.addStatement("%N.name(%S)", writerParam, property.jsonName)
+      result.addStatement("%N.name(\\"${property.jsonName}\\")", writerParam)
       result.addStatement("%N.toJson(%N, %N.%L)",
           nameAllocator.get(property.delegateKey), writerParam, valueParam, property.name)
     }
diff --git a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TargetProperty.kt b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TargetProperty.kt
index a0decdc..e1b14e5 100644
--- a/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TargetProperty.kt
+++ b/kotlin/codegen/src/main/java/com/squareup/moshi/kotlin/codegen/TargetProperty.kt
@@ -128,7 +128,7 @@ internal data class TargetProperty(
   private val Element?.jsonName: String?
     get() {
       if (this == null) return null
-      return getAnnotation(Json::class.java)?.name
+      return getAnnotation(Json::class.java)?.name?.replace("$", "\\\\$")
     }
 
   override fun toString() = name
diff --git a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt
index f302c3e..300d827 100644
--- a/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt
+++ b/kotlin/tests/src/test/kotlin/com/squareup/moshi/kotlin/codgen/GeneratedAdaptersTest.kt
@@ -55,6 +55,27 @@ class GeneratedAdaptersTest {
   @JsonClass(generateAdapter = true)
   data class JsonAnnotation(@Json(name = "foo") val bar: String)
 
+  @Test
+  fun jsonAnnotationWithDollarSign() {
+    val adapter = moshi.adapter(JsonAnnotationWithDollarSign::class.java)
+
+    // Read
+    @Language("JSON")
+    val json = "{\\"\\$foo\\": \\"bar\\"}"
+
+    val instance = adapter.fromJson(json)!!
+    assertThat(instance.bar).isEqualTo("bar")
+
+    // Write
+    @Language("JSON")
+    val expectedJson = "{\\"\\$foo\\":\\"baz\\"}"
+
+    assertThat(adapter.toJson(JsonAnnotationWithDollarSign("baz"))).isEqualTo(expectedJson)
+  }
+
+  @JsonClass(generateAdapter = true)
+  data class JsonAnnotationWithDollarSign(@Json(name = "\\$foo") val bar: String)
+
   @Test
   fun defaultValues() {
     val adapter = moshi.adapter(DefaultValues::class.java)