From a884be697c55908c8a670d85f0db56f35b66e40a Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Thu, 13 Nov 2025 20:59:34 +0800 Subject: [PATCH] refactor: replace Any type with PropertyTypeValue in generator and deployer classes --- .../gropify/plugin/DefaultDeployer.kt | 13 +- .../plugin/generator/BuildscriptGenerator.kt | 18 +-- .../plugin/generator/JavaCodeGenerator.kt | 10 +- .../plugin/generator/KotlinCodeGenerator.kt | 10 +- .../plugin/generator/extension/Generator.kt | 55 +-------- .../generator/extension/PropertyType.kt | 116 ++++++++++++++++++ 6 files changed, 143 insertions(+), 79 deletions(-) create mode 100644 gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/PropertyType.kt diff --git a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/DefaultDeployer.kt b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/DefaultDeployer.kt index 0c57eb0..e6c9cc2 100644 --- a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/DefaultDeployer.kt +++ b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/DefaultDeployer.kt @@ -28,6 +28,9 @@ import com.highcapable.gropify.plugin.config.type.GropifyLocation import com.highcapable.gropify.plugin.deployer.BuildscriptDeployer import com.highcapable.gropify.plugin.deployer.SourceCodeDeployer import com.highcapable.gropify.plugin.generator.extension.PropertyMap +import com.highcapable.gropify.plugin.generator.extension.PropertyTypeValue +import com.highcapable.gropify.plugin.generator.extension.createTypeValue +import com.highcapable.gropify.plugin.generator.extension.createTypeValueByType import com.highcapable.gropify.utils.extension.hasInterpolation import com.highcapable.gropify.utils.extension.removeSurroundingQuotes import com.highcapable.gropify.utils.extension.replaceInterpolation @@ -100,10 +103,10 @@ internal object DefaultDeployer { * @return [PropertyMap] */ fun generateMap(config: GropifyConfig.CommonGenerateConfig, descriptor: ProjectDescriptor): PropertyMap { - val properties = mutableMapOf() + val properties = mutableMapOf() val resolveProperties = mutableMapOf() - config.permanentKeyValues.forEach { (key, value) -> properties[key] = value } + config.permanentKeyValues.forEach { (key, value) -> properties[key] = value.createTypeValueByType(config.useTypeAutoConversion) } config.locations.forEach { location -> when (location) { GropifyLocation.CurrentProject -> createProperties(config, descriptor.currentDir).forEach { resolveProperties.putAll(it) } @@ -156,11 +159,13 @@ internal object DefaultDeployer { config.keyValuesRules[key]?.also { resolveKeyValues[key] = it(value) } } - properties.putAll(resolveKeyValues) + properties.putAll(resolveKeyValues.map { (key, value) -> + key to value.createTypeValue(config.useTypeAutoConversion) + }) } // Replace all key-values if exists. - config.replacementKeyValues.forEach { (key, value) -> properties[key] = value } + config.replacementKeyValues.forEach { (key, value) -> properties[key] = value.createTypeValueByType(config.useTypeAutoConversion) } return properties } diff --git a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/BuildscriptGenerator.kt b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/BuildscriptGenerator.kt index bf28d22..b3bb42f 100644 --- a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/BuildscriptGenerator.kt +++ b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/BuildscriptGenerator.kt @@ -29,7 +29,7 @@ import com.highcapable.gropify.plugin.Gropify import com.highcapable.gropify.plugin.config.proxy.GropifyConfig import com.highcapable.gropify.plugin.extension.accessors.proxy.ExtensionAccessors import com.highcapable.gropify.plugin.generator.extension.PropertyMap -import com.highcapable.gropify.plugin.generator.extension.createTypedValue +import com.highcapable.gropify.plugin.generator.extension.PropertyTypeValue import com.highcapable.gropify.plugin.generator.extension.toOptimize import com.highcapable.gropify.plugin.generator.extension.toPoetNoEscape import com.highcapable.gropify.utils.extension.capitalize @@ -43,7 +43,6 @@ import com.palantir.javapoet.JavaFile import com.palantir.javapoet.MethodSpec import com.palantir.javapoet.TypeSpec import javax.lang.model.element.Modifier -import kotlin.properties.Delegates /** * Generator for buildscript accessors classes. @@ -70,8 +69,6 @@ internal class BuildscriptGenerator { } } - private var config by Delegates.notNull() - private val classSpecs = mutableMapOf() private val constructorSpecs = mutableMapOf() private val preAddConstructorSpecNames = mutableListOf>() @@ -135,16 +132,15 @@ internal class BuildscriptGenerator { }.build() ) - private fun TypeSpec.Builder.addFinalValueMethod(accessorsName: String, methodName: String, className: String, value: Any) = + private fun TypeSpec.Builder.addFinalValueMethod(accessorsName: String, methodName: String, className: String, value: PropertyTypeValue) = addMethod( MethodSpec.methodBuilder("get${getOrCreateUsedSuccessiveMethodName(methodName, className).capitalize()}").apply { - val typedValue = value.createTypedValue(config.useTypeAutoConversion) - val safeValueForJavadoc = typedValue.second.replace("$", "$$") + val safeValueForJavadoc = value.codeValue.replace("$", "$$") - addJavadoc("Resolve the \"$accessorsName\" value \"${value.toString().toPoetNoEscape()}\".") + addJavadoc("Resolve the \"$accessorsName\" value \"${value.raw.toPoetNoEscape()}\".") addModifiers(Modifier.PUBLIC, Modifier.FINAL) - returns(typedValue.first.java) + returns(value.type.java) addStatement("return $safeValueForJavadoc") }.build() ) @@ -176,7 +172,7 @@ internal class BuildscriptGenerator { * * After the parsing is completed, we need to call [releaseParseTypeSpec] to complete the parsing. */ - private fun parseTypeSpec(successiveName: String, key: String, value: Any) { + private fun parseTypeSpec(successiveName: String, key: String, value: PropertyTypeValue) { fun String.duplicateGrandSuccessiveIndex() = lowercase().let { name -> if (grandSuccessiveDuplicateIndexes.contains(name)) { grandSuccessiveDuplicateIndexes[name] = (grandSuccessiveDuplicateIndexes[name] ?: 1) + 1 @@ -274,8 +270,6 @@ internal class BuildscriptGenerator { "Class name cannot be empty or blank." } - this.config = config - val topClassName = "${config.name.replace(":", "_").upperCamelcase()}$TOP_CLASS_SUFFIX_NAME" memoryExtensionClasses[config.name] = "$ACCESSORS_PACKAGE_NAME.$topClassName" diff --git a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/JavaCodeGenerator.kt b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/JavaCodeGenerator.kt index ec9b4ac..f5d2704 100644 --- a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/JavaCodeGenerator.kt +++ b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/JavaCodeGenerator.kt @@ -27,7 +27,6 @@ import com.highcapable.gropify.plugin.config.proxy.GropifyConfig import com.highcapable.gropify.plugin.generator.config.GenerateConfig import com.highcapable.gropify.plugin.generator.config.SourceCodeSpec import com.highcapable.gropify.plugin.generator.extension.PropertyMap -import com.highcapable.gropify.plugin.generator.extension.createTypedValue import com.highcapable.gropify.plugin.generator.extension.toOptimize import com.highcapable.gropify.plugin.generator.extension.toPoetNoEscape import com.highcapable.gropify.plugin.generator.extension.toPoetSpace @@ -62,17 +61,18 @@ internal class JavaCodeGenerator { if (!config.isRestrictedAccessEnabled) addModifiers(Modifier.PUBLIC) keyValues.toOptimize().toUnderscores().forEach { (key, value) -> - val typedValue = value.second.createTypedValue(config.useTypeAutoConversion) + val currentKey = value.first + val currentValue = value.second addField( - FieldSpec.builder(typedValue.first.java, key.firstNumberToLetter()).apply { - addJavadoc("Resolve the \"${value.first.toPoetNoEscape()}\" value \"${value.second.toString().toPoetNoEscape()}\".") + FieldSpec.builder(currentValue.type.java, key.firstNumberToLetter()).apply { + addJavadoc("Resolve the \"${currentKey.toPoetNoEscape()}\" value \"${currentValue.raw.toPoetNoEscape()}\".") if (!config.isRestrictedAccessEnabled) addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) else addModifiers(Modifier.STATIC, Modifier.FINAL) - initializer(typedValue.second.toPoetNoEscape().toPoetSpace()) + initializer(currentValue.codeValue.toPoetNoEscape().toPoetSpace()) }.build() ) } diff --git a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/KotlinCodeGenerator.kt b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/KotlinCodeGenerator.kt index 4a894ec..a922c0e 100644 --- a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/KotlinCodeGenerator.kt +++ b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/KotlinCodeGenerator.kt @@ -27,7 +27,6 @@ import com.highcapable.gropify.plugin.config.proxy.GropifyConfig import com.highcapable.gropify.plugin.generator.config.GenerateConfig import com.highcapable.gropify.plugin.generator.config.SourceCodeSpec import com.highcapable.gropify.plugin.generator.extension.PropertyMap -import com.highcapable.gropify.plugin.generator.extension.createTypedValue import com.highcapable.gropify.plugin.generator.extension.toOptimize import com.highcapable.gropify.plugin.generator.extension.toPoetNoEscape import com.highcapable.gropify.plugin.generator.extension.toPoetSpace @@ -66,14 +65,15 @@ internal class KotlinCodeGenerator { if (config.isRestrictedAccessEnabled) addModifiers(KModifier.INTERNAL) keyValues.toOptimize().toUnderscores().forEach { (key, value) -> - val typedValue = value.second.createTypedValue(config.useTypeAutoConversion) + val currentKey = value.first + val currentValue = value.second - addProperty(PropertySpec.builder(key.firstNumberToLetter(), typedValue.first).apply { - addKdoc("Resolve the \"${value.first.toPoetNoEscape()}\" value \"${value.second.toString().toPoetNoEscape()}\".") + addProperty(PropertySpec.builder(key.firstNumberToLetter(), currentValue.type).apply { + addKdoc("Resolve the \"${currentKey.toPoetNoEscape()}\" value \"${currentValue.raw.toPoetNoEscape()}\".") if (config.isRestrictedAccessEnabled) addModifiers(KModifier.INTERNAL) addModifiers(KModifier.CONST) - initializer(typedValue.second.toPoetNoEscape().toPoetSpace()) + initializer(currentValue.codeValue.toPoetNoEscape().toPoetSpace()) }.build()) } }.build()) diff --git a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/Generator.kt b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/Generator.kt index 7a224ec..685fff3 100644 --- a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/Generator.kt +++ b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/Generator.kt @@ -21,63 +21,12 @@ */ package com.highcapable.gropify.plugin.generator.extension -import com.highcapable.gropify.utils.extension.isNumeric import com.highcapable.gropify.utils.extension.underscore -import kotlin.reflect.KClass -internal typealias PropertyMap = MutableMap -internal typealias PropertyOptimizeMap = MutableMap> +internal typealias PropertyMap = MutableMap +internal typealias PropertyOptimizeMap = MutableMap> internal typealias PropertyValueRule = (value: String) -> String -/** - * Create typed value from [Any] value. - * @param autoConversion whether to enable auto conversion. - * @return [Pair]<[KClass], [String]> - */ -internal fun Any.createTypedValue(autoConversion: Boolean): Pair, String> { - var isStringType = false - val valueString = toString() - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("\\", "\\\\") - .let { - if (autoConversion && (it.startsWith("\"") && it.endsWith("\"") || it.startsWith("'") && it.endsWith("'"))) { - isStringType = true - it.drop(1).dropLast(1) - } else it.replace("\"", "\\\"") - } - - if (!autoConversion) return String::class to "\"$valueString\"" - - val trimmed = valueString.trim() - val typeSpec = when { - isStringType -> String::class - trimmed.toBooleanStrictOrNull() != null -> Boolean::class - trimmed.isNumeric() -> - if (!trimmed.contains(".")) { - val longValue = trimmed.toLongOrNull() - when (longValue) { - null -> String::class - in Int.MIN_VALUE..Int.MAX_VALUE -> Int::class - else -> Long::class - } - } else { - val doubleValue = trimmed.toDoubleOrNull() - if (doubleValue == null || doubleValue.isInfinite()) - String::class - else Double::class - } - else -> String::class - } - val finalValue = when (typeSpec) { - String::class -> "\"$valueString\"" - Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L" - else -> trimmed - } - - return typeSpec to finalValue -} - /** * Optimize property keys for code generation. * @receiver [PropertyMap] diff --git a/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/PropertyType.kt b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/PropertyType.kt new file mode 100644 index 0000000..d82553b --- /dev/null +++ b/gropify-gradle-plugin/src/main/kotlin/com/highcapable/gropify/plugin/generator/extension/PropertyType.kt @@ -0,0 +1,116 @@ +/* + * Gropify - A type-safe and modern properties plugin for Gradle. + * Copyright (C) 2019 HighCapable + * https://github.com/HighCapable/Gropify + * + * Apache License Version 2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is created by fankes on 2025/11/13. + */ +package com.highcapable.gropify.plugin.generator.extension + +import com.highcapable.gropify.internal.error +import com.highcapable.gropify.plugin.Gropify +import com.highcapable.gropify.utils.extension.isNumeric +import kotlin.reflect.KClass + +/** + * Create [PropertyTypeValue] from [String] value. + * @receiver [String] + * @param autoConversion whether to enable auto conversion. + * @return [PropertyTypeValue] + */ +internal fun String.createTypeValue(autoConversion: Boolean): PropertyTypeValue { + var isStringType = false + val valueString = replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\\", "\\\\") + .let { + if (autoConversion && (it.startsWith("\"") && it.endsWith("\"") || it.startsWith("'") && it.endsWith("'"))) { + isStringType = true + it.drop(1).dropLast(1) + } else it.replace("\"", "\\\"") + } + + if (!autoConversion) return PropertyTypeValue(this, "\"$valueString\"", String::class) + + val trimmed = valueString.trim() + val typeSpec = when { + isStringType -> String::class + trimmed.toBooleanStrictOrNull() != null -> Boolean::class + trimmed.isNumeric() -> + if (!trimmed.contains(".")) { + val longValue = trimmed.toLongOrNull() + when (longValue) { + null -> String::class + in Int.MIN_VALUE..Int.MAX_VALUE -> Int::class + else -> Long::class + } + } else { + val doubleValue = trimmed.toDoubleOrNull() + if (doubleValue == null || doubleValue.isInfinite()) + String::class + else Double::class + } + else -> String::class + } + val finalValue = when (typeSpec) { + String::class -> "\"$valueString\"" + Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L" + else -> trimmed + } + + return PropertyTypeValue(this, finalValue, typeSpec) +} + +/** + * Create [PropertyTypeValue] from [Any] value's type. + * @receiver [Any] + * @param autoConversion whether to enable auto conversion. + * @return [PropertyTypeValue] + */ +internal fun Any.createTypeValueByType(autoConversion: Boolean): PropertyTypeValue { + val typeSpec = this.javaClass.kotlin + val valueString = toString() + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\\", "\\\\") + .replace("\"", "\\\"") + + val trimmed = valueString.trim() + + val finalValue = if (autoConversion) when (typeSpec) { + String::class, CharSequence::class -> "\"$trimmed\"" + Char::class -> "'$trimmed'" + Long::class -> if (trimmed.endsWith("L")) trimmed else "${trimmed}L" + Float::class -> if (trimmed.endsWith("f") || trimmed.endsWith("F")) trimmed else "${trimmed}f" + Int::class, Double::class -> trimmed + else -> Gropify.error( + "Unsupported property value type: ${typeSpec.qualifiedName}, " + + "only String, CharSequence, Char, Int, Long, Float, Double are supported." + ) + } else "\"$valueString\"" + + return PropertyTypeValue(this.toString(), finalValue, typeSpec) +} + +/** + * Property type value entity. + */ +internal data class PropertyTypeValue( + val raw: String, + val codeValue: String, + val type: KClass<*> +) \ No newline at end of file