in integration-test/compiler/src/main/kotlin/com/uber/crumb/integration/compiler/GsonSupport.kt [179:268]
override fun produce(context: CrumbContext,
type: TypeElement,
annotations: Collection<AnnotationMirror>): ProducerMetadata {
val elements = context.roundEnv.findElementsAnnotatedWith<CrumbConsumable>()
.filterIsInstance(TypeElement::class.java)
.filter { isConsumableApplicable(context, it) }
if (elements.isEmpty()) {
context.processingEnv.messager.printMessage(Kind.ERROR, """
|No @CrumbConsumable-annotated elements applicable for the given @CrumbProducer-annotated element with the current crumb extensions
|CrumbProducer: $type
|Extension: $this
""".trimMargin(), type)
return emptyMap<String, String>() to emptySet()
}
val gson = ParameterSpec.builder(Gson::class.java, "gson").build()
val t = TypeVariableName.get("T")
val typeParam = ParameterSpec
.builder(ParameterizedTypeName.get(ClassName.get(TypeToken::class.java), t), "type")
.build()
val result = ParameterizedTypeName.get(ClassName.get(TypeAdapter::class.java), t)
val create = MethodSpec.methodBuilder("create")
.addModifiers(PUBLIC)
.addTypeVariable(t)
.addAnnotation(Nullable::class.java)
.addAnnotation(Override::class.java)
.addAnnotation(AnnotationSpec.builder(SuppressWarnings::class.java)
.addMember("value", "\"unchecked\"")
.build())
.addParameters(ImmutableSet.of(gson, typeParam))
.returns(result)
.addStatement("Class<\$T> rawType = (Class<\$T>) \$N.getRawType()", t, t, typeParam)
val modelsMap = mutableMapOf<String, GsonSupportMeta>()
elements.forEachIndexed { i, element ->
val elementType = element.rawType()
val fqcn = elementType.toString()
if (i == 0) {
create.beginControlFlow("if (\$T.class.isAssignableFrom(rawType))", elementType)
} else {
create.nextControlFlow("else if (\$T.class.isAssignableFrom(rawType))", elementType)
}
getTypeAdapterMethod(element)?.let { typeAdapterMethod ->
val typeAdapterName = typeAdapterMethod.simpleName.toString()
val params = typeAdapterMethod.parameters
val argCount: Int
when {
params == null || params.size == 0 -> {
argCount = 0
create.addStatement("return (TypeAdapter<\$T>) \$T.$typeAdapterName()", t,
elementType)
}
params.size == 1 -> {
argCount = 1
create.addStatement("return (TypeAdapter<\$T>) \$T.$typeAdapterName(\$N)", t,
elementType, gson)
}
else -> {
argCount = 1
create.addStatement(
"return (TypeAdapter<\$T>) \$T.$typeAdapterName(\$N, (\$T) \$N)", t,
elementType, gson, params[1], typeParam)
}
}
modelsMap[fqcn] = GsonSupportMeta(typeAdapterName, argCount)
}
}
create.nextControlFlow("else")
create.addStatement("return null")
create.endControlFlow()
val originatingElements = setOf(type) + elements
val adapterName = type.classNameOf()
val packageName = type.packageName()
val factorySpec = TypeSpec.classBuilder(
ClassName.get(packageName, PRODUCER_PREFIX + adapterName))
.addModifiers(FINAL)
.addSuperinterface(TypeName.get(TypeAdapterFactory::class.java))
.addMethod(create.build())
.apply {
originatingElements.forEach { addOriginatingElement(it) }
}
.build()
JavaFile.builder(packageName, factorySpec)
.build()
.writeTo(context.processingEnv.filer)
return mapOf(Pair(EXTRAS_KEY, metaMapAdapter.toJson(modelsMap))) to elements.toSet()
}