mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
Fold the kotlin-codegen-runtime into Moshi itself.
Rename @MoshiSerializable to @JsonClass. Like @Json, I'm anticipating a future where there are other interesting properties on this annotation. Perhaps a future feature where Moshi is strict and only adapts types that have a '@JsonClass' annotation. Also rename MoshiKotlinCodeGenProcessor to JsonClassCodeGenProcessor. We may later support other ways of generating code here; perhaps for regular Java types.
This commit is contained in:
@@ -50,23 +50,25 @@ import javax.tools.Diagnostic.Kind.ERROR
|
||||
* adapter will also be internal).
|
||||
*
|
||||
* If you define a companion object, a jsonAdapter() extension function will be generated onto it.
|
||||
* If you don't want this though, you can use the runtime [MoshiSerializable] factory implementation.
|
||||
* If you don't want this though, you can use the runtime [JsonClass] factory implementation.
|
||||
*/
|
||||
@AutoService(Processor::class)
|
||||
class MoshiKotlinCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils {
|
||||
class JsonClassCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils {
|
||||
|
||||
private val annotationName = MoshiSerializable::class.java.canonicalName
|
||||
private val annotation = JsonClass::class.java
|
||||
|
||||
override fun getSupportedAnnotationTypes() = setOf(annotationName)
|
||||
override fun getSupportedAnnotationTypes() = setOf(annotation.canonicalName)
|
||||
|
||||
override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latest()
|
||||
|
||||
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
|
||||
val annotationElement = elementUtils.getTypeElement(annotationName)
|
||||
roundEnv.getElementsAnnotatedWith(annotationElement)
|
||||
.asSequence()
|
||||
.mapNotNull { processElement(it) }
|
||||
.forEach { it.generateAndWrite() }
|
||||
for (type in roundEnv.getElementsAnnotatedWith(annotation)) {
|
||||
val jsonClass = type.getAnnotation(annotation)
|
||||
if (jsonClass.generateAdapter) {
|
||||
val adapterGenerator = processElement(type) ?: continue
|
||||
adapterGenerator.generateAndWrite()
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -178,7 +180,7 @@ class MoshiKotlinCodeGenProcessor : KotlinAbstractProcessor(), KotlinMetadataUti
|
||||
|
||||
private fun errorMustBeDataClass(element: Element) {
|
||||
messager.printMessage(ERROR,
|
||||
"@${MoshiSerializable::class.java.simpleName} can't be applied to $element: must be a Kotlin data class",
|
||||
"@${JsonClass::class.java.simpleName} can't be applied to $element: must be a Kotlin data class",
|
||||
element)
|
||||
}
|
||||
|
@@ -18,11 +18,6 @@
|
||||
<artifactId>moshi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi-kotlin-codegen-runtime</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
@@ -57,7 +52,6 @@
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>src/main/kotlin</sourceDir>
|
||||
<sourceDir>src/main/java</sourceDir>
|
||||
</sourceDirs>
|
||||
<annotationProcessorPaths>
|
||||
<annotationProcessorPath>
|
||||
|
@@ -22,7 +22,7 @@ import org.junit.Test
|
||||
|
||||
class DataClassesTest {
|
||||
|
||||
private val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
private val moshi = Moshi.Builder().build()
|
||||
|
||||
@Test
|
||||
fun jsonAnnotation() {
|
||||
@@ -42,7 +42,7 @@ class DataClassesTest {
|
||||
assertThat(adapter.toJson(JsonAnnotation("baz"))).isEqualTo(expectedJson)
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class JsonAnnotation(@Json(name = "foo") val bar: String)
|
||||
|
||||
@Test
|
||||
@@ -79,7 +79,7 @@ class DataClassesTest {
|
||||
assertThat(adapter.toJson(instance2)).isEqualTo(json2)
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class DefaultValues(val foo: String,
|
||||
val bar: String = "",
|
||||
val nullableBar: String? = null,
|
||||
@@ -97,7 +97,7 @@ class DataClassesTest {
|
||||
assertThat(adapter.toJson(instance)).isEqualTo(json)
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NullableArray(val data: Array<String?>)
|
||||
|
||||
@Test
|
||||
@@ -112,7 +112,7 @@ class DataClassesTest {
|
||||
assertThat(adapter.toJson(instance)).isEqualTo(json)
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class PrimitiveArray(val ints: IntArray)
|
||||
|
||||
@Test
|
||||
@@ -136,7 +136,7 @@ class DataClassesTest {
|
||||
}
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NullabeTypes(
|
||||
val foo: String,
|
||||
val nullableString: String?
|
||||
@@ -160,7 +160,7 @@ class DataClassesTest {
|
||||
assertThat(newCollections).isEqualTo(specialCollections)
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SpecialCollections(
|
||||
val mutableList: MutableList<String>,
|
||||
val mutableSet: MutableSet<String>,
|
||||
@@ -194,7 +194,7 @@ class DataClassesTest {
|
||||
assertThat(newMutableProperties).isEqualTo(mutableProperties)
|
||||
}
|
||||
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class MutableProperties(
|
||||
val immutableProperty: String,
|
||||
var mutableProperty: String,
|
||||
@@ -238,10 +238,24 @@ class DataClassesTest {
|
||||
val nullSerializedNullableTypeParams = adapter.fromJson(nullSerializedJson)
|
||||
assertThat(nullSerializedNullableTypeParams).isEqualTo(nullableTypeParams)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doNotGenerateAdapter() {
|
||||
try {
|
||||
StandardJsonAdapters.generatedAdapter(
|
||||
moshi, DoNotGenerateAdapter::class.java, DoNotGenerateAdapter::class.java)
|
||||
fail("found a generated adapter for a type that shouldn't have one")
|
||||
} catch (e: RuntimeException) {
|
||||
assertThat(e).hasCauseInstanceOf(ClassNotFoundException::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = false)
|
||||
data class DoNotGenerateAdapter(val foo: String)
|
||||
}
|
||||
|
||||
// Has to be outside to avoid Types seeing an owning class
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class NullableTypeParams<T>(
|
||||
val nullableList: List<String?>,
|
||||
val nullableSet: Set<String?>,
|
||||
@@ -255,7 +269,7 @@ typealias TypeAliasName = String
|
||||
* This is here mostly just to ensure it still compiles. Covers variance, @Json, default values,
|
||||
* nullability, primitive arrays, and some wacky generics.
|
||||
*/
|
||||
@MoshiSerializable
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SmokeTestType(
|
||||
@Json(name = "first_name") val firstName: String,
|
||||
@Json(name = "last_name") val lastName: String,
|
||||
|
@@ -26,7 +26,7 @@ import kotlin.annotation.AnnotationRetention.RUNTIME
|
||||
|
||||
class KotlinCodeGenTest {
|
||||
@Ignore @Test fun constructorParameters() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ConstructorParameters::class.java)
|
||||
|
||||
val encoded = ConstructorParameters(3, 5)
|
||||
@@ -41,7 +41,7 @@ class KotlinCodeGenTest {
|
||||
|
||||
@Ignore @Test fun properties() {
|
||||
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(Properties::class.java)
|
||||
|
||||
val encoded = Properties()
|
||||
@@ -60,7 +60,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun constructorParametersAndProperties() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ConstructorParametersAndProperties::class.java)
|
||||
|
||||
val encoded = ConstructorParametersAndProperties(3)
|
||||
@@ -77,7 +77,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun immutableConstructorParameters() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ImmutableConstructorParameters::class.java)
|
||||
|
||||
val encoded = ImmutableConstructorParameters(3, 5)
|
||||
@@ -91,7 +91,7 @@ class KotlinCodeGenTest {
|
||||
class ImmutableConstructorParameters(val a: Int, val b: Int)
|
||||
|
||||
@Ignore @Test fun immutableProperties() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ImmutableProperties::class.java)
|
||||
|
||||
val encoded = ImmutableProperties(3, 5)
|
||||
@@ -108,7 +108,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun constructorDefaults() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ConstructorDefaultValues::class.java)
|
||||
|
||||
val encoded = ConstructorDefaultValues(3, 5)
|
||||
@@ -122,7 +122,7 @@ class KotlinCodeGenTest {
|
||||
class ConstructorDefaultValues(var a: Int = -1, var b: Int = -2)
|
||||
|
||||
@Ignore @Test fun requiredValueAbsent() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(RequiredValueAbsent::class.java)
|
||||
|
||||
try {
|
||||
@@ -136,7 +136,7 @@ class KotlinCodeGenTest {
|
||||
class RequiredValueAbsent(var a: Int = 3, var b: Int)
|
||||
|
||||
@Ignore @Test fun nonNullConstructorParameterCalledWithNullFailsWithJsonDataException() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(HasNonNullConstructorParameter::class.java)
|
||||
|
||||
try {
|
||||
@@ -150,7 +150,7 @@ class KotlinCodeGenTest {
|
||||
class HasNonNullConstructorParameter(val a: String)
|
||||
|
||||
@Ignore @Test fun nonNullPropertySetToNullFailsWithJsonDataException() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(HasNonNullProperty::class.java)
|
||||
|
||||
try {
|
||||
@@ -166,7 +166,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun duplicatedValue() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(DuplicateValue::class.java)
|
||||
|
||||
try {
|
||||
@@ -180,7 +180,7 @@ class KotlinCodeGenTest {
|
||||
class DuplicateValue(var a: Int = -1, var b: Int = -2)
|
||||
|
||||
@Ignore @Test fun explicitNull() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ExplicitNull::class.java)
|
||||
|
||||
val encoded = ExplicitNull(null, 5)
|
||||
@@ -195,7 +195,7 @@ class KotlinCodeGenTest {
|
||||
class ExplicitNull(var a: Int?, var b: Int?)
|
||||
|
||||
@Ignore @Test fun absentNull() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(AbsentNull::class.java)
|
||||
|
||||
val encoded = AbsentNull(null, 5)
|
||||
@@ -210,7 +210,7 @@ class KotlinCodeGenTest {
|
||||
class AbsentNull(var a: Int?, var b: Int?)
|
||||
|
||||
@Ignore @Test fun repeatedValue() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(RepeatedValue::class.java)
|
||||
|
||||
try {
|
||||
@@ -225,7 +225,6 @@ class KotlinCodeGenTest {
|
||||
|
||||
@Ignore @Test fun constructorParameterWithQualifier() {
|
||||
val moshi = Moshi.Builder()
|
||||
.add(MoshiSerializableFactory())
|
||||
.add(UppercaseJsonAdapter())
|
||||
.build()
|
||||
val jsonAdapter = moshi.adapter(ConstructorParameterWithQualifier::class.java)
|
||||
@@ -242,7 +241,6 @@ class KotlinCodeGenTest {
|
||||
|
||||
@Ignore @Test fun propertyWithQualifier() {
|
||||
val moshi = Moshi.Builder()
|
||||
.add(MoshiSerializableFactory())
|
||||
.add(UppercaseJsonAdapter())
|
||||
.build()
|
||||
val jsonAdapter = moshi.adapter(PropertyWithQualifier::class.java)
|
||||
@@ -263,7 +261,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun constructorParameterWithJsonName() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ConstructorParameterWithJsonName::class.java)
|
||||
|
||||
val encoded = ConstructorParameterWithJsonName(3, 5)
|
||||
@@ -277,7 +275,7 @@ class KotlinCodeGenTest {
|
||||
class ConstructorParameterWithJsonName(@Json(name = "key a") var a: Int, var b: Int)
|
||||
|
||||
@Ignore @Test fun propertyWithJsonName() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(PropertyWithJsonName::class.java)
|
||||
|
||||
val encoded = PropertyWithJsonName()
|
||||
@@ -296,7 +294,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun transientConstructorParameter() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(TransientConstructorParameter::class.java)
|
||||
|
||||
val encoded = TransientConstructorParameter(3, 5)
|
||||
@@ -310,7 +308,7 @@ class KotlinCodeGenTest {
|
||||
class TransientConstructorParameter(@Transient var a: Int = -1, var b: Int = -1)
|
||||
|
||||
@Ignore @Test fun requiredTransientConstructorParameterFails() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(RequiredTransientConstructorParameter::class.java)
|
||||
fail()
|
||||
@@ -324,7 +322,7 @@ class KotlinCodeGenTest {
|
||||
class RequiredTransientConstructorParameter(@Transient var a: Int)
|
||||
|
||||
@Ignore @Test fun transientProperty() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(TransientProperty::class.java)
|
||||
|
||||
val encoded = TransientProperty()
|
||||
@@ -343,7 +341,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun supertypeConstructorParameters() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(SubtypeConstructorParameters::class.java)
|
||||
|
||||
val encoded = SubtypeConstructorParameters(3, 5)
|
||||
@@ -359,7 +357,7 @@ class KotlinCodeGenTest {
|
||||
class SubtypeConstructorParameters(a: Int, var b: Int) : SupertypeConstructorParameters(a)
|
||||
|
||||
@Ignore @Test fun supertypeProperties() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(SubtypeProperties::class.java)
|
||||
|
||||
val encoded = SubtypeProperties()
|
||||
@@ -381,7 +379,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun extendsPlatformClassWithPrivateField() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ExtendsPlatformClassWithPrivateField::class.java)
|
||||
|
||||
val encoded = ExtendsPlatformClassWithPrivateField(3)
|
||||
@@ -395,7 +393,7 @@ class KotlinCodeGenTest {
|
||||
internal class ExtendsPlatformClassWithPrivateField(var a: Int) : SimpleTimeZone(0, "C")
|
||||
|
||||
@Ignore @Test fun extendsPlatformClassWithProtectedField() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ExtendsPlatformClassWithProtectedField::class.java)
|
||||
|
||||
val encoded = ExtendsPlatformClassWithProtectedField(3)
|
||||
@@ -413,7 +411,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun platformTypeThrows() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(Triple::class.java)
|
||||
fail()
|
||||
@@ -424,7 +422,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun privateConstructorParameters() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(PrivateConstructorParameters::class.java)
|
||||
|
||||
val encoded = PrivateConstructorParameters(3, 5)
|
||||
@@ -441,7 +439,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun privateConstructor() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(PrivateConstructor::class.java)
|
||||
|
||||
val encoded = PrivateConstructor.newInstance(3, 5)
|
||||
@@ -461,7 +459,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun privateProperties() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(PrivateProperties::class.java)
|
||||
|
||||
val encoded = PrivateProperties()
|
||||
@@ -492,7 +490,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun unsettablePropertyIgnored() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(UnsettableProperty::class.java)
|
||||
|
||||
val encoded = UnsettableProperty()
|
||||
@@ -510,7 +508,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun getterOnlyNoBackingField() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(GetterOnly::class.java)
|
||||
|
||||
val encoded = GetterOnly(3, 5)
|
||||
@@ -528,7 +526,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun getterAndSetterNoBackingField() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(GetterAndSetter::class.java)
|
||||
|
||||
val encoded = GetterAndSetter(3, 5)
|
||||
@@ -556,7 +554,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun nonPropertyConstructorParameter() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(NonPropertyConstructorParameter::class.java)
|
||||
fail()
|
||||
@@ -570,7 +568,7 @@ class KotlinCodeGenTest {
|
||||
class NonPropertyConstructorParameter(a: Int, val b: Int)
|
||||
|
||||
@Ignore @Test fun kotlinEnumsAreNotCovered() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val adapter = moshi.adapter(UsingEnum::class.java)
|
||||
|
||||
assertThat(adapter.fromJson("""{"e": "A"}""")).isEqualTo(UsingEnum(KotlinEnum.A))
|
||||
@@ -583,7 +581,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun interfacesNotSupported() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(Interface::class.java)
|
||||
fail()
|
||||
@@ -596,7 +594,7 @@ class KotlinCodeGenTest {
|
||||
interface Interface
|
||||
|
||||
@Ignore @Test fun abstractClassesNotSupported() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(AbstractClass::class.java)
|
||||
fail()
|
||||
@@ -609,7 +607,7 @@ class KotlinCodeGenTest {
|
||||
abstract class AbstractClass(val a: Int)
|
||||
|
||||
@Ignore @Test fun innerClassesNotSupported() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(InnerClass::class.java)
|
||||
fail()
|
||||
@@ -623,7 +621,7 @@ class KotlinCodeGenTest {
|
||||
|
||||
@Ignore @Test fun localClassesNotSupported() {
|
||||
class LocalClass(val a: Int)
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(LocalClass::class.java)
|
||||
fail()
|
||||
@@ -634,7 +632,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun objectDeclarationsNotSupported() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(ObjectDeclaration.javaClass)
|
||||
fail()
|
||||
@@ -652,7 +650,7 @@ class KotlinCodeGenTest {
|
||||
val expression = object : Any() {
|
||||
var a = 5
|
||||
}
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
try {
|
||||
moshi.adapter(expression.javaClass)
|
||||
fail()
|
||||
@@ -663,7 +661,7 @@ class KotlinCodeGenTest {
|
||||
}
|
||||
|
||||
@Ignore @Test fun manyProperties32() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ManyProperties32::class.java)
|
||||
|
||||
val encoded = ManyProperties32(
|
||||
@@ -703,7 +701,7 @@ class KotlinCodeGenTest {
|
||||
var v31: Int, var v32: Int)
|
||||
|
||||
@Ignore @Test fun manyProperties33() {
|
||||
val moshi = Moshi.Builder().add(MoshiSerializableFactory()).build()
|
||||
val moshi = Moshi.Builder().build()
|
||||
val jsonAdapter = moshi.adapter(ManyProperties33::class.java)
|
||||
|
||||
val encoded = ManyProperties33(
|
||||
|
@@ -1,82 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi-parent</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>moshi-kotlin-codegen-runtime</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.squareup.moshi</groupId>
|
||||
<artifactId>moshi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>testCompile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Square, Inc.
|
||||
*
|
||||
* 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 com.squareup.moshi
|
||||
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.annotation.AnnotationRetention.RUNTIME
|
||||
import kotlin.annotation.AnnotationTarget.CLASS
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@Target(CLASS)
|
||||
annotation class MoshiSerializable
|
||||
|
||||
class MoshiSerializableFactory : JsonAdapter.Factory {
|
||||
|
||||
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
|
||||
|
||||
val rawType = Types.getRawType(type)
|
||||
if (!rawType.isAnnotationPresent(MoshiSerializable::class.java)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val clsName = rawType.name.replace("$", "_")
|
||||
val constructor = try {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val bindingClass = rawType.classLoader
|
||||
.loadClass(clsName + "JsonAdapter") as Class<out JsonAdapter<*>>
|
||||
if (type is ParameterizedType) {
|
||||
// This is generic, use the two param moshi + type constructor
|
||||
bindingClass.getDeclaredConstructor(Moshi::class.java, Array<Type>::class.java)
|
||||
} else {
|
||||
// The standard single param moshi constructor
|
||||
bindingClass.getDeclaredConstructor(Moshi::class.java)
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
throw RuntimeException("Unable to find generated Moshi adapter class for $clsName", e)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
throw RuntimeException("Unable to find generated Moshi adapter constructor for $clsName", e)
|
||||
}
|
||||
|
||||
try {
|
||||
return when {
|
||||
constructor.parameterTypes.size == 1 -> constructor.newInstance(moshi)
|
||||
type is ParameterizedType -> constructor.newInstance(moshi, type.actualTypeArguments)
|
||||
else -> throw IllegalStateException("Unable to handle type $type")
|
||||
}
|
||||
} catch (e: IllegalAccessException) {
|
||||
throw RuntimeException("Unable to invoke $constructor", e)
|
||||
} catch (e: InstantiationException) {
|
||||
throw RuntimeException("Unable to invoke $constructor", e)
|
||||
} catch (e: InvocationTargetException) {
|
||||
val cause = e.cause
|
||||
if (cause is RuntimeException) {
|
||||
throw cause
|
||||
}
|
||||
if (cause is Error) {
|
||||
throw cause
|
||||
}
|
||||
throw RuntimeException(
|
||||
"Could not create generated JsonAdapter instance for type $rawType", cause)
|
||||
}
|
||||
}
|
||||
}
|
32
moshi/src/main/java/com/squareup/moshi/JsonClass.java
Normal file
32
moshi/src/main/java/com/squareup/moshi/JsonClass.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Square, Inc.
|
||||
*
|
||||
* 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 com.squareup.moshi;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Customizes how a type is encoded as JSON.
|
||||
*
|
||||
* <p>This annotation is currently only permitted on declarations of data classes in Kotlin.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
public @interface JsonClass {
|
||||
boolean generateAdapter();
|
||||
}
|
@@ -18,6 +18,9 @@ package com.squareup.moshi;
|
||||
import com.squareup.moshi.internal.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -53,6 +56,12 @@ final class StandardJsonAdapters {
|
||||
if (type == Object.class) return new ObjectJsonAdapter(moshi).nullSafe();
|
||||
|
||||
Class<?> rawType = Types.getRawType(type);
|
||||
|
||||
JsonClass jsonClass = rawType.getAnnotation(JsonClass.class);
|
||||
if (jsonClass != null && jsonClass.generateAdapter()) {
|
||||
return generatedAdapter(moshi, type, rawType);
|
||||
}
|
||||
|
||||
if (rawType.isEnum()) {
|
||||
//noinspection unchecked
|
||||
return new EnumJsonAdapter<>((Class<? extends Enum>) rawType).nullSafe();
|
||||
@@ -215,6 +224,45 @@ final class StandardJsonAdapters {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the generated JsonAdapter for classes annotated {@link JsonClass}. This works because it
|
||||
* uses the same naming conventions as {@code JsonClassCodeGenProcessor}.
|
||||
*/
|
||||
static JsonAdapter<?> generatedAdapter(Moshi moshi, Type type, Class<?> rawType) {
|
||||
String adapterClassName = rawType.getName().replace("$", "_") + "JsonAdapter";
|
||||
try {
|
||||
@SuppressWarnings("unchecked") // We generate types to match.
|
||||
Class<? extends JsonAdapter<?>> adapterClass = (Class<? extends JsonAdapter<?>>)
|
||||
Class.forName(adapterClassName, true, rawType.getClassLoader());
|
||||
if (type instanceof ParameterizedType) {
|
||||
Constructor<? extends JsonAdapter<?>> constructor
|
||||
= adapterClass.getDeclaredConstructor(Moshi.class, Type[].class);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(moshi, ((ParameterizedType) type).getActualTypeArguments());
|
||||
} else {
|
||||
Constructor<? extends JsonAdapter<?>> constructor
|
||||
= adapterClass.getDeclaredConstructor(Moshi.class);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(moshi);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to find the generated JsonAdapter class for " + rawType, e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to find the generated JsonAdapter constructor for " + rawType, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to access the generated JsonAdapter for " + rawType, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to construct the generated JsonAdapter for " + rawType, e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to instantiate the generated JsonAdapter for " + rawType, e);
|
||||
}
|
||||
}
|
||||
|
||||
static final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
|
||||
private final Class<T> enumType;
|
||||
private final String[] nameStrings;
|
||||
|
Reference in New Issue
Block a user