se.ansman.deager.renderers.EagerObjectModuleJavaRenderer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
Eager Singletons with Dagger
The newest version!
package se.ansman.deager.renderers
import com.squareup.javapoet.AnnotationSpec
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.JavaFile
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterSpec
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.codegen.OriginatingElement
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import se.ansman.deager.Initializable
import se.ansman.deager.asClassName
import se.ansman.deager.models.EagerObject
import javax.lang.model.element.Modifier
typealias JavaEagerObject = EagerObject
class EagerObjectModuleJavaRenderer private constructor(
private val moduleName: ClassName,
private val originatingElement: ClassName,
private val eagerObjects: List
) {
constructor(module: ClassName, eagerObjects: Iterable) : this(
moduleName = module.peerClass(module.simpleNames().joinToString(separator = "", prefix = "Eager")),
originatingElement = module.topLevelClassName(),
eagerObjects = eagerObjects.toList()
)
constructor(eagerObject: JavaEagerObject) : this(
moduleName = eagerObject.moduleName(),
originatingElement = eagerObject.targetType.asClassName().topLevelClassName(),
eagerObjects = listOf(eagerObject)
)
fun render(modifier: TypeSpec.Builder.() -> Unit = {}): JavaFile {
val typeSpec = TypeSpec.classBuilder(moduleName)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addMethod(
MethodSpec.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.build()
)
.addAnnotation(Module::class.java)
.addAnnotation(
AnnotationSpec.builder(InstallIn::class.java)
.addMember("value", "\$T.class", SingletonComponent::class.java)
.build()
)
.addAnnotation(
AnnotationSpec.builder(OriginatingElement::class.java)
.addMember("topLevelClass", "\$T.class", originatingElement)
.build()
)
for (eagerObject in eagerObjects) {
val qualifiers = eagerObject.qualifiers.map { it.toAnnotationSpec() }
val methodSpec = MethodSpec.methodBuilder(eagerObject.method.name)
val parameterName = eagerObject.targetType
.asClassName()
.simpleName()
.replaceFirstChar(Char::lowercaseChar)
when (eagerObject.method) {
is EagerObject.Method.Binding -> {
methodSpec
.addModifiers(Modifier.ABSTRACT)
.addAnnotation(Binds::class.java)
.addParameter(
ParameterSpec
.builder(eagerObject.targetType, parameterName)
.addAnnotations(qualifiers)
.build()
)
}
is EagerObject.Method.Provider -> {
val parameter = ParameterSpec
.builder(
ParameterizedTypeName.get(ClassName.get(Lazy::class.java), eagerObject.targetType),
parameterName
)
.addAnnotations(qualifiers)
.build()
methodSpec
.addModifiers(Modifier.STATIC)
.addAnnotation(Provides::class.java)
.addParameter(parameter)
.addStatement(
"return \$T.fromLazy(\$N\$L)",
Initializable::class.java,
parameter,
if (eagerObject.priority == null) {
CodeBlock.of("")
} else {
CodeBlock.of(", /* priority */ \$L", eagerObject.priority)
}
)
}
}
typeSpec.addMethod(
methodSpec
.addModifiers(Modifier.PUBLIC)
.addAnnotation(IntoSet::class.java)
.returns(Initializable::class.java)
.build()
)
}
return JavaFile.builder(moduleName.packageName(), typeSpec.apply(modifier).build())
.addFileComment("Code generated by Deager. Do not edit.")
.build()
}
}
private fun JavaEagerObject.moduleName(): ClassName =
ClassName.get(
targetType.asClassName().packageName(),
targetType.asClassName().simpleNames().joinToString(prefix = "Eager", postfix = "Module", separator = "")
)