summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hai Zhang <zhanghai@google.com> 2023-04-21 01:43:47 +0000
committer Hai Zhang <zhanghai@google.com> 2023-04-20 19:13:53 -0700
commitf89fc1df277ae570c942e89e2ae8803258741f17 (patch)
tree475643a763639b4982ce2e169a1313c220fa0949
parent9fc312cdcd15668141c65d7df41f027602623a41 (diff)
Remove unused old tool.
This codegen was never actually put into production. Test: build Change-Id: I0f8b5a994bf9fd32b4b5cbb4ab469ede8988edbb
-rw-r--r--tools/xmlpersistence/Android.bp20
-rw-r--r--tools/xmlpersistence/OWNERS1
-rw-r--r--tools/xmlpersistence/manifest.txt1
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Generator.kt577
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Main.kt45
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Parser.kt248
-rw-r--r--tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt44
7 files changed, 0 insertions, 936 deletions
diff --git a/tools/xmlpersistence/Android.bp b/tools/xmlpersistence/Android.bp
deleted file mode 100644
index 0b6dba626794..000000000000
--- a/tools/xmlpersistence/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_binary_host {
- name: "xmlpersistence_cli",
- manifest: "manifest.txt",
- srcs: [
- "src/**/*.kt",
- ],
- static_libs: [
- "javaparser-symbol-solver",
- "javapoet",
- ],
-}
diff --git a/tools/xmlpersistence/OWNERS b/tools/xmlpersistence/OWNERS
deleted file mode 100644
index 4f4d06a32676..000000000000
--- a/tools/xmlpersistence/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-zhanghai@google.com
diff --git a/tools/xmlpersistence/manifest.txt b/tools/xmlpersistence/manifest.txt
deleted file mode 100644
index 6d9771998efc..000000000000
--- a/tools/xmlpersistence/manifest.txt
+++ /dev/null
@@ -1 +0,0 @@
-Main-class: MainKt
diff --git a/tools/xmlpersistence/src/main/kotlin/Generator.kt b/tools/xmlpersistence/src/main/kotlin/Generator.kt
deleted file mode 100644
index 8e62388c860f..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/Generator.kt
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.JavaFile
-import com.squareup.javapoet.MethodSpec
-import com.squareup.javapoet.NameAllocator
-import com.squareup.javapoet.ParameterSpec
-import com.squareup.javapoet.TypeSpec
-import java.io.File
-import java.io.FileInputStream
-import java.io.FileNotFoundException
-import java.io.FileOutputStream
-import java.io.IOException
-import java.nio.charset.StandardCharsets
-import java.time.Year
-import java.util.Objects
-import javax.lang.model.element.Modifier
-
-// JavaPoet only supports line comments, and can't add a newline after file level comments.
-val FILE_HEADER = """
- /*
- * Copyright (C) ${Year.now().value} The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
- // Generated by xmlpersistence. DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- // @formatter:off
-""".trimIndent() + "\n\n"
-
-private val atomicFileType = ClassName.get("android.util", "AtomicFile")
-
-fun generate(persistence: PersistenceInfo): JavaFile {
- val distinctClassFields = persistence.root.allClassFields.distinctBy { it.type }
- val type = TypeSpec.classBuilder(persistence.name)
- .addJavadoc(
- """
- Generated class implementing XML persistence for${'$'}W{@link $1T}.
- <p>
- This class provides atomicity for persistence via {@link $2T}, however it does not provide
- thread safety, so please bring your own synchronization mechanism.
- """.trimIndent(), persistence.root.type, atomicFileType
- )
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .addField(generateFileField())
- .addMethod(generateConstructor())
- .addMethod(generateReadMethod(persistence.root))
- .addMethod(generateParseMethod(persistence.root))
- .addMethods(distinctClassFields.map { generateParseClassMethod(it) })
- .addMethod(generateWriteMethod(persistence.root))
- .addMethod(generateSerializeMethod(persistence.root))
- .addMethods(distinctClassFields.map { generateSerializeClassMethod(it) })
- .addMethod(generateDeleteMethod())
- .build()
- return JavaFile.builder(persistence.root.type.packageName(), type)
- .skipJavaLangImports(true)
- .indent(" ")
- .build()
-}
-
-private val nonNullType = ClassName.get("android.annotation", "NonNull")
-
-private fun generateFileField(): FieldSpec =
- FieldSpec.builder(atomicFileType, "mFile", Modifier.PRIVATE, Modifier.FINAL)
- .addAnnotation(nonNullType)
- .build()
-
-private fun generateConstructor(): MethodSpec =
- MethodSpec.constructorBuilder()
- .addJavadoc(
- """
- Create an instance of this class.
-
- @param file the XML file for persistence
- """.trimIndent()
- )
- .addModifiers(Modifier.PUBLIC)
- .addParameter(
- ParameterSpec.builder(File::class.java, "file").addAnnotation(nonNullType).build()
- )
- .addStatement("mFile = new \$1T(file)", atomicFileType)
- .build()
-
-private val nullableType = ClassName.get("android.annotation", "Nullable")
-
-private val xmlPullParserType = ClassName.get("org.xmlpull.v1", "XmlPullParser")
-
-private val xmlType = ClassName.get("android.util", "Xml")
-
-private val xmlPullParserExceptionType = ClassName.get("org.xmlpull.v1", "XmlPullParserException")
-
-private fun generateReadMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("read")
- .addJavadoc(
- """
- Read${'$'}W{@link $1T}${'$'}Wfrom${'$'}Wthe${'$'}WXML${'$'}Wfile.
-
- @return the persisted${'$'}W{@link $1T},${'$'}Wor${'$'}W{@code null}${'$'}Wif${'$'}Wthe${'$'}WXML${'$'}Wfile${'$'}Wdoesn't${'$'}Wexist
- @throws IllegalArgumentException if an error occurred while reading
- """.trimIndent(), rootField.type
- )
- .addAnnotation(nullableType)
- .addModifiers(Modifier.PUBLIC)
- .returns(rootField.type)
- .addControlFlow("try (\$1T inputStream = mFile.openRead())", FileInputStream::class.java) {
- addStatement("final \$1T parser = \$2T.newPullParser()", xmlPullParserType, xmlType)
- addStatement("parser.setInput(inputStream, null)")
- addStatement("return parse(parser)")
- nextControlFlow("catch (\$1T e)", FileNotFoundException::class.java)
- addStatement("return null")
- nextControlFlow(
- "catch (\$1T | \$2T e)", IOException::class.java, xmlPullParserExceptionType
- )
- addStatement("throw new IllegalArgumentException(e)")
- }
- .build()
-
-private val ClassFieldInfo.allClassFields: List<ClassFieldInfo>
- get() =
- mutableListOf<ClassFieldInfo>().apply {
- this += this@allClassFields
- for (field in fields) {
- when (field) {
- is ClassFieldInfo -> this += field.allClassFields
- is ListFieldInfo -> this += field.element.allClassFields
- else -> {}
- }
- }
- }
-
-private fun generateParseMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("parse")
- .addAnnotation(nonNullType)
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .returns(rootField.type)
- .addParameter(
- ParameterSpec.builder(xmlPullParserType, "parser").addAnnotation(nonNullType).build()
- )
- .addExceptions(listOf(ClassName.get(IOException::class.java), xmlPullParserExceptionType))
- .apply {
- addStatement("int type")
- addStatement("int depth")
- addStatement("int innerDepth = parser.getDepth() + 1")
- addControlFlow(
- "while ((type = parser.next()) != \$1T.END_DOCUMENT\$W"
- + "&& ((depth = parser.getDepth()) >= innerDepth || type != \$1T.END_TAG))",
- xmlPullParserType
- ) {
- addControlFlow(
- "if (depth > innerDepth || type != \$1T.START_TAG)", xmlPullParserType
- ) {
- addStatement("continue")
- }
- addControlFlow(
- "if (\$1T.equals(parser.getName(),\$W\$2S))", Objects::class.java,
- rootField.tagName
- ) {
- addStatement("return \$1L(parser)", rootField.parseMethodName)
- }
- }
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Missing root tag <${rootField.tagName}>"
- )
- }
- .build()
-
-private fun generateParseClassMethod(classField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder(classField.parseMethodName)
- .addAnnotation(nonNullType)
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .returns(classField.type)
- .addParameter(
- ParameterSpec.builder(xmlPullParserType, "parser").addAnnotation(nonNullType).build()
- )
- .apply {
- val (attributeFields, tagFields) = classField.fields
- .partition { it is PrimitiveFieldInfo || it is StringFieldInfo }
- if (tagFields.isNotEmpty()) {
- addExceptions(
- listOf(ClassName.get(IOException::class.java), xmlPullParserExceptionType)
- )
- }
- val nameAllocator = NameAllocator().apply {
- newName("parser")
- newName("type")
- newName("depth")
- newName("innerDepth")
- }
- for (field in attributeFields) {
- val variableName = nameAllocator.newName(field.variableName, field)
- when (field) {
- is PrimitiveFieldInfo -> {
- val stringVariableName =
- nameAllocator.newName("${field.variableName}String")
- addStatement(
- "final String \$1L =\$Wparser.getAttributeValue(null,\$W\$2S)",
- stringVariableName, field.attributeName
- )
- if (field.isRequired) {
- addControlFlow("if (\$1L == null)", stringVariableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Missing attribute \"${field.attributeName}\""
- )
- }
- }
- val boxedType = field.type.box()
- val parseTypeMethodName = if (field.type.isPrimitive) {
- "parse${field.type.toString().capitalize()}"
- } else {
- "valueOf"
- }
- if (field.isRequired) {
- addStatement(
- "final \$1T \$2L =\$W\$3T.\$4L($5L)", field.type, variableName,
- boxedType, parseTypeMethodName, stringVariableName
- )
- } else {
- addStatement(
- "final \$1T \$2L =\$W$3L != null ?\$W\$4T.\$5L($3L)\$W: null",
- field.type, variableName, stringVariableName, boxedType,
- parseTypeMethodName
- )
- }
- }
- is StringFieldInfo ->
- addStatement(
- "final String \$1L =\$Wparser.getAttributeValue(null,\$W\$2S)",
- variableName, field.attributeName
- )
- else -> error(field)
- }
- }
- if (tagFields.isNotEmpty()) {
- for (field in tagFields) {
- val variableName = nameAllocator.newName(field.variableName, field)
- when (field) {
- is ClassFieldInfo ->
- addStatement("\$1T \$2L =\$Wnull", field.type, variableName)
- is ListFieldInfo ->
- addStatement(
- "final \$1T \$2L =\$Wnew \$3T<>()", field.type, variableName,
- ArrayList::class.java
- )
- else -> error(field)
- }
- }
- addStatement("int type")
- addStatement("int depth")
- addStatement("int innerDepth = parser.getDepth() + 1")
- addControlFlow(
- "while ((type = parser.next()) != \$1T.END_DOCUMENT\$W"
- + "&& ((depth = parser.getDepth()) >= innerDepth || type != \$1T.END_TAG))",
- xmlPullParserType
- ) {
- addControlFlow(
- "if (depth > innerDepth || type != \$1T.START_TAG)", xmlPullParserType
- ) {
- addStatement("continue")
- }
- addControlFlow("switch (parser.getName())") {
- for (field in tagFields) {
- addControlFlow("case \$1S:", field.tagName) {
- val variableName = nameAllocator.get(field)
- when (field) {
- is ClassFieldInfo -> {
- addControlFlow("if (\$1L != null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Duplicate tag \"${field.tagName}\""
- )
- }
- addStatement(
- "\$1L =\$W\$2L(parser)", variableName,
- field.parseMethodName
- )
- addStatement("break")
- }
- is ListFieldInfo -> {
- val elementNameAllocator = nameAllocator.clone()
- val elementVariableName = elementNameAllocator.newName(
- field.element.xmlName!!.toLowerCamelCase()
- )
- addStatement(
- "final \$1T \$2L =\$W\$3L(parser)", field.element.type,
- elementVariableName, field.element.parseMethodName
- )
- addStatement(
- "\$1L.add(\$2L)", variableName, elementVariableName
- )
- addStatement("break")
- }
- else -> error(field)
- }
- }
- }
- }
- }
- }
- for (field in tagFields.filter { it is ClassFieldInfo && it.isRequired }) {
- addControlFlow("if ($1L == null)", nameAllocator.get(field)) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)", "Missing tag <${field.tagName}>"
- )
- }
- }
- addStatement(
- classField.fields.joinToString(",\$W", "return new \$1T(", ")") {
- nameAllocator.get(it)
- }, classField.type
- )
- }
- .build()
-
-private val ClassFieldInfo.parseMethodName: String
- get() = "parse${type.simpleName().toUpperCamelCase()}"
-
-private val xmlSerializerType = ClassName.get("org.xmlpull.v1", "XmlSerializer")
-
-private fun generateWriteMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("write")
- .apply {
- val nameAllocator = NameAllocator().apply {
- newName("outputStream")
- newName("serializer")
- }
- val parameterName = nameAllocator.newName(rootField.variableName)
- addJavadoc(
- """
- Write${'$'}W{@link $1T}${'$'}Wto${'$'}Wthe${'$'}WXML${'$'}Wfile.
-
- @param $2L the${'$'}W{@link ${'$'}1T}${'$'}Wto${'$'}Wpersist
- """.trimIndent(), rootField.type, parameterName
- )
- addAnnotation(nullableType)
- addModifiers(Modifier.PUBLIC)
- addParameter(
- ParameterSpec.builder(rootField.type, parameterName)
- .addAnnotation(nonNullType)
- .build()
- )
- addStatement("\$1T outputStream = null", FileOutputStream::class.java)
- addControlFlow("try") {
- addStatement("outputStream = mFile.startWrite()")
- addStatement(
- "final \$1T serializer =\$W\$2T.newSerializer()", xmlSerializerType, xmlType
- )
- addStatement(
- "serializer.setOutput(outputStream, \$1T.UTF_8.name())",
- StandardCharsets::class.java
- )
- addStatement(
- "serializer.setFeature(\$1S, true)",
- "http://xmlpull.org/v1/doc/features.html#indent-output"
- )
- addStatement("serializer.startDocument(null, true)")
- addStatement("serialize(serializer,\$W\$1L)", parameterName)
- addStatement("serializer.endDocument()")
- addStatement("mFile.finishWrite(outputStream)")
- nextControlFlow("catch (Exception e)")
- addStatement("e.printStackTrace()")
- addStatement("mFile.failWrite(outputStream)")
- }
- }
- .build()
-
-private fun generateSerializeMethod(rootField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder("serialize")
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .addParameter(
- ParameterSpec.builder(xmlSerializerType, "serializer")
- .addAnnotation(nonNullType)
- .build()
- )
- .apply {
- val nameAllocator = NameAllocator().apply { newName("serializer") }
- val parameterName = nameAllocator.newName(rootField.variableName)
- addParameter(
- ParameterSpec.builder(rootField.type, parameterName)
- .addAnnotation(nonNullType)
- .build()
- )
- addException(IOException::class.java)
- addStatement("serializer.startTag(null, \$1S)", rootField.tagName)
- addStatement("\$1L(serializer, \$2L)", rootField.serializeMethodName, parameterName)
- addStatement("serializer.endTag(null, \$1S)", rootField.tagName)
- }
- .build()
-
-private fun generateSerializeClassMethod(classField: ClassFieldInfo): MethodSpec =
- MethodSpec.methodBuilder(classField.serializeMethodName)
- .addModifiers(Modifier.PRIVATE, Modifier.STATIC)
- .addParameter(
- ParameterSpec.builder(xmlSerializerType, "serializer")
- .addAnnotation(nonNullType)
- .build()
- )
- .apply {
- val nameAllocator = NameAllocator().apply {
- newName("serializer")
- newName("i")
- }
- val parameterName = nameAllocator.newName(classField.serializeParameterName)
- addParameter(
- ParameterSpec.builder(classField.type, parameterName)
- .addAnnotation(nonNullType)
- .build()
- )
- addException(IOException::class.java)
- val (attributeFields, tagFields) = classField.fields
- .partition { it is PrimitiveFieldInfo || it is StringFieldInfo }
- for (field in attributeFields) {
- val variableName = "$parameterName.${field.name}"
- if (!field.isRequired) {
- beginControlFlow("if (\$1L != null)", variableName)
- }
- when (field) {
- is PrimitiveFieldInfo -> {
- if (field.isRequired && !field.type.isPrimitive) {
- addControlFlow("if (\$1L == null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Field \"${field.name}\" is null"
- )
- }
- }
- val stringVariableName =
- nameAllocator.newName("${field.variableName}String")
- addStatement(
- "final String \$1L =\$WString.valueOf(\$2L)", stringVariableName,
- variableName
- )
- addStatement(
- "serializer.attribute(null, \$1S, \$2L)", field.attributeName,
- stringVariableName
- )
- }
- is StringFieldInfo -> {
- if (field.isRequired) {
- addControlFlow("if (\$1L == null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Field \"${field.name}\" is null"
- )
- }
- }
- addStatement(
- "serializer.attribute(null, \$1S, \$2L)", field.attributeName,
- variableName
- )
- }
- else -> error(field)
- }
- if (!field.isRequired) {
- endControlFlow()
- }
- }
- for (field in tagFields) {
- val variableName = "$parameterName.${field.name}"
- if (field.isRequired) {
- addControlFlow("if (\$1L == null)", variableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S)",
- "Field \"${field.name}\" is null"
- )
- }
- }
- when (field) {
- is ClassFieldInfo -> {
- addStatement("serializer.startTag(null, \$1S)", field.tagName)
- addStatement(
- "\$1L(serializer, \$2L)", field.serializeMethodName, variableName
- )
- addStatement("serializer.endTag(null, \$1S)", field.tagName)
- }
- is ListFieldInfo -> {
- val sizeVariableName = nameAllocator.newName("${field.variableName}Size")
- addStatement(
- "final int \$1L =\$W\$2L.size()", sizeVariableName, variableName
- )
- addControlFlow("for (int i = 0;\$Wi < \$1L;\$Wi++)", sizeVariableName) {
- val elementNameAllocator = nameAllocator.clone()
- val elementVariableName = elementNameAllocator.newName(
- field.element.xmlName!!.toLowerCamelCase()
- )
- addStatement(
- "final \$1T \$2L =\$W\$3L.get(i)", field.element.type,
- elementVariableName, variableName
- )
- addControlFlow("if (\$1L == null)", elementVariableName) {
- addStatement(
- "throw new IllegalArgumentException(\$1S\$W+ i\$W+ \$2S)",
- "Field element \"${field.name}[", "]\" is null"
- )
- }
- addStatement("serializer.startTag(null, \$1S)", field.element.tagName)
- addStatement(
- "\$1L(serializer,\$W\$2L)", field.element.serializeMethodName,
- elementVariableName
- )
- addStatement("serializer.endTag(null, \$1S)", field.element.tagName)
- }
- }
- else -> error(field)
- }
- }
- }
- .build()
-
-private val ClassFieldInfo.serializeMethodName: String
- get() = "serialize${type.simpleName().toUpperCamelCase()}"
-
-private val ClassFieldInfo.serializeParameterName: String
- get() = type.simpleName().toLowerCamelCase()
-
-private val FieldInfo.variableName: String
- get() = name.toLowerCamelCase()
-
-private val FieldInfo.attributeName: String
- get() {
- check(this is PrimitiveFieldInfo || this is StringFieldInfo)
- return xmlNameOrName.toLowerCamelCase()
- }
-
-private val FieldInfo.tagName: String
- get() {
- check(this is ClassFieldInfo || this is ListFieldInfo)
- return xmlNameOrName.toLowerKebabCase()
- }
-
-private val FieldInfo.xmlNameOrName: String
- get() = xmlName ?: name
-
-private fun generateDeleteMethod(): MethodSpec =
- MethodSpec.methodBuilder("delete")
- .addJavadoc("Delete the XML file, if any.")
- .addModifiers(Modifier.PUBLIC)
- .addStatement("mFile.delete()")
- .build()
-
-private inline fun MethodSpec.Builder.addControlFlow(
- controlFlow: String,
- vararg args: Any,
- block: MethodSpec.Builder.() -> Unit
-): MethodSpec.Builder {
- beginControlFlow(controlFlow, *args)
- block()
- endControlFlow()
- return this
-}
diff --git a/tools/xmlpersistence/src/main/kotlin/Main.kt b/tools/xmlpersistence/src/main/kotlin/Main.kt
deleted file mode 100644
index e271f8cb9361..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/Main.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-import java.io.File
-import java.nio.file.Files
-
-fun main(args: Array<String>) {
- val showUsage = args.isEmpty() || when (args.singleOrNull()) {
- "-h", "--help" -> true
- else -> false
- }
- if (showUsage) {
- usage()
- return
- }
-
- val files = args.flatMap {
- File(it).walk().filter { it.isFile && it.extension == "java" }.map { it.toPath() }
- }
- val persistences = parse(files)
- for (persistence in persistences) {
- val file = generate(persistence)
- Files.newBufferedWriter(persistence.path).use {
- it.write(FILE_HEADER)
- file.writeTo(it)
- }
- }
-}
-
-private fun usage() {
- println("Usage: xmlpersistence <FILES>")
-}
diff --git a/tools/xmlpersistence/src/main/kotlin/Parser.kt b/tools/xmlpersistence/src/main/kotlin/Parser.kt
deleted file mode 100644
index 3ea12a9aa389..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/Parser.kt
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-import com.github.javaparser.JavaParser
-import com.github.javaparser.ParseProblemException
-import com.github.javaparser.ParseResult
-import com.github.javaparser.ParserConfiguration
-import com.github.javaparser.ast.Node
-import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
-import com.github.javaparser.ast.body.FieldDeclaration
-import com.github.javaparser.ast.body.TypeDeclaration
-import com.github.javaparser.ast.expr.AnnotationExpr
-import com.github.javaparser.ast.expr.Expression
-import com.github.javaparser.ast.expr.NormalAnnotationExpr
-import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr
-import com.github.javaparser.ast.expr.StringLiteralExpr
-import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration
-import com.github.javaparser.resolution.types.ResolvedPrimitiveType
-import com.github.javaparser.resolution.types.ResolvedReferenceType
-import com.github.javaparser.symbolsolver.JavaSymbolSolver
-import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration
-import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver
-import com.github.javaparser.symbolsolver.resolution.typesolvers.MemoryTypeSolver
-import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-import java.nio.file.Path
-import java.util.Optional
-
-class PersistenceInfo(
- val name: String,
- val root: ClassFieldInfo,
- val path: Path
-)
-
-sealed class FieldInfo {
- abstract val name: String
- abstract val xmlName: String?
- abstract val type: TypeName
- abstract val isRequired: Boolean
-}
-
-class PrimitiveFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val type: TypeName,
- override val isRequired: Boolean
-) : FieldInfo()
-
-class StringFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val isRequired: Boolean
-) : FieldInfo() {
- override val type: TypeName = ClassName.get(String::class.java)
-}
-
-class ClassFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val type: ClassName,
- override val isRequired: Boolean,
- val fields: List<FieldInfo>
-) : FieldInfo()
-
-class ListFieldInfo(
- override val name: String,
- override val xmlName: String?,
- override val type: ParameterizedTypeName,
- val element: ClassFieldInfo
-) : FieldInfo() {
- override val isRequired: Boolean = true
-}
-
-fun parse(files: List<Path>): List<PersistenceInfo> {
- val typeSolver = CombinedTypeSolver().apply { add(ReflectionTypeSolver()) }
- val javaParser = JavaParser(ParserConfiguration()
- .setSymbolResolver(JavaSymbolSolver(typeSolver)))
- val compilationUnits = files.map { javaParser.parse(it).getOrThrow() }
- val memoryTypeSolver = MemoryTypeSolver().apply {
- for (compilationUnit in compilationUnits) {
- for (typeDeclaration in compilationUnit.getNodesByClass<TypeDeclaration<*>>()) {
- val name = typeDeclaration.fullyQualifiedName.getOrNull() ?: continue
- addDeclaration(name, typeDeclaration.resolve())
- }
- }
- }
- typeSolver.add(memoryTypeSolver)
- return mutableListOf<PersistenceInfo>().apply {
- for (compilationUnit in compilationUnits) {
- val classDeclarations = compilationUnit
- .getNodesByClass<ClassOrInterfaceDeclaration>()
- .filter { !it.isInterface && (!it.isNestedType || it.isStatic) }
- this += classDeclarations.mapNotNull { parsePersistenceInfo(it) }
- }
- }
-}
-
-private fun parsePersistenceInfo(classDeclaration: ClassOrInterfaceDeclaration): PersistenceInfo? {
- val annotation = classDeclaration.getAnnotationByName("XmlPersistence").getOrNull()
- ?: return null
- val rootClassName = classDeclaration.nameAsString
- val name = annotation.getMemberValue("value")?.stringLiteralValue
- ?: "${rootClassName}Persistence"
- val rootXmlName = classDeclaration.getAnnotationByName("XmlName").getOrNull()
- ?.getMemberValue("value")?.stringLiteralValue
- val root = parseClassFieldInfo(
- rootXmlName ?: rootClassName, rootXmlName, true, classDeclaration
- )
- val path = classDeclaration.findCompilationUnit().get().storage.get().path
- .resolveSibling("$name.java")
- return PersistenceInfo(name, root, path)
-}
-
-private fun parseClassFieldInfo(
- name: String,
- xmlName: String?,
- isRequired: Boolean,
- classDeclaration: ClassOrInterfaceDeclaration
-): ClassFieldInfo {
- val fields = classDeclaration.fields.filterNot { it.isStatic }.map { parseFieldInfo(it) }
- val type = classDeclaration.resolve().typeName
- return ClassFieldInfo(name, xmlName, type, isRequired, fields)
-}
-
-private fun parseFieldInfo(field: FieldDeclaration): FieldInfo {
- require(field.isPublic && field.isFinal)
- val variable = field.variables.single()
- val name = variable.nameAsString
- val annotations = field.annotations + variable.type.annotations
- val annotation = annotations.getByName("XmlName")
- val xmlName = annotation?.getMemberValue("value")?.stringLiteralValue
- val isRequired = annotations.getByName("NonNull") != null
- return when (val type = variable.type.resolve()) {
- is ResolvedPrimitiveType -> {
- val primitiveType = type.typeName
- PrimitiveFieldInfo(name, xmlName, primitiveType, true)
- }
- is ResolvedReferenceType -> {
- when (type.qualifiedName) {
- Boolean::class.javaObjectType.name, Byte::class.javaObjectType.name,
- Short::class.javaObjectType.name, Char::class.javaObjectType.name,
- Integer::class.javaObjectType.name, Long::class.javaObjectType.name,
- Float::class.javaObjectType.name, Double::class.javaObjectType.name ->
- PrimitiveFieldInfo(name, xmlName, type.typeName, isRequired)
- String::class.java.name -> StringFieldInfo(name, xmlName, isRequired)
- List::class.java.name -> {
- requireNotNull(xmlName)
- val elementType = type.typeParametersValues().single()
- require(elementType is ResolvedReferenceType)
- val listType = ParameterizedTypeName.get(
- ClassName.get(List::class.java), elementType.typeName
- )
- val element = parseClassFieldInfo(
- "(element)", xmlName, true, elementType.classDeclaration
- )
- ListFieldInfo(name, xmlName, listType, element)
- }
- else -> parseClassFieldInfo(name, xmlName, isRequired, type.classDeclaration)
- }
- }
- else -> error(type)
- }
-}
-
-private fun <T> ParseResult<T>.getOrThrow(): T =
- if (isSuccessful) {
- result.get()
- } else {
- throw ParseProblemException(problems)
- }
-
-private inline fun <reified T : Node> Node.getNodesByClass(): List<T> =
- getNodesByClass(T::class.java)
-
-private fun <T : Node> Node.getNodesByClass(klass: Class<T>): List<T> = mutableListOf<T>().apply {
- if (klass.isInstance(this@getNodesByClass)) {
- this += klass.cast(this@getNodesByClass)
- }
- for (childNode in childNodes) {
- this += childNode.getNodesByClass(klass)
- }
-}
-
-private fun <T> Optional<T>.getOrNull(): T? = orElse(null)
-
-private fun List<AnnotationExpr>.getByName(name: String): AnnotationExpr? =
- find { it.name.identifier == name }
-
-private fun AnnotationExpr.getMemberValue(name: String): Expression? =
- when (this) {
- is NormalAnnotationExpr -> pairs.find { it.nameAsString == name }?.value
- is SingleMemberAnnotationExpr -> if (name == "value") memberValue else null
- else -> null
- }
-
-private val Expression.stringLiteralValue: String
- get() {
- require(this is StringLiteralExpr)
- return value
- }
-
-private val ResolvedReferenceType.classDeclaration: ClassOrInterfaceDeclaration
- get() {
- val resolvedClassDeclaration = typeDeclaration
- require(resolvedClassDeclaration is JavaParserClassDeclaration)
- return resolvedClassDeclaration.wrappedNode
- }
-
-private val ResolvedPrimitiveType.typeName: TypeName
- get() =
- when (this) {
- ResolvedPrimitiveType.BOOLEAN -> TypeName.BOOLEAN
- ResolvedPrimitiveType.BYTE -> TypeName.BYTE
- ResolvedPrimitiveType.SHORT -> TypeName.SHORT
- ResolvedPrimitiveType.CHAR -> TypeName.CHAR
- ResolvedPrimitiveType.INT -> TypeName.INT
- ResolvedPrimitiveType.LONG -> TypeName.LONG
- ResolvedPrimitiveType.FLOAT -> TypeName.FLOAT
- ResolvedPrimitiveType.DOUBLE -> TypeName.DOUBLE
- }
-
-// This doesn't support type parameters.
-private val ResolvedReferenceType.typeName: TypeName
- get() = typeDeclaration.typeName
-
-private val ResolvedReferenceTypeDeclaration.typeName: ClassName
- get() {
- val packageName = packageName
- val classNames = className.split(".")
- val topLevelClassName = classNames.first()
- val nestedClassNames = classNames.drop(1)
- return ClassName.get(packageName, topLevelClassName, *nestedClassNames.toTypedArray())
- }
diff --git a/tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt b/tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt
deleted file mode 100644
index b4bdbba7170b..000000000000
--- a/tools/xmlpersistence/src/main/kotlin/StringCaseExtensions.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * 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
- *
- * http://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.
- */
-
-import java.util.Locale
-
-private val camelHumpBoundary = Regex(
- "-"
- + "|_"
- + "|(?<=[0-9])(?=[^0-9])"
- + "|(?<=[A-Z])(?=[^A-Za-z]|[A-Z][a-z])"
- + "|(?<=[a-z])(?=[^a-z])"
-)
-
-private fun String.toCamelHumps(): List<String> = split(camelHumpBoundary)
-
-fun String.toUpperCamelCase(): String =
- toCamelHumps().joinToString("") { it.toLowerCase(Locale.ROOT).capitalize(Locale.ROOT) }
-
-fun String.toLowerCamelCase(): String = toUpperCamelCase().decapitalize(Locale.ROOT)
-
-fun String.toUpperKebabCase(): String =
- toCamelHumps().joinToString("-") { it.toUpperCase(Locale.ROOT) }
-
-fun String.toLowerKebabCase(): String =
- toCamelHumps().joinToString("-") { it.toLowerCase(Locale.ROOT) }
-
-fun String.toUpperSnakeCase(): String =
- toCamelHumps().joinToString("_") { it.toUpperCase(Locale.ROOT) }
-
-fun String.toLowerSnakeCase(): String =
- toCamelHumps().joinToString("_") { it.toLowerCase(Locale.ROOT) }