in integration-test/compiler/src/main/kotlin/com/uber/crumb/integration/compiler/MoshiSupport.kt [179:314]
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 typeParam = TYPE_SPEC
val annotationsParam = ANNOTATIONS_SPEC
val moshi = MOSHI_SPEC
val create = MethodSpec.methodBuilder("create")
.addModifiers(PUBLIC)
.addAnnotation(Nullable::class.java)
.addAnnotation(Override::class.java)
.addParameters(ImmutableSet.of(typeParam, annotationsParam, moshi))
.returns(
FACTORY_RETURN_TYPE_NAME)
var classes: CodeBlock.Builder? = null
var generics: CodeBlock.Builder? = null
var factories: CodeBlock.Builder? = null
var numGenerics = 0
var numClasses = 0
var numFactories = 0
// Avoid providing an adapter for an annotated type.
create.addStatement("if (!\$N.isEmpty()) return null", annotationsParam)
val modelsMap = mutableMapOf<String, MoshiSupportMeta>()
for (element in elements) {
val elementType = element.rawType()
val fqcn = elementType.toString()
val factoryMethod = getJsonAdapterFactoryMethod(element)
if (factoryMethod != null) {
val factoryMethodName = factoryMethod.simpleName.toString()
factories = factories ?: CodeBlock.builder()
if (numFactories == 0) {
factories!!.addStatement("\$T adapter",
FACTORY_RETURN_TYPE_NAME)
factories.beginControlFlow(
"if ((adapter = \$L.\$L().create(type, annotations, moshi)) != null)",
element,
factoryMethod.simpleName)
} else {
factories!!.nextControlFlow(
"else if ((adapter = \$L.\$L().create(type, annotations, moshi)) != null)",
element,
factoryMethod.simpleName)
}
factories.addStatement("return adapter")
numFactories++
modelsMap[fqcn] = MoshiSupportMeta(factoryMethodName,
isFactory = true)
continue
}
val elementTypeName = TypeName.get(element.asType())
if (elementTypeName is ParameterizedTypeName) {
generics = generics ?: CodeBlock.builder()
.beginControlFlow("if (\$N instanceof \$T)", typeParam, ParameterizedType::class.java)
.addStatement("\$T rawType = ((\$T) \$N).getRawType()", Type::class.java,
ParameterizedType::class.java, typeParam)
addControlFlowGeneric(generics!!, elementTypeName, element, numGenerics)
numGenerics++
} else {
val jsonAdapterMethod = getJsonAdapterMethod(element)
if (jsonAdapterMethod != null) {
val adapterMethodName = jsonAdapterMethod.simpleName.toString()
classes = classes ?: CodeBlock.builder()
addControlFlow(classes!!, CodeBlock.of("\$N", typeParam), elementTypeName, numClasses)
numClasses++
val paramsCount = jsonAdapterMethod.parameters.size
if (paramsCount == 1) {
classes.addStatement("return \$T.\$L(\$N)", element, jsonAdapterMethod.simpleName,
moshi)
} else {
// No arg factory
classes.addStatement("return \$L.\$L()", element.simpleName,
jsonAdapterMethod.simpleName)
}
modelsMap[fqcn] = MoshiSupportMeta(adapterMethodName,
argCount = paramsCount)
}
}
}
generics?.apply {
endControlFlow()
addStatement("return null")
endControlFlow()
create.addCode(build())
}
classes?.apply {
endControlFlow()
create.addCode(build())
}
factories?.apply {
endControlFlow()
create.addCode(build())
}
create.addStatement("return null")
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(JsonAdapter.Factory::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()
}