mirror of
https://github.com/fankes/moshi.git
synced 2025-10-20 00:19:21 +08:00
Check types parameter size in init (#1063)
* Add types size check in code gen Resolves #932 * Add more useful message for mismatched generics lookup * Add tests * Style
This commit is contained in:
@@ -18,6 +18,7 @@ package com.squareup.moshi.kotlin.codegen.api
|
|||||||
import com.squareup.kotlinpoet.ARRAY
|
import com.squareup.kotlinpoet.ARRAY
|
||||||
import com.squareup.kotlinpoet.AnnotationSpec
|
import com.squareup.kotlinpoet.AnnotationSpec
|
||||||
import com.squareup.kotlinpoet.CodeBlock
|
import com.squareup.kotlinpoet.CodeBlock
|
||||||
|
import com.squareup.kotlinpoet.CodeBlock.Companion
|
||||||
import com.squareup.kotlinpoet.FileSpec
|
import com.squareup.kotlinpoet.FileSpec
|
||||||
import com.squareup.kotlinpoet.FunSpec
|
import com.squareup.kotlinpoet.FunSpec
|
||||||
import com.squareup.kotlinpoet.INT
|
import com.squareup.kotlinpoet.INT
|
||||||
@@ -158,6 +159,22 @@ internal class AdapterGenerator(
|
|||||||
|
|
||||||
if (typeVariables.isNotEmpty()) {
|
if (typeVariables.isNotEmpty()) {
|
||||||
result.addTypeVariables(typeVariables.map { it.stripTypeVarVariance() as TypeVariableName })
|
result.addTypeVariables(typeVariables.map { it.stripTypeVarVariance() as TypeVariableName })
|
||||||
|
// require(types.size == 1) {
|
||||||
|
// "TypeVariable mismatch: Expecting 1 type(s) for generic type variables [T], but received ${types.size} with values $types"
|
||||||
|
// }
|
||||||
|
result.addInitializerBlock(CodeBlock.builder()
|
||||||
|
.beginControlFlow("require(types.size == %L)", typeVariables.size)
|
||||||
|
.addStatement(
|
||||||
|
"buildString·{·append(%S).append(%L).append(%S).append(%S).append(%S).append(%L)·}",
|
||||||
|
"TypeVariable mismatch: Expecting ",
|
||||||
|
typeVariables.size,
|
||||||
|
" ${if (typeVariables.size == 1) "type" else "types"} for generic type variables [",
|
||||||
|
typeVariables.joinToString(", ") { it.name },
|
||||||
|
"], but received ",
|
||||||
|
"${typesParam.name}.size"
|
||||||
|
)
|
||||||
|
.endControlFlow()
|
||||||
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO make this configurable. Right now it just matches the source model
|
// TODO make this configurable. Right now it just matches the source model
|
||||||
|
@@ -1220,6 +1220,30 @@ class GeneratedAdaptersTest {
|
|||||||
val propertyWithAnnotatedType: @TypeAnnotation String = "",
|
val propertyWithAnnotatedType: @TypeAnnotation String = "",
|
||||||
val generic: List<@TypeAnnotation String>
|
val generic: List<@TypeAnnotation String>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Test fun typesSizeCheckMessages_noArgs() {
|
||||||
|
try {
|
||||||
|
moshi.adapter(MultipleGenerics::class.java)
|
||||||
|
fail("Should have failed to construct the adapter due to missing generics")
|
||||||
|
} catch (e: RuntimeException) {
|
||||||
|
assertThat(e).hasMessage("Failed to find the generated JsonAdapter constructor for 'class com.squareup.moshi.kotlin.codegen.GeneratedAdaptersTest\$MultipleGenerics'. Suspiciously, the type was not parameterized but the target class 'com.squareup.moshi.kotlin.codegen.GeneratedAdaptersTest_MultipleGenericsJsonAdapter' is generic. Consider using Types#newParameterizedType() to define these missing type variables.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun typesSizeCheckMessages_wrongNumberOfArgs() {
|
||||||
|
try {
|
||||||
|
GeneratedAdaptersTest_MultipleGenericsJsonAdapter<String, Any, Any, Any>(
|
||||||
|
moshi,
|
||||||
|
arrayOf(String::class.java)
|
||||||
|
)
|
||||||
|
fail("Should have failed to construct the adapter due to wrong number of generics")
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
assertThat(e).hasMessage("TypeVariable mismatch: Expecting 4 types for generic type variables [A, B, C, D], but received 1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class MultipleGenerics<A, B, C, D>(val prop: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regression test for https://github.com/square/moshi/issues/1022
|
// Regression test for https://github.com/square/moshi/issues/1022
|
||||||
|
@@ -517,9 +517,10 @@ public final class Util {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String adapterClassName = Types.generatedJsonAdapterName(rawType.getName());
|
String adapterClassName = Types.generatedJsonAdapterName(rawType.getName());
|
||||||
|
Class<? extends JsonAdapter<?>> adapterClass = null;
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("unchecked") // We generate types to match.
|
//noinspection unchecked - We generate types to match.
|
||||||
Class<? extends JsonAdapter<?>> adapterClass = (Class<? extends JsonAdapter<?>>)
|
adapterClass = (Class<? extends JsonAdapter<?>>)
|
||||||
Class.forName(adapterClassName, true, rawType.getClassLoader());
|
Class.forName(adapterClassName, true, rawType.getClassLoader());
|
||||||
Constructor<? extends JsonAdapter<?>> constructor;
|
Constructor<? extends JsonAdapter<?>> constructor;
|
||||||
Object[] args;
|
Object[] args;
|
||||||
@@ -547,16 +548,24 @@ public final class Util {
|
|||||||
return constructor.newInstance(args).nullSafe();
|
return constructor.newInstance(args).nullSafe();
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Failed to find the generated JsonAdapter class for " + rawType, e);
|
"Failed to find the generated JsonAdapter class for " + type, e);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new RuntimeException(
|
if (!(type instanceof ParameterizedType) && adapterClass.getTypeParameters().length != 0) {
|
||||||
"Failed to find the generated JsonAdapter constructor for " + rawType, e);
|
throw new RuntimeException(
|
||||||
|
"Failed to find the generated JsonAdapter constructor for '" + type
|
||||||
|
+ "'. Suspiciously, the type was not parameterized but the target class '"
|
||||||
|
+ adapterClass.getCanonicalName() + "' is generic. Consider using "
|
||||||
|
+ "Types#newParameterizedType() to define these missing type variables.", e);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Failed to find the generated JsonAdapter constructor for " + type, e);
|
||||||
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Failed to access the generated JsonAdapter for " + rawType, e);
|
"Failed to access the generated JsonAdapter for " + type, e);
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Failed to instantiate the generated JsonAdapter for " + rawType, e);
|
"Failed to instantiate the generated JsonAdapter for " + type, e);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
throw rethrowCause(e);
|
throw rethrowCause(e);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user