io.appmetrica.gradle.aarcheck.api.ApiSerializer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aar-check Show documentation
Show all versions of aar-check Show documentation
Provides plugin for check aar
The newest version!
package io.appmetrica.gradle.aarcheck.api
import io.appmetrica.gradle.aarcheck.utils.MappingFile
import java.io.File
private val NULLABLE_ANNOTATIONS = listOf(
"androidx.annotation.Nullable",
"org.jetbrains.annotations.Nullable"
)
private val NONNULL_ANNOTATIONS = listOf(
"androidx.annotation.NonNull",
"org.jetbrains.annotations.NotNull"
)
private val NOT_PRINT_PACKAGES = listOf(
"java.lang"
)
class ApiSerializer(
mappingFile: MappingFile? = null
) {
private class BodyGroup(
val isEmpty: Boolean,
val appendTo: Appendable.() -> Unit
)
private val nameProvider = NameProvider(mappingFile)
fun writeTo(classes: List, file: File) {
file.parentFile.mkdirs()
file.bufferedWriter().use { out ->
writeTo(classes, out)
}
}
fun writeTo(classes: List, appender: Appendable) {
val apiClasses = classes.sortedBy { it.fullName }
for (clazz in apiClasses) {
when (clazz.type) {
ClassType.CLASS -> appender.appendClass(clazz)
ClassType.ENUM -> appender.appendEnum(clazz)
ClassType.INTERFACE -> appender.appendInterface(clazz)
ClassType.ANNOTATION -> appender.appendAnnotation(clazz)
}
appender.newLine()
}
}
private fun Appendable.appendEnum(clazz: Class) = apply {
append(clazz.modifier.toString()).append(" ")
append(clazz.type.toString()).append(" ")
append(clazz.fullName)
if (clazz.interfaces.isNotEmpty()) {
append(" implementation ").appendList(clazz.interfaces, ", ") { appendType(it) }
}
val isEnumConstant = { field: Field ->
field.isFinal && field.isStatic && field.type.fullName == clazz.fullName
}
val enumValues = clazz.fields.filter(isEnumConstant)
val fields = clazz.fields.filterNot(isEnumConstant)
appendBody(
BodyGroup(isEmpty = enumValues.isEmpty()) {
appendTab()
appendList(enumValues.sortedBy { it.name }, ", ") { append(it.name) }
newLine()
},
fieldBodyGroup(fields),
methodBodyGroup(clazz.methods)
)
newLine()
}
private fun Appendable.appendAnnotation(clazz: Class) = apply {
append(clazz.modifier.toString()).append(" ")
append(clazz.type.toString()).append(" ")
append(clazz.fullName)
appendBody(
fieldBodyGroup(clazz.fields),
methodBodyGroup(clazz.methods)
)
newLine()
}
private fun Appendable.appendInterface(clazz: Class) = apply {
append(clazz.modifier.toString()).append(" ")
append(clazz.type.toString()).append(" ")
append(clazz.fullName)
appendGenericParameters(clazz.genericParameters)
if (clazz.interfaces.isNotEmpty()) {
append(" extends ").appendList(clazz.interfaces, ", ") { appendType(it) }
}
appendBody(
fieldBodyGroup(clazz.fields),
methodBodyGroup(clazz.methods)
)
newLine()
}
private fun Appendable.appendClass(clazz: Class) = apply {
append(clazz.modifier.toString()).append(" ")
if (clazz.isAbstract) append("abstract ")
if (clazz.isStatic) append("static ")
if (clazz.isFinal) append("final ")
append(clazz.type.toString()).append(" ")
append(clazz.fullName)
appendGenericParameters(clazz.genericParameters)
if (clazz.superClass != null) {
append(" extends ").appendType(clazz.superClass)
}
if (clazz.interfaces.isNotEmpty()) {
append(" implementation ").appendList(clazz.interfaces, ", ") { appendType(it) }
}
appendBody(
fieldBodyGroup(clazz.fields),
methodBodyGroup(clazz.methods)
)
newLine()
}
private fun fieldBodyGroup(fields: List) = BodyGroup(isEmpty = fields.isEmpty()) {
fields.sortedBy { nameProvider.getClearFieldName(it) }.forEach { appendField(it) }
}
private fun methodBodyGroup(methods: List) = BodyGroup(isEmpty = methods.isEmpty()) {
methods.sortedBy { "${nameProvider.getClearMethodName(it)}(${it.paramString})" }.forEach { appendMethod(it) }
}
private fun Appendable.appendBody(vararg groups: BodyGroup) = apply {
if (groups.all { it.isEmpty }) return@apply
append(" {").newLine()
appendList(groups.filterNot { it.isEmpty }, "\n") { it.appendTo(this) }
append("}")
}
private fun Appendable.appendField(field: Field) = apply {
appendTab()
append(field.modifier.toString()).append(" ")
if (field.isStatic) append("static ")
if (field.isFinal) append("final ")
appendNullable(field.annotations)
appendType(field.type).append(" ")
append(nameProvider.getFieldName(field))
newLine()
}
private fun Appendable.appendMethod(method: Method) = apply {
appendTab()
append(method.modifier.toString()).append(" ")
if (method.isAbstract) append("abstract ")
if (method.isStatic) append("static ")
if (method.isFinal) append("final ")
if (method.genericParameters.isNotEmpty()) {
appendGenericParameters(method.genericParameters).append(" ")
}
if (!method.isConstructor) {
appendNullable(method.annotations)
appendType(method.returnType).append(" ")
}
append(nameProvider.getMethodName(method))
append("(")
appendList(method.params, ", ") { appendMethodParam(it) }
append(")")
newLine()
}
private fun Appendable.appendMethodParam(param: MethodParam) = apply {
appendNullable(param.annotations)
appendType(param.type)
if (param.isVarArgs) append("...")
}
private fun Appendable.appendType(type: Type) = apply {
if (type.packageName in NOT_PRINT_PACKAGES) {
append(type.name)
} else {
append(nameProvider.getClassName(type))
}
appendTypeArguments(type.arguments)
repeat(type.arrayDim) {
append("[]")
}
}
private fun Appendable.appendGenericParameters(parameters: List) = apply {
if (parameters.isEmpty()) return@apply
append("<")
appendList(parameters, ", ") { appendTypeParameter(it) }
append(">")
}
private fun Appendable.appendTypeParameter(parameter: TypeParameter) = apply {
append(parameter.name)
val extends = listOfNotNull(
parameter.extend.takeIf { it.fullName != "java.lang.Object" }
) + parameter.interfaces
if (extends.isNotEmpty()) {
append(" extends ")
appendList(extends, " & ") { appendType(it) }
}
}
private fun Appendable.appendTypeArguments(arguments: List) = apply {
if (arguments.isEmpty()) return@apply
append("<")
appendList(arguments, ", ") { appendTypeArgument(it) }
append(">")
}
private fun Appendable.appendTypeArgument(argument: TypeArgument): Appendable {
when (argument.wildcard) {
'*' -> append("?")
'+' -> append("? extends ")
'-' -> append("? super ")
}
if (argument.type != null) {
appendType(argument.type)
}
return this
}
private fun Appendable.appendNullable(annotations: List) = apply {
if (annotations.any { it.type.fullName in NULLABLE_ANNOTATIONS }) {
append("[Nullable] ")
} else if (annotations.any { it.type.fullName in NONNULL_ANNOTATIONS }) {
append("[NonNull] ")
}
}
}
private fun Appendable.appendList(list: List, delimiter: String, appender: Appendable.(T) -> Unit) = apply {
list.forEachIndexed { index, it ->
appender(it)
if (index != list.lastIndex) {
append(delimiter)
}
}
}
private fun Appendable.appendTab(n: Int = 1) = apply {
append(" ".repeat(n))
}
private fun Appendable.newLine() = apply {
append("\n")
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy