override fun produce()

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