override fun produce()

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()
  }