Remove contentaccess library
We are no longer planning to work on it. Remove it from
the repository.
Test: None
Change-Id: Ib65eadb29ca54044960a2a5a321368da7d13ca7f
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 3ac2ad9..0d21faa 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -38,7 +38,6 @@
val CAR_APP = LibraryGroup("androidx.car.app", LibraryVersions.CAR_APP)
val COLLECTION = LibraryGroup("androidx.collection", LibraryVersions.COLLECTION)
val CONCURRENT = LibraryGroup("androidx.concurrent", LibraryVersions.FUTURES)
- val CONTENTACCESS = LibraryGroup("androidx.contentaccess", LibraryVersions.CONTENTACCESS)
val CONTENTPAGER = LibraryGroup("androidx.contentpager", LibraryVersions.CONTENTPAGER)
val COORDINATORLAYOUT = LibraryGroup("androidx.coordinatorlayout", LibraryVersions.COORDINATORLAYOUT)
val CORE = LibraryGroup("androidx.core", null)
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 728965b..9d8c476 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -45,7 +45,6 @@
val COLLECTION = Version("1.2.0-alpha01")
val CONTENTPAGER = Version("1.1.0-alpha01")
val COMPOSE = Version("1.0.0-alpha08")
- val CONTENTACCESS = Version("1.0.0-alpha01")
val COORDINATORLAYOUT = Version("1.2.0-alpha01")
val CORE = Version("1.5.0-alpha05")
val CORE_ANIMATION = Version("1.0.0-alpha03")
diff --git a/contentaccess/OWNERS b/contentaccess/OWNERS
deleted file mode 100644
index 075ab06..0000000
--- a/contentaccess/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-sumir@google.com
diff --git a/contentaccess/contentaccess-annotations/build.gradle b/contentaccess/contentaccess-annotations/build.gradle
deleted file mode 100644
index c0d5144..0000000
--- a/contentaccess/contentaccess-annotations/build.gradle
+++ /dev/null
@@ -1,41 +0,0 @@
-
-/*
- * Copyright 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 androidx.build.LibraryGroups
-import androidx.build.LibraryVersions
-import androidx.build.Publish
-
-import static androidx.build.dependencies.DependenciesKt.*
-
-plugins {
- id("AndroidXPlugin")
- id("kotlin")
-}
-
-dependencies {
- implementation(KOTLIN_STDLIB)
-}
-
-androidx {
- name = "AndroidX ContentAccess Annotations"
- publish = Publish.SNAPSHOT_ONLY
- mavenVersion = LibraryVersions.CONTENTACCESS
- mavenGroup = LibraryGroups.CONTENTACCESS
- inceptionYear = "2020"
- description = "AndroidX ContentAccess Annotations"
- legacyDisableKotlinStrictApiMode = true
-}
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentAccessObject.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentAccessObject.kt
deleted file mode 100644
index 45eed8b..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentAccessObject.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess
-
-import kotlin.reflect.KClass
-
-/**
- * Represents an object that will be used for accessing and interacting with a content provider.
- *
- * @property contentEntity The content entity to associate the access object with.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.CLASS)
-annotation class ContentAccessObject(val contentEntity: KClass<*> = Void::class)
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentColumn.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentColumn.kt
deleted file mode 100644
index cb38082..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentColumn.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-/**
- * Represents a column in a content provider table.
- *
- * @property columnName The column name in the content provider table.
- *
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
-annotation class ContentColumn(val columnName: String)
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentDelete.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentDelete.kt
deleted file mode 100644
index 3c20129..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentDelete.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-import kotlin.reflect.KClass
-
-/**
- * Annotates a method that deletes one or more entries into a content provider.
- *
- * @property where The conditions for deleting a row (e.g column1 = :value).
- * This applies if the method is not being passed the entity, otherwise this field is ignored and
- * we deleted the passed in entity(s).
- *
- * @property uri The string representation of the uri to delete from, if empty then uses the
- * entity's uri, if existing.
- *
- * @property contentEntity The content entity to associate the method with.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FUNCTION)
-annotation class ContentDelete(
- val where: String = "",
- val uri: String = "",
- val contentEntity: KClass<*> = Void::class
-)
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentEntity.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentEntity.kt
deleted file mode 100644
index 46d67d6..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentEntity.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-/**
- * Represents a content provider table by mapping columns in a content provider to typed fields in
- * a class.
- *
- * @property uri The string representation of the uri of the table, if empty then all querying
- * methods must specify it instead.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.CLASS)
-annotation class ContentEntity(val uri: String = "")
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentInsert.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentInsert.kt
deleted file mode 100644
index 866ce23..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentInsert.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-/**
- * Annotates a method that inserts one or more entities into a content provider.
- *
- * @property uri The string representation of the uri to insert into, if empty then uses the
- * entity's uri, if existing.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FUNCTION)
-annotation class ContentInsert(val uri: String = "")
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentPrimaryKey.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentPrimaryKey.kt
deleted file mode 100644
index 2a1d753..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentPrimaryKey.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-/**
- * Represents a content provider table column that is the primary key (usually the ._ID column.)
- *
- * @property columnName The column name in the content provider table.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
-annotation class ContentPrimaryKey(val columnName: String)
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentQuery.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentQuery.kt
deleted file mode 100644
index e183748..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentQuery.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-import kotlin.reflect.KClass
-
-/**
- * Annotates a method that accesses a content provider.
- *
- * @property projection optional single field to query, otherwise queried fields are inferred from
- * return type. If this is specified and but the return type is a POJO, then that will result in
- * an error.
- *
- * @property selection The matching conditions, if empty applies to all (e.g "column1 = :value").
- *
- * @property orderBy The entity fields to order by, passed to the content provider in the
- * specified order. An entry in the array can either a single column name, or a single column
- * name followed by "asc" or "desc". (e.g order by = arrayOf("column1", "column2 asc")).
- *
- * @property uri The string representation of the uri to query, if empty then uses the entity's uri,
- * if existing.
- */
-
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FUNCTION)
-annotation class ContentQuery(
- val projection: Array<String> = arrayOf(),
- val selection: String = "",
- val orderBy: Array<String> = arrayOf(),
- val uri: String = "",
- val contentEntity: KClass<*> = Void::class
-)
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentUpdate.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentUpdate.kt
deleted file mode 100644
index 8939326..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/ContentUpdate.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-
-/*
- * Copyright 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.
- */
-package androidx.contentaccess
-
-import kotlin.reflect.KClass
-
-/**
- * Annotates a method that accesses a content provider.
- *
- * Both the updates and selection parameters are ignored if the method takes as input the entity
- * as that entity will be updated instead.
- *
- * @property where The matching conditions, if empty applies to all (e.g "column1 = :value").
- *
- * @property uri The string representation of the uri to query, if empty then uses the entity's uri,
- * if existing.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FUNCTION)
-annotation class ContentUpdate(
- val where: String = "",
- val uri: String = "",
- val contentEntity: KClass<*> = Void::class
-)
diff --git a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/IgnoreConstructor.kt b/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/IgnoreConstructor.kt
deleted file mode 100644
index ab74e86..0000000
--- a/contentaccess/contentaccess-annotations/src/main/kotlin/androidx/contentaccess/IgnoreConstructor.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess
-
-/**
- * Annotates a constructor so that it's not considered when analyzing an entity or a pojo.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.CONSTRUCTOR)
-annotation class IgnoreConstructor
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/build.gradle b/contentaccess/contentaccess-compiler/build.gradle
deleted file mode 100644
index e7941b8..0000000
--- a/contentaccess/contentaccess-compiler/build.gradle
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 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 androidx.build.LibraryGroups
-import androidx.build.LibraryType
-import androidx.build.LibraryVersions
-import androidx.build.Publish
-import androidx.build.SdkHelperKt
-import androidx.build.SupportConfig
-
-import static androidx.build.dependencies.DependenciesKt.*
-
-plugins {
- id("AndroidXPlugin")
- id("kotlin")
- id("kotlin-kapt")
-}
-
-dependencies {
- implementation(project(":contentaccess:contentaccess-annotations"))
-
- // TODO(obenabde): ensure all of those are used.
- implementation(KOTLIN_STDLIB)
- compileOnly(AUTO_SERVICE_ANNOTATIONS)
- kapt(AUTO_SERVICE_PROCESSOR)
- compileOnly(GRADLE_INCAP_HELPER)
- kapt(GRADLE_INCAP_HELPER_PROCESSOR)
- implementation(AUTO_COMMON)
- implementation(JSQLPARSER)
- implementation(KOTLINPOET)
- implementation(KOTLINPOET_METADATA)
- implementation(KOTLINPOET_METADATA_SPECS)
- implementation(KOTLINPOET_CLASSINSPECTOR_ELEMENTS)
- implementation("androidx.annotation:annotation:1.0.0")
-
- testImplementation(ASSERTJ)
- testImplementation(GOOGLE_COMPILE_TESTING)
- testImplementation(JUNIT)
- testImplementation(KOTLIN_COMPILE_TESTING)
- testImplementation(KOTLIN_COROUTINES_ANDROID)
- testImplementation fileTree(
- dir: "${SdkHelperKt.getSdkPath(project)}/platforms/$SupportConfig.COMPILE_SDK_VERSION/",
- include : "android.jar"
- )
-}
-
-androidx {
- name = "AndroidX ContentAccess Annotation Compiler"
- type = LibraryType.ANNOTATION_PROCESSOR
- publish = Publish.SNAPSHOT_ONLY
- mavenVersion = LibraryVersions.CONTENTACCESS
- mavenGroup = LibraryGroups.CONTENTACCESS
- inceptionYear = "2020"
- description = "AndroidX ContentAccess Annotation Compiler"
-}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
deleted file mode 100644
index 4cf63d3..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.compiler.processor.ContentAccessObjectProcessor
-import com.google.auto.common.BasicAnnotationProcessor
-import com.google.auto.common.MoreElements
-import com.google.common.collect.SetMultimap
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.SourceVersion
-import javax.lang.model.element.Element
-import javax.annotation.processing.Processor
-import com.google.auto.service.AutoService
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-
-@AutoService(Processor::class)
-@IncrementalAnnotationProcessor(ISOLATING)
-// TODO(obenabde): write incrementality tests.
-class ContentAccessProcessor : BasicAnnotationProcessor() {
-
- override fun initSteps(): MutableIterable<ProcessingStep>? {
- return mutableListOf(ContentAccessProcessStep(processingEnv))
- }
-
- override fun getSupportedSourceVersion(): SourceVersion {
- return SourceVersion.latest()
- }
-
- class ContentAccessProcessStep(val processingEnv: ProcessingEnvironment) : ProcessingStep {
- @KotlinPoetMetadataPreview
- override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>?):
- Set<Element> {
-
- elementsByAnnotation?.get(ContentAccessObject::class.java)?.forEach {
- ContentAccessObjectProcessor(MoreElements.asType(it), processingEnv).process()
- }
- return emptySet()
- }
-
- override fun annotations(): MutableSet<out Class<out Annotation>> {
- return mutableSetOf(ContentAccessObject::class.java)
- }
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
deleted file mode 100644
index a5e990b..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
+++ /dev/null
@@ -1,371 +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.
- */
-
-@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
-
-package androidx.contentaccess.ext
-
-import androidx.contentaccess.IgnoreConstructor
-import androidx.contentaccess.compiler.utils.JvmSignatureUtil
-import asTypeElement
-import com.google.auto.common.AnnotationMirrors
-import com.google.auto.common.MoreElements
-import com.google.auto.common.MoreTypes
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.KModifier
-import com.squareup.kotlinpoet.classinspector.elements.ElementsClassInspector
-import com.squareup.kotlinpoet.metadata.ImmutableKmFunction
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import com.squareup.kotlinpoet.metadata.specs.toTypeSpec
-import com.squareup.kotlinpoet.tag
-import java.lang.reflect.Proxy
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.AnnotationMirror
-import javax.lang.model.element.AnnotationValue
-import javax.lang.model.element.Element
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.Modifier
-import javax.lang.model.element.TypeElement
-import javax.lang.model.element.VariableElement
-import javax.lang.model.type.TypeKind
-import javax.lang.model.type.TypeMirror
-import javax.lang.model.type.WildcardType
-import javax.lang.model.util.ElementFilter
-import javax.lang.model.util.SimpleAnnotationValueVisitor6
-import javax.lang.model.util.SimpleTypeVisitor7
-import kotlin.reflect.KClass
-
-fun Element.hasAnnotation(klass: KClass<out Annotation>): Boolean {
- return MoreElements.isAnnotationPresent(this, klass.java)
-}
-
-fun TypeElement.getNonPrivateNonIgnoreConstructors(): List<ExecutableElement> {
- return ElementFilter.constructorsIn(this.enclosedElements).filter {
- !it.modifiers.contains(Modifier.PRIVATE) && !it.hasAnnotation(IgnoreConstructor::class)
- }
-}
-
-fun TypeElement.hasMoreThanOneNonPrivateNonIgnoredConstructor() =
- this.getNonPrivateNonIgnoreConstructors().size > 1
-
-fun TypeElement.isFilledThroughConstructor() = this.getNonPrivateNonIgnoreConstructors().size == 1
-
-fun TypeElement.isNotInstantiable():
- Boolean {
- // No constructors means we can't instantiate it to fill its public fields, user might have
- // made the default constructor private or simply ignored it.
- return this.getNonPrivateNonIgnoreConstructors().isEmpty()
- }
-
-/**
- * Gets either all the parameters of the single public constructor if they exist, otherwise returns
- * a list of all public fields, even if empty.
- */
-fun TypeElement.getAllConstructorParamsOrPublicFields():
- List<VariableElement> {
- val constructors = this.getNonPrivateNonIgnoreConstructors()
-
- if (constructors.size == 1) {
- val parameters = MoreElements.asExecutable(constructors.first()).parameters
- if (parameters.isNotEmpty()) {
- return parameters.map { it as VariableElement }
- }
- } else if (constructors.isEmpty()) {
- error("${this.qualifiedName} has no non private and non ignored constructors!")
- } else {
- error("${this.qualifiedName} has more than non private non ignored constructor")
- }
- // TODO(obenabde): explore ways to warn users if they're unknowingly doing something wrong
- // e.g if there is a possibility they think we are filling fields instead of constructors
- // or both etc...
- // This is a class with an empty or no public constructor, check public fields.
- return getAllNonPrivateFieldsIncludingSuperclassOnes()
- }
-
-fun TypeElement.getAllNonPrivateFieldsIncludingSuperclassOnes(): List<VariableElement> {
- var nonPrivateFields = ElementFilter.fieldsIn(this.enclosedElements)
- .filterNot { it.modifiers.contains(Modifier.PRIVATE) }
- if (superclass.kind != TypeKind.NONE) {
- nonPrivateFields = nonPrivateFields + MoreTypes.asTypeElement(superclass)
- .getAllNonPrivateFieldsIncludingSuperclassOnes()
- }
- return nonPrivateFields.map { it as VariableElement }
-}
-
-fun TypeElement.hasNonEmptyNonPrivateNonIgnoredConstructor(): Boolean {
- val constructors = ElementFilter.constructorsIn(this.enclosedElements).filter {
- !it.modifiers.contains(Modifier.PRIVATE) && !it.hasAnnotation(IgnoreConstructor::class)
- }
- if (constructors.isEmpty()) {
- return false
- }
- val parameters = MoreElements.asExecutable(constructors.first()).parameters
- return parameters.isNotEmpty()
-}
-
-fun TypeMirror.extendsBound(): TypeMirror? {
- return this.accept(
- object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
- override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
- return type.extendsBound ?: type.superBound
- }
- },
- null
- )
-}
-
-@KotlinPoetMetadataPreview
-fun ExecutableElement.isSuspendFunction(processingEnv: ProcessingEnvironment) =
- getKotlinFunspec(processingEnv).modifiers.contains(KModifier.SUSPEND)
-
-@KotlinPoetMetadataPreview
-fun ExecutableElement.getSuspendFunctionReturnType():
- TypeMirror {
- val typeParam = MoreTypes.asDeclared(parameters.last().asType()).typeArguments.first()
- return typeParam.extendsBound() ?: typeParam
- }
-
-@KotlinPoetMetadataPreview
-fun ExecutableElement.getKotlinFunspec(processingEnv: ProcessingEnvironment):
- FunSpec {
- val classInspector = ElementsClassInspector.create(
- processingEnv.elementUtils,
- processingEnv
- .typeUtils
- )
- val enclosingClass = this.enclosingElement as TypeElement
-
- val kotlinApi = enclosingClass.toTypeSpec(classInspector)
- val jvmSignature = JvmSignatureUtil.getMethodDescriptor(this)
- val funSpec = kotlinApi.funSpecs.find {
- it.tag<ImmutableKmFunction>()?.signature?.asString() == jvmSignature
- } ?: error("No matching funSpec found for $jvmSignature.")
- return funSpec
- }
-
-fun TypeElement.getAllMethodsIncludingSupers(): Set<ExecutableElement> {
- val myMethods = ElementFilter.methodsIn(this.enclosedElements).toSet()
- val interfaceMethods = interfaces.flatMap {
- it.asTypeElement().getAllMethodsIncludingSupers()
- }
- return if (superclass.kind != TypeKind.NONE) {
- myMethods + interfaceMethods + superclass.asTypeElement().getAllMethodsIncludingSupers()
- } else {
- myMethods + interfaceMethods
- }
-}
-
-interface ClassGetter {
- fun getAsTypeMirror(methodName: String): TypeMirror?
- fun getAsTypeMirrorList(methodName: String): List<TypeMirror>
- fun <T : Annotation> getAsAnnotationBox(methodName: String): AnnotationBox<T>
- fun <T : Annotation> getAsAnnotationBoxArray(methodName: String): Array<AnnotationBox<T>>
-}
-
-/**
- * Class that helps to read values from annotations. Simple types as string, int, lists can
- * be read from [value]. If you need to read classes or another annotations from annotation use
- * [getAsTypeMirror], [getAsAnnotationBox] and [getAsAnnotationBoxArray] correspondingly.
- */
-class AnnotationBox<T : Annotation>(private val obj: Any) : ClassGetter by (obj as ClassGetter) {
- @Suppress("UNCHECKED_CAST")
- val value: T = obj as T
-}
-
-private fun <T : Annotation> AnnotationMirror.box(cl: Class<T>): AnnotationBox<T> {
- if (!cl.isAnnotation) {
- throw IllegalArgumentException("$cl is not annotation")
- }
- val map = cl.declaredMethods.associate { method ->
- val value = AnnotationMirrors.getAnnotationValue(this, method.name)
- val returnType = method.returnType
- val defaultValue = method.defaultValue
- val result: Any? = when {
- returnType == Boolean::class.java -> value.getAsBoolean(defaultValue as Boolean)
- returnType == String::class.java -> value.getAsString(defaultValue as String?)
- returnType == Array<String>::class.java -> value.getAsStringList().toTypedArray()
- returnType == emptyArray<Class<*>>()::class.java -> value.toListOfClassTypes()
- returnType == IntArray::class.java -> value.getAsIntList().toIntArray()
- returnType == Class::class.java -> {
- try {
- value.toClassType()
- } catch (notPresent: TypeNotPresentException) {
- null
- }
- }
- returnType == Int::class.java -> value.getAsInt(defaultValue as Int?)
- returnType.isAnnotation -> {
- @Suppress("UNCHECKED_CAST")
- AnnotationClassVisitor(returnType as Class<out Annotation>).visit(value)
- }
- returnType.isArray && returnType.componentType.isAnnotation -> {
- @Suppress("UNCHECKED_CAST")
- ListVisitor(returnType.componentType as Class<out Annotation>).visit(value)
- }
- returnType.isEnum -> {
- @Suppress("UNCHECKED_CAST")
- value.getAsEnum(returnType as Class<out Enum<*>>)
- }
- else -> throw UnsupportedOperationException("$returnType isn't supported")
- }
- method.name to result
- }
- return AnnotationBox(
- Proxy.newProxyInstance(
- ClassGetter::class.java.classLoader,
- arrayOf(cl, ClassGetter::class.java)
- ) { _, method, args ->
- when (method.name) {
- ClassGetter::getAsTypeMirror.name -> map[args[0]]
- ClassGetter::getAsTypeMirrorList.name -> map[args[0]]
- "getAsAnnotationBox" -> map[args[0]]
- "getAsAnnotationBoxArray" -> map[args[0]]
- else -> map[method.name]
- }
- }
- )
-}
-
-fun <T : Annotation> Element.toAnnotationBox(cl: KClass<T>) =
- MoreElements.getAnnotationMirror(this, cl.java).orNull()?.box(cl.java)
-
-@Suppress("DEPRECATION")
-private class ListVisitor<T : Annotation>(private val annotationClass: Class<T>) :
- SimpleAnnotationValueVisitor6<Array<AnnotationBox<T>>, Void?>() {
- override fun visitArray(
- values: MutableList<out AnnotationValue>?,
- void: Void?
- ): Array<AnnotationBox<T>> {
- val visitor = AnnotationClassVisitor(annotationClass)
- return values?.mapNotNull { visitor.visit(it) }?.toTypedArray() ?: emptyArray()
- }
-}
-
-@Suppress("DEPRECATION")
-private class AnnotationClassVisitor<T : Annotation>(private val annotationClass: Class<T>) :
- SimpleAnnotationValueVisitor6<AnnotationBox<T>?, Void?>() {
- override fun visitAnnotation(a: AnnotationMirror?, v: Void?) = a?.box(annotationClass)
-}
-
-// code below taken from dagger2
-// compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
-@Suppress("DEPRECATION")
-private val TO_LIST_OF_TYPES = object :
- SimpleAnnotationValueVisitor6<List<TypeMirror>, Void?>() {
- override fun visitArray(values: MutableList<out AnnotationValue>?, p: Void?): List<TypeMirror> {
- return values?.mapNotNull {
- val tmp = TO_TYPE.visit(it)
- tmp
- } ?: emptyList()
- }
-
- override fun defaultAction(o: Any?, p: Void?): List<TypeMirror>? {
- return emptyList()
- }
-}
-
-@Suppress("DEPRECATION")
-private val TO_TYPE = object : SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
-
- override fun visitType(t: TypeMirror, p: Void?): TypeMirror {
- return t
- }
-
- override fun defaultAction(o: Any?, p: Void?): TypeMirror {
- throw TypeNotPresentException(o!!.toString(), null)
- }
-}
-
-private fun AnnotationValue.toListOfClassTypes(): List<TypeMirror> {
- return TO_LIST_OF_TYPES.visit(this)
-}
-
-private fun AnnotationValue.toClassType(): TypeMirror? {
- return TO_TYPE.visit(this)
-}
-
-@Suppress("DEPRECATION")
-private val ANNOTATION_VALUE_TO_INT_VISITOR = object : SimpleAnnotationValueVisitor6<Int?, Void>() {
- override fun visitInt(i: Int, p: Void?): Int? {
- return i
- }
-}
-
-@Suppress("DEPRECATION")
-private val ANNOTATION_VALUE_TO_BOOLEAN_VISITOR = object :
- SimpleAnnotationValueVisitor6<Boolean?, Void>() {
- override fun visitBoolean(b: Boolean, p: Void?): Boolean? {
- return b
- }
-}
-
-@Suppress("DEPRECATION")
-private val ANNOTATION_VALUE_TO_STRING_VISITOR = object :
- SimpleAnnotationValueVisitor6<String?, Void>() {
- override fun visitString(s: String?, p: Void?): String? {
- return s
- }
-}
-
-@Suppress("DEPRECATION")
-private val ANNOTATION_VALUE_STRING_ARR_VISITOR = object :
- SimpleAnnotationValueVisitor6<List<String>, Void>() {
- override fun visitArray(vals: MutableList<out AnnotationValue>?, p: Void?): List<String> {
- return vals?.mapNotNull {
- ANNOTATION_VALUE_TO_STRING_VISITOR.visit(it)
- } ?: emptyList()
- }
-}
-
-@Suppress("DEPRECATION")
-private val ANNOTATION_VALUE_INT_ARR_VISITOR = object :
- SimpleAnnotationValueVisitor6<List<Int>, Void>() {
- override fun visitArray(vals: MutableList<out AnnotationValue>?, p: Void?): List<Int> {
- return vals?.mapNotNull {
- ANNOTATION_VALUE_TO_INT_VISITOR.visit(it)
- } ?: emptyList()
- }
-}
-
-private fun AnnotationValue.getAsInt(def: Int? = null): Int? {
- return ANNOTATION_VALUE_TO_INT_VISITOR.visit(this) ?: def
-}
-
-private fun AnnotationValue.getAsIntList(): List<Int> {
- return ANNOTATION_VALUE_INT_ARR_VISITOR.visit(this)
-}
-
-private fun AnnotationValue.getAsString(def: String? = null): String? {
- return ANNOTATION_VALUE_TO_STRING_VISITOR.visit(this) ?: def
-}
-
-private fun AnnotationValue.getAsBoolean(def: Boolean): Boolean {
- return ANNOTATION_VALUE_TO_BOOLEAN_VISITOR.visit(this) ?: def
-}
-
-private fun AnnotationValue.getAsStringList(): List<String> {
- return ANNOTATION_VALUE_STRING_ARR_VISITOR.visit(this)
-}
-
-@Suppress("UNCHECKED_CAST", "DEPRECATION")
-private fun <T : Enum<*>> AnnotationValue.getAsEnum(enumClass: Class<T>): T {
- return object : SimpleAnnotationValueVisitor6<T, Void>() {
- override fun visitEnumConstant(value: VariableElement?, p: Void?): T {
- return enumClass.getDeclaredMethod("valueOf", String::class.java)
- .invoke(null, value!!.simpleName.toString()) as T
- }
- }.visit(this)
-}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
deleted file mode 100644
index ffb4433..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2016 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.google.auto.common.MoreTypes
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.asTypeName
-import java.lang.RuntimeException
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.TypeElement
-import javax.lang.model.element.VariableElement
-import javax.lang.model.type.TypeKind
-import javax.lang.model.type.TypeMirror
-import javax.lang.model.util.ElementFilter
-
-fun TypeMirror.asTypeElement(): TypeElement = MoreTypes.asTypeElement(this)
-
-fun TypeMirror.isList(): Boolean {
- return MoreTypes.isTypeOf(java.util.List::class.java, this)
-}
-
-fun TypeMirror.isSet(): Boolean {
- // Is of type kotlin.collections.Set?
- return MoreTypes.isTypeOf(Set::class.java, this)
-}
-
-fun TypeMirror.isSupportedCollection(): Boolean {
- return isList() || isSet()
-}
-
-fun TypeMirror.isOptional(): Boolean {
- return MoreTypes.isTypeOf(java.util.Optional::class.java, this)
-}
-
-fun TypeMirror.isFlowable(): Boolean {
- return this.asTypeName() == ClassName("io.reactivex", "Flowable")
-}
-
-fun TypeMirror.isSupportedGenericType(): Boolean {
- return isSupportedCollection() || isOptional() || isFlowable()
-}
-
-fun TypeMirror.extractImmediateTypeParameter():
- TypeMirror {
- val asDeclared = MoreTypes.asDeclared(this)
- return asDeclared.typeArguments.first()
- }
-
-fun TypeMirror.extractIntendedReturnType(): TypeMirror {
- if (!this.isSupportedGenericType()) {
- return this
- }
- val firstWrappedType = extractImmediateTypeParameter()
- if (isFlowable() && (
- firstWrappedType.isSupportedCollection() ||
- firstWrappedType.isOptional()
- )
- ) {
- return firstWrappedType.extractImmediateTypeParameter()
- }
- return firstWrappedType
-}
-
-fun TypeMirror.toKotlinClassName(): ClassName {
- if (isInt()) {
- return ClassName("kotlin", "Int")
- } else if (isLong()) {
- return ClassName("kotlin", "Long")
- } else if (isDouble()) {
- return ClassName("kotlin", "Double")
- } else if (isShort()) {
- return ClassName("kotlin", "Short")
- } else if (isFloat()) {
- return ClassName("kotlin", "Short")
- }
- return ClassName.bestGuess(this.toString())
-}
-
-fun TypeMirror.boxIfPrimitive(processingEnv: ProcessingEnvironment): TypeMirror {
- val types = processingEnv.typeUtils
- if (isInt()) {
- return types.boxedClass(types.getPrimitiveType(TypeKind.INT)).asType()
- } else if (isLong()) {
- return types.boxedClass(types.getPrimitiveType(TypeKind.LONG)).asType()
- } else if (isDouble()) {
- return types.boxedClass(types.getPrimitiveType(TypeKind.DOUBLE)).asType()
- } else if (isShort()) {
- return types.boxedClass(types.getPrimitiveType(TypeKind.SHORT)).asType()
- } else if (isFloat()) {
- return types.boxedClass(types.getPrimitiveType(TypeKind.FLOAT)).asType()
- }
- return this
-}
-
-fun TypeMirror.isVoidObject() =
- MoreTypes.isType(this) && MoreTypes.isTypeOf(Void::class.java, this)
-
-fun TypeMirror.isPrimitiveInt() = kind == TypeKind.INT
-
-fun TypeMirror.isBoxedInt() =
- MoreTypes.isType(this) && MoreTypes.isTypeOf(java.lang.Integer::class.java, this)
-
-fun TypeMirror.isInt() = isPrimitiveInt() || isBoxedInt()
-
-fun TypeMirror.isPrimitiveLong() = kind == TypeKind.LONG
-
-fun TypeMirror.isBoxedLong() =
- MoreTypes.isType(this) && MoreTypes.isTypeOf(java.lang.Long::class.java, this)
-
-fun TypeMirror.isLong() = isPrimitiveLong() || isBoxedLong()
-
-fun TypeMirror.isPrimitiveFloat() = kind == TypeKind.FLOAT
-
-fun TypeMirror.isBoxedFloat() =
- MoreTypes.isType(this) && MoreTypes.isTypeOf(java.lang.Float::class.java, this)
-
-fun TypeMirror.isFloat() = isPrimitiveFloat() || isBoxedFloat()
-
-fun TypeMirror.isPrimitiveShort() = kind == TypeKind.SHORT
-
-fun TypeMirror.isBoxedShort() =
- MoreTypes.isType(this) && MoreTypes.isTypeOf(java.lang.Short::class.java, this)
-
-fun TypeMirror.isShort() = isPrimitiveShort() || isBoxedShort()
-
-fun TypeMirror.isPrimitiveDouble() = kind == TypeKind.DOUBLE
-
-fun TypeMirror.isBoxedDouble() =
- MoreTypes.isType(this) && MoreTypes.isTypeOf(java.lang.Double::class.java, this)
-
-fun TypeMirror.isDouble() = isPrimitiveDouble() || isBoxedDouble()
-
-fun TypeMirror.isString() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
- String::class
- .java,
- this
-)
-
-fun TypeMirror.isPrimitiveBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
- ByteArray::class
- .java,
- this
-)
-
-fun TypeMirror.isBoxedBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
- Array<Byte>::class
- .java,
- this
-)
-
-fun TypeMirror.isBlob() = isPrimitiveBlob() || isBoxedBlob()
-
-fun TypeMirror.isSupportedColumnType() = isBlob() || isInt() || isString() || isFloat() ||
- isDouble() || isShort() || isLong()
-
-fun TypeMirror.isPrimitive(): Boolean = isPrimitiveLong() || isPrimitiveShort() ||
- isPrimitiveBlob() || isPrimitiveDouble() || isPrimitiveFloat() || isPrimitiveInt()
-
-fun TypeMirror.getCursorMethod(): String {
- if (isShort()) {
- return "getShort"
- } else if (isLong()) {
- return "getLong"
- } else if (isInt()) {
- return "getInt"
- } else if (isString()) {
- return "getString"
- } else if (isFloat()) {
- return "getFloat"
- } else if (isBlob()) {
- return "getBlob"
- } else if (isDouble()) {
- return "getDouble"
- }
- // This should honestly only ever be called after checking isSupportedColumnType() but you
- // never know.
- throw RuntimeException("No cursor method for the given return type.")
-}
-
-fun TypeMirror.getOrderedConstructorParams(): List<VariableElement> {
- val constructors = ElementFilter.constructorsIn(this.asTypeElement().enclosedElements)
- if (constructors.size > 1) {
- // TODO(obenabde): error, should have only one constructor otherwise it becomes
- // ambiguous
- }
- return constructors.first().parameters
-}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
deleted file mode 100644
index 9002873..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.ContentDelete
-import androidx.contentaccess.ContentInsert
-import androidx.contentaccess.ContentQuery
-import androidx.contentaccess.ContentUpdate
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentAccessObjectVO
-import androidx.contentaccess.compiler.writer.ContentAccessObjectWriter
-import androidx.contentaccess.ext.getAllMethodsIncludingSupers
-import androidx.contentaccess.ext.hasAnnotation
-import javax.annotation.processing.ProcessingEnvironment
-import androidx.contentaccess.ext.toAnnotationBox
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import isVoidObject
-import javax.lang.model.element.ElementKind
-import javax.lang.model.element.TypeElement
-
-class ContentAccessObjectProcessor(
- val element: TypeElement,
- private val processingEnv:
- ProcessingEnvironment
-) {
- @KotlinPoetMetadataPreview
- fun process() {
- val errorReporter = ErrorReporter(processingEnv.messager)
- if (element.kind != ElementKind.INTERFACE) {
- errorReporter.reportError(
- "Only interfaces should be annotated with " +
- "@ContentAccessObject, '${element.qualifiedName}' is not interface.",
- element
- )
- } else {
- if (element.getAllMethodsIncludingSupers().isEmpty()) {
- errorReporter.reportError(
- "Interface '${element.qualifiedName}' annotated with " +
- "@ContentAccessObject doesn't delcare any functions. Interfaces annotated" +
- " with @ContentAccessObject should declare at least one function.",
- element
- )
- }
- }
- val contentEntityType = element.toAnnotationBox(ContentAccessObject::class)!!
- .getAsTypeMirror("contentEntity")!!
- val entity = if (contentEntityType.isVoidObject()) {
- null
- } else {
- ContentEntityProcessor(contentEntityType, processingEnv, errorReporter).processEntity()
- }
- if (errorReporter.errorReported) {
- // Any of the above errors should handicap progress, stop early.
- return
- }
- val queryMethods = element.getAllMethodsIncludingSupers()
- .filter { it.hasAnnotation(ContentQuery::class) }
- .map {
- ContentQueryProcessor(
- contentEntity = entity,
- method = it,
- contentQueryAnnotation = it.getAnnotation(ContentQuery::class.java),
- processingEnv = processingEnv,
- errorReporter = errorReporter
- ).process()
- }
-
- val updateMethods = element.getAllMethodsIncludingSupers()
- .filter { it.hasAnnotation(ContentUpdate::class) }
- .map {
- ContentUpdateProcessor(
- contentEntity = entity,
- method = it,
- contentUpdateAnnotation = it.getAnnotation(ContentUpdate::class.java),
- processingEnv = processingEnv,
- errorReporter = errorReporter
- ).process()
- }
-
- val deleteMethods = element.getAllMethodsIncludingSupers()
- .filter { it.hasAnnotation(ContentDelete::class) }
- .map {
- ContentDeleteProcessor(
- contentEntity = entity,
- method = it,
- contentDeleteAnnotation = it.getAnnotation(ContentDelete::class.java),
- processingEnv = processingEnv,
- errorReporter = errorReporter
- ).process()
- }
-
- val insertMethods = element.getAllMethodsIncludingSupers()
- .filter { it.hasAnnotation(ContentInsert::class) }
- .map {
- ContentInsertProcessor(
- method = it,
- contentInsertAnnotation = it.getAnnotation(ContentInsert::class.java),
- processingEnv = processingEnv,
- errorReporter = errorReporter
- ).process()
- }
-
- // Return if there was an error.
- if (errorReporter.errorReported) {
- return
- }
- ContentAccessObjectWriter(
- ContentAccessObjectVO(
- contentEntity = entity,
- interfaceName = element.qualifiedName.toString(),
- interfaceElement = element,
- packageName = processingEnv.elementUtils.getPackageOf(element).toString(),
- interfaceType = element.asType(),
- queries = queryMethods.mapNotNull { it },
- updates = updateMethods.mapNotNull { it },
- deletes = deleteMethods.filterNotNull(),
- inserts = insertMethods.filterNotNull()
- ),
- processingEnv
- ).generateFile()
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessor.kt
deleted file mode 100644
index 71796a5..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessor.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.ContentDelete
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentDeleteVO
-import androidx.contentaccess.compiler.vo.ContentEntityVO
-import androidx.contentaccess.ext.getSuspendFunctionReturnType
-import androidx.contentaccess.ext.isSuspendFunction
-import androidx.contentaccess.ext.toAnnotationBox
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import isInt
-import isVoidObject
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.type.TypeMirror
-
-class ContentDeleteProcessor(
- private val contentEntity: ContentEntityVO?,
- private val method: ExecutableElement,
- private val contentDeleteAnnotation: ContentDelete,
- private val processingEnv: ProcessingEnvironment,
- private val errorReporter: ErrorReporter
-) {
- @KotlinPoetMetadataPreview
- fun process(): ContentDeleteVO? {
- val isSuspendFunction = method.isSuspendFunction(processingEnv)
- val returnType = if (isSuspendFunction) {
- method.getSuspendFunctionReturnType()
- } else {
- method.returnType
- }
- if (!returnType.isInt()) {
- errorReporter.reportError(contentDeleteAnnotatedMethodNotReturningAnInteger(), method)
- }
- val potentialContentEntity = method.toAnnotationBox(ContentDelete::class)!!
- .getAsTypeMirror("contentEntity")!!
- val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
- ContentEntityProcessor(
- potentialContentEntity,
- processingEnv, errorReporter
- ).processEntity()
- } else {
- contentEntity
- }
- if (resolvedContentEntity == null) {
- errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
- return null
- }
- val toBeUsedUri = determineToBeUsedUri(
- resolvedContentEntity = resolvedContentEntity,
- uriInAnnotation = contentDeleteAnnotation.uri,
- errorReporter = errorReporter,
- method = method
- )
- if (toBeUsedUri.isEmpty()) {
- errorReporter.reportError(missingUriOnMethod(), method)
- }
-
- // TODO(yrezgui): Prefer mapOf instead of HashMap
- val paramsNamesAndTypes = HashMap<String, TypeMirror>()
- for (param in method.parameters) {
- paramsNamesAndTypes[param.simpleName.toString()] = param.asType()
- }
-
- val selectionVO = if (contentDeleteAnnotation.where.isEmpty()) {
- null
- } else {
- SelectionProcessor(
- method = method,
- selection = contentDeleteAnnotation.where,
- paramsNamesAndTypes = paramsNamesAndTypes,
- errorReporter = errorReporter,
- resolvedContentEntity = resolvedContentEntity
- ).process()
- }
-
- return ContentDeleteVO(
- name = method.simpleName.toString(),
- where = selectionVO,
- uri = toBeUsedUri,
- method = method,
- isSuspend = isSuspendFunction
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
deleted file mode 100644
index d317ce7..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.annotation.RequiresApi
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentEntity
-import androidx.contentaccess.ContentPrimaryKey
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentColumnVO
-import androidx.contentaccess.compiler.vo.ContentEntityVO
-import androidx.contentaccess.ext.getAllConstructorParamsOrPublicFields
-import androidx.contentaccess.ext.hasAnnotation
-import androidx.contentaccess.ext.hasMoreThanOneNonPrivateNonIgnoredConstructor
-import androidx.contentaccess.ext.isNotInstantiable
-import asTypeElement
-import com.google.auto.common.MoreTypes
-import isPrimitive
-import isPrimitiveBlob
-import isSupportedColumnType
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.VariableElement
-import javax.lang.model.type.TypeMirror
-
-class ContentEntityProcessor(
- private val contentEntity: TypeMirror,
- private val processingEnv: ProcessingEnvironment,
- private val errorReporter: ErrorReporter
-) {
-
- fun processEntity(): ContentEntityVO? {
- val entity = contentEntity.asTypeElement()
- if (entity.hasMoreThanOneNonPrivateNonIgnoredConstructor()) {
- errorReporter.reportError(
- entityWithMultipleConstructors(contentEntity.toString()),
- entity
- )
- return null
- } else if (entity.isNotInstantiable()) {
- errorReporter.reportError(nonInstantiableEntity(contentEntity.toString()), entity)
- return null
- }
- val columns = entity.getAllConstructorParamsOrPublicFields()
- columns.forEach {
- if (fieldIsNullable(it) && (
- it.asType().isPrimitive() &&
- !it.asType().isPrimitiveBlob()
- )
- ) {
- errorReporter.reportError(
- entityWithNullablePrimitiveType(
- it.simpleName.toString(),
- contentEntity.toString()
- ),
- it
- )
- }
- }
- val contentColumns = HashMap<String, ContentColumnVO>()
- val contentPrimaryKey = ArrayList<ContentColumnVO>()
- columns.forEach { column ->
- if (column.hasAnnotation(ContentColumn::class) &&
- column.hasAnnotation(ContentPrimaryKey::class)
- ) {
- errorReporter.reportError(
- entityFieldWithBothAnnotations(
- column.simpleName
- .toString(),
- entity.qualifiedName.toString()
- ),
- entity
- )
- } else if (column.hasAnnotation(ContentColumn::class)) {
- if (validateColumnType(column, errorReporter)) {
- val vo = ContentColumnVO(
- column.simpleName.toString(), column.asType(),
- column.getAnnotation(ContentColumn::class.java).columnName,
- fieldIsNullable(column),
- fieldRequiresApi(column)
- )
- contentColumns.put(vo.columnName, vo)
- }
- } else if (column.hasAnnotation(ContentPrimaryKey::class)) {
- if (validateColumnType(column, errorReporter)) {
- val vo = ContentColumnVO(
- column.simpleName.toString(), column.asType(),
- column
- .getAnnotation(ContentPrimaryKey::class.java).columnName,
- fieldIsNullable(column),
- fieldRequiresApi(column)
- )
- contentColumns.put(vo.columnName, vo)
- contentPrimaryKey.add(vo)
- }
- } else {
- errorReporter.reportError(
- missingAnnotationOnEntityFieldErrorMessage(
- column.simpleName.toString(),
- entity.qualifiedName.toString()
- ),
- entity
- )
- }
- }
- if (contentPrimaryKey.isEmpty()) {
- if (columns.isEmpty()) {
- errorReporter.reportError(
- missingFieldsInContentEntityErrorMessage(
- entity
- .qualifiedName.toString()
- ),
- entity
- )
- } else {
- errorReporter.reportError(
- missingEntityPrimaryKeyErrorMessage(
- entity
- .qualifiedName.toString()
- ),
- entity
- )
- }
- }
- if (contentPrimaryKey.size > 1) {
- errorReporter.reportError(
- entityWithMultiplePrimaryKeys(entity.qualifiedName.toString()),
- entity
- )
- }
- if (errorReporter.errorReported) {
- return null
- }
- return ContentEntityVO(
- entity.getAnnotation(ContentEntity::class.java).uri,
- MoreTypes
- .asDeclared(entity.asType()),
- contentColumns, contentPrimaryKey.first()
- )
- }
-
- fun validateColumnType(column: VariableElement, errorReporter: ErrorReporter): Boolean {
- if (!column.asType().isSupportedColumnType()) {
- errorReporter.reportError(
- unsupportedColumnType(
- column.simpleName.toString(),
- contentEntity.toString(),
- column.asType().toString()
- ),
- column
- )
- return false
- }
- return true
- }
-}
-
-fun fieldIsNullable(field: VariableElement): Boolean {
- return field.annotationMirrors.any { NULLABLE_ANNOTATIONS.contains(it.toString()) }
-}
-
-fun fieldRequiresApi(field: VariableElement): Int? {
- if (field.hasAnnotation(RequiresApi::class)) {
- return field.getAnnotation(RequiresApi::class.java).value
- }
- return null
-}
-
-val NULLABLE_ANNOTATIONS = listOf(
- "@org.jetbrains.annotations.Nullable",
- "@androidx.annotation.Nullable"
-)
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
deleted file mode 100644
index 955e06b..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.ContentEntity
-import androidx.contentaccess.ContentInsert
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentInsertVO
-import androidx.contentaccess.ext.getSuspendFunctionReturnType
-import androidx.contentaccess.ext.hasAnnotation
-import androidx.contentaccess.ext.isSuspendFunction
-import asTypeElement
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.VariableElement
-
-class ContentInsertProcessor(
- private val method: ExecutableElement,
- private val contentInsertAnnotation: ContentInsert,
- private val processingEnv: ProcessingEnvironment,
- private val errorReporter: ErrorReporter
-) {
- @KotlinPoetMetadataPreview
- fun process(): ContentInsertVO? {
- val isSuspendFunction = method.isSuspendFunction(processingEnv)
- val returnType = if (isSuspendFunction) {
- method.getSuspendFunctionReturnType()
- } else {
- method.returnType
- }
- val entitiesInParams = mutableListOf<VariableElement>()
- for (param in method.parameters) {
- if (param.asType().asTypeElement().hasAnnotation(ContentEntity::class)) {
- entitiesInParams.add(param)
- }
- }
- if (entitiesInParams.size > 1) {
- errorReporter.reportError(
- insertMethodHasMoreThanOneEntity(), method
- )
- return null
- } else if (entitiesInParams.isEmpty()) {
- errorReporter.reportError(
- insertMethodHasNoEntityInParameters(), method
- )
- return null
- }
-
- val entity = entitiesInParams.first()
- val entityParameterName = entity.simpleName.toString()
-
- val contentEntity = ContentEntityProcessor(
- entity.asType(),
- processingEnv,
- errorReporter
- ).processEntity()
- if (contentEntity == null) {
- return null
- }
- val toBeUsedUri = determineToBeUsedUri(
- resolvedContentEntity = contentEntity,
- uriInAnnotation = contentInsertAnnotation.uri,
- errorReporter = errorReporter,
- method = method
- )
- if (toBeUsedUri.isEmpty()) {
- errorReporter.reportError(missingUriOnMethod(), method)
- }
-
- if (!returnType.toString().equals("android.net.Uri")) {
- errorReporter.reportError(contentInsertAnnotatedMethodNotReturningAUri(), method)
- }
-
- return ContentInsertVO(
- name = method.simpleName.toString(),
- uri = toBeUsedUri,
- method = method,
- isSuspend = isSuspendFunction,
- parameterName = entityParameterName,
- columns = contentEntity.columns.values.toList()
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
deleted file mode 100644
index 9c69ff6..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.ContentQuery
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentEntityVO
-import androidx.contentaccess.compiler.vo.ContentQueryVO
-import androidx.contentaccess.compiler.vo.PojoVO
-import androidx.contentaccess.ext.getSuspendFunctionReturnType
-import androidx.contentaccess.ext.hasMoreThanOneNonPrivateNonIgnoredConstructor
-import androidx.contentaccess.ext.isFilledThroughConstructor
-import androidx.contentaccess.ext.isNotInstantiable
-import androidx.contentaccess.ext.isSuspendFunction
-import androidx.contentaccess.ext.toAnnotationBox
-import asTypeElement
-import boxIfPrimitive
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import extractIntendedReturnType
-import isPrimitive
-import isString
-import isSupportedColumnType
-import isSupportedGenericType
-import isVoidObject
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.type.TypeMirror
-
-class ContentQueryProcessor(
- private val contentEntity: ContentEntityVO?,
- private val method: ExecutableElement,
- private val contentQueryAnnotation: ContentQuery,
- private val processingEnv: ProcessingEnvironment,
- private val errorReporter: ErrorReporter
-) {
- @KotlinPoetMetadataPreview
- fun process(): ContentQueryVO? {
- // TODO(obenabde): for cases where the return type is not a supported generic type (so one
- // entity, column pojo etc...) ensure it is nullable.
- val isSuspendFunction = method.isSuspendFunction(processingEnv)
- val returnType = if (isSuspendFunction) {
- method.getSuspendFunctionReturnType()
- } else {
- method.returnType
- }
- val types = processingEnv.typeUtils
- val potentialContentEntity = method.toAnnotationBox(ContentQuery::class)!!
- .getAsTypeMirror("contentEntity")!!
- val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
- ContentEntityProcessor(
- potentialContentEntity,
- processingEnv, errorReporter
- ).processEntity()
- } else {
- contentEntity
- }
- if (resolvedContentEntity == null) {
- errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
- return null
- }
- val toBeUsedUri = determineToBeUsedUri(
- resolvedContentEntity, contentQueryAnnotation.uri,
- errorReporter, method
- )
- if (toBeUsedUri.isEmpty()) {
- errorReporter.reportError(missingUriOnMethod(), method)
- }
- val orderBy = if (contentQueryAnnotation.orderBy.isNotEmpty()) {
- for (orderByMember in contentQueryAnnotation.orderBy) {
- val trimmedOrderByMember = orderByMember.trim()
- if (!resolvedContentEntity.columns.containsKey(trimmedOrderByMember)) {
- // Maybe it was "column desc" or "column asc", check.
- val splitOrderBy = trimmedOrderByMember.split(" ")
- if (splitOrderBy.size == 2 && resolvedContentEntity.columns.containsKey
- (splitOrderBy.get(0)) && ORDER_BY_KEYWORDS.contains(
- splitOrderBy
- .get(1)
- )
- ) {
- continue
- }
- errorReporter.reportError(badlyFormulatedOrderBy(orderByMember), method)
- }
- }
- contentQueryAnnotation.orderBy.joinToString(", ")
- } else {
- ""
- }
- val paramsNamesAndTypes = HashMap<String, TypeMirror>()
- for (param in method.parameters) {
- paramsNamesAndTypes.put(param.simpleName.toString(), param.asType())
- }
- val selectionVO = if (contentQueryAnnotation.selection.isEmpty()) {
- null
- } else {
- SelectionProcessor(
- method, contentQueryAnnotation.selection,
- paramsNamesAndTypes, errorReporter, resolvedContentEntity
- ).process()
- }
- if (contentQueryAnnotation.projection.size == 1 &&
- returnType.extractIntendedReturnType().isSupportedColumnType()
- ) {
- val queriedColumn = contentQueryAnnotation.projection[0]
- if (!resolvedContentEntity.columns.containsKey(queriedColumn)) {
- errorReporter.reportError(
- queriedColumnInProjectionNotInEntity(
- queriedColumn,
- resolvedContentEntity.type.toString()
- ),
- method
- )
- return null
- }
- val queriedColumnType = resolvedContentEntity.columns.get(queriedColumn)!!.type
- if (queriedColumnType.boxIfPrimitive(processingEnv).toString()
- != returnType.boxIfPrimitive(processingEnv).toString() &&
- (
- (
- !returnType.isSupportedGenericType() ||
- !processingEnv.typeUtils
- .isSameType(
- returnType.extractIntendedReturnType(),
- queriedColumnType.boxIfPrimitive(processingEnv)
- )
- )
- )
- ) {
- errorReporter.reportError(
- queriedColumnInProjectionTypeDoesntMatchReturnType(
- returnType.toString(),
- queriedColumnType.toString(), queriedColumn
- ),
- method
- )
- }
- if (errorReporter.errorReported) {
- return null
- }
- return ContentQueryVO(
- name = method.simpleName.toString(),
- toQueryFor = listOf(resolvedContentEntity.columns.get(queriedColumn)!!),
- selection = selectionVO,
- uri = toBeUsedUri,
- returnType = returnType,
- method = method,
- orderBy = orderBy,
- isSuspend = isSuspendFunction
- )
- } else {
- // Either empty projection or more than one field, either way infer the return columns
- // from the return type POJO/entity.
- if (types.isSameType(returnType, resolvedContentEntity.type)) {
- // TODO(obenabde): no need for projection with entity.
- return ContentQueryVO(
- name = method.simpleName.toString(),
- toQueryFor = resolvedContentEntity.columns.map { it.value },
- selection = selectionVO,
- orderBy = orderBy,
- uri = toBeUsedUri,
- returnType = returnType,
- method = method,
- isSuspend = isSuspendFunction
- )
- }
-
- val intendedReturnType = if (returnType.isSupportedGenericType()) {
- returnType.extractIntendedReturnType()
- } else {
- returnType
- }
-
- if (intendedReturnType.asTypeElement()
- .hasMoreThanOneNonPrivateNonIgnoredConstructor()
- ) {
- errorReporter.reportError(
- pojoHasMoreThanOneQualifyingConstructor(intendedReturnType.toString()),
- intendedReturnType.asTypeElement()
- )
- return null
- } else if (intendedReturnType.asTypeElement().isNotInstantiable()) {
- errorReporter.reportError(
- pojoIsNotInstantiable(
- intendedReturnType.asTypeElement()
- .qualifiedName.toString()
- ),
- intendedReturnType.asTypeElement()
- )
- return null
- }
- val pojo = PojoProcessor(intendedReturnType).process()
- // Apply the projection (if existing) to the POJO
- val pojoWithProjection = validateAndApplyProjectionToPojo(
- contentQueryAnnotation
- .projection,
- pojo, returnType, resolvedContentEntity
- )
- if (errorReporter.errorReported) {
- return null
- }
- pojoWithProjection!!.pojoFields.forEach {
- if (it.isNullable && it.type.isPrimitive()) {
- errorReporter.reportError(
- pojoWithNullablePrimitive(
- it.name,
- pojo.type.toString()
- ),
- method
- )
- }
- }
- return ContentQueryVO(
- name = method.simpleName.toString(),
- toQueryFor = pojoWithProjection.pojoFields.map {
- resolvedContentEntity.columns[it.columnName]!!
- },
- selection = selectionVO,
- uri = toBeUsedUri,
- returnType = returnType,
- method = method,
- orderBy = orderBy,
- isSuspend = isSuspendFunction
- )
- }
- }
-
- // Returns whether the pojo's fields names and types match ones in the entity being queried.
- private fun validatePojoCorrectnessAgainstEntity(
- pojo: PojoVO,
- resolvedContentEntity: ContentEntityVO
- ) {
- pojo.pojoFields.forEach { field ->
- if (!resolvedContentEntity.columns.containsKey(field.columnName) || !processingEnv
- .typeUtils.isSameType(
- resolvedContentEntity.columns.get(field.columnName)!!
- .type.boxIfPrimitive(processingEnv),
- field.type.boxIfPrimitive(processingEnv)
- )
- ) {
- errorReporter.reportError(
- pojoFieldNotInEntity(
- field.name, field.type.toString(),
- field.columnName, pojo.type.toString(),
- resolvedContentEntity.type.toString()
- ),
- method
- )
- } else {
- if (resolvedContentEntity.columns.get(field.columnName)!!.isNullable &&
- !field.isNullable
- ) {
- // TODO(obenabde): clarify how to mark as nullable, i.e "?" for Kotlin and
- // @androidx.annotations.Nullable for Java.
- errorReporter.reportError(
- nullableEntityColumnNotNullableInPojo(
- field.name,
- field.type.toString(),
- field.columnName,
- resolvedContentEntity.type.toString()
- ),
- method
- )
- }
- }
- }
- }
-
- private fun validateAndApplyProjectionToPojo(
- projection: Array<String>,
- pojo: PojoVO,
- returnType: TypeMirror,
- resolvedContentEntity: ContentEntityVO
- ): PojoVO? {
- // alert now.
- if (projection.isEmpty()) {
- validatePojoCorrectnessAgainstEntity(pojo, resolvedContentEntity)
- return pojo
- }
- var errorFound = false
- val extractedColumnNames = pojo.pojoFields.map { it.columnName to it.isNullable }.toMap()
- for (column in projection) {
- if (!extractedColumnNames.containsKey(column)) {
- errorFound = true
- errorReporter.reportError(
- columnInProjectionNotIncludedInReturnPojo(
- column,
- pojo.type.toString()
- ),
- method
- )
- }
- }
- for (pojoField in pojo.pojoFields) {
- if (!projection.contains(pojoField.columnName) && !pojoField.isNullable &&
- pojo.type.asTypeElement().isFilledThroughConstructor()
- ) {
- errorFound = true
- errorReporter.reportError(
- constructorFieldNotIncludedInProjectionNotNullable(
- pojoField.name,
- returnType
- .extractIntendedReturnType().toString()
- ),
- method
- )
- }
- }
- if (errorFound) {
- return null
- }
- val pojoFieldsWithProjection = pojo.pojoFields.filter { projection.contains(it.columnName) }
- validatePojoCorrectnessAgainstEntity(
- PojoVO(pojoFieldsWithProjection, pojo.type),
- resolvedContentEntity
- )
- return PojoVO(pojoFieldsWithProjection, pojo.type)
- }
-}
-
-fun determineToBeUsedUri(
- resolvedContentEntity: ContentEntityVO,
- uriInAnnotation: String,
- errorReporter: ErrorReporter,
- method: ExecutableElement
-): String {
- if (uriInAnnotation.isEmpty()) {
- return resolvedContentEntity.defaultUri
- }
-
- if (!uriInAnnotation.startsWith(":")) {
- return uriInAnnotation
- }
-
- val specifiedParamName = uriInAnnotation.substring(1)
- if (specifiedParamName.isEmpty()) {
- errorReporter.reportError(columnOnlyAsUri(), method)
- return uriInAnnotation
- } else if (!method.parameters.map { it.simpleName.toString() }.contains
- (specifiedParamName)
- ) {
- errorReporter.reportError(missingUriParameter(specifiedParamName), method)
- return uriInAnnotation
- } else if (!method.parameters.filter {
- it.simpleName.toString().equals(specifiedParamName)
- }[0].asType().isString()
- ) {
- errorReporter.reportError(uriParameterIsNotString(specifiedParamName), method)
- return uriInAnnotation
- }
- return uriInAnnotation
-}
-
-internal val ORDER_BY_KEYWORDS = listOf("asc", "desc")
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
deleted file mode 100644
index 1a46f41..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentUpdate
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentEntityVO
-import androidx.contentaccess.compiler.vo.ContentUpdateVO
-import androidx.contentaccess.compiler.vo.SelectionVO
-import androidx.contentaccess.ext.hasAnnotation
-import androidx.contentaccess.ext.getSuspendFunctionReturnType
-import androidx.contentaccess.ext.isSuspendFunction
-import androidx.contentaccess.ext.toAnnotationBox
-import boxIfPrimitive
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import isInt
-import isVoidObject
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.type.TypeMirror
-
-class ContentUpdateProcessor(
- private val contentEntity: ContentEntityVO?,
- private val method: ExecutableElement,
- private val contentUpdateAnnotation: ContentUpdate,
- private val processingEnv: ProcessingEnvironment,
- private val errorReporter: ErrorReporter
-) {
- @KotlinPoetMetadataPreview
- fun process(): ContentUpdateVO? {
- val isSuspendFunction = method.isSuspendFunction(processingEnv)
- val returnType = if (isSuspendFunction) {
- method.getSuspendFunctionReturnType()
- } else {
- method.returnType
- }
- val types = processingEnv.typeUtils
- val potentialContentEntity = method.toAnnotationBox(ContentUpdate::class)!!
- .getAsTypeMirror("contentEntity")!!
- val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
- ContentEntityProcessor(
- potentialContentEntity,
- processingEnv, errorReporter
- ).processEntity()
- } else {
- contentEntity
- }
- if (resolvedContentEntity == null) {
- errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
- return null
- }
- val toBeUsedUri = determineToBeUsedUri(
- resolvedContentEntity, contentUpdateAnnotation.uri,
- errorReporter, method
- )
- if (toBeUsedUri.isEmpty()) {
- errorReporter.reportError(missingUriOnMethod(), method)
- }
- if (!returnType.isInt()) {
- errorReporter.reportError(contentUpdateAnnotatedMethodNotReturningAnInteger(), method)
- }
- val entitiesInParams = mutableListOf<String>()
- for (param in method.parameters) {
- if (types.isSameType(param.asType(), resolvedContentEntity.type)) {
- entitiesInParams.add(param.simpleName.toString())
- }
- }
- if (entitiesInParams.size > 1) {
- // TODO(obenabde): we could in theory also support updating a list of entities
- // but that would mean multiple operations through the content resolver and may not
- // happen atomically. Anyhow it would be easier to do the other way through
- // parameters annotated with @ContentColumn. Explore this further later on, although I
- // doubt we need to worry about this so much for the updates
- errorReporter.reportError(
- updatingMultipleEntitiesAtTheSameType
- (resolvedContentEntity.type.toString(), method.simpleName.toString()),
- method
- )
- return null
- }
- if (entitiesInParams.size == 1) {
- // Assume the user wants to update a single entity
- if (contentUpdateAnnotation.where.isNotEmpty()) {
- errorReporter.reportError(
- methodSpecifiesWhereClauseWhenUpdatingUsingEntity
- (entitiesInParams.first().toString()),
- method
- )
- return null
- }
- val primaryKeyColumnName = resolvedContentEntity.primaryKeyColumn.columnName
- val primaryKeyVariableName = resolvedContentEntity.primaryKeyColumn.name
- val whereClause = "$primaryKeyColumnName = \${${entitiesInParams.first()}" +
- ".$primaryKeyVariableName}"
- val updateList = mutableListOf<Pair<String, String>>()
- for (entityColumn in resolvedContentEntity.columns.values) {
- if (entityColumn.columnName != primaryKeyColumnName) {
- val contentValue = Pair(
- entityColumn.columnName,
- "${entitiesInParams.first()}.${entityColumn.name}"
- )
- updateList.add(contentValue)
- }
- }
- return ContentUpdateVO(
- method.simpleName.toString(),
- updateList,
- SelectionVO(whereClause, emptyList()),
- toBeUsedUri,
- method,
- isSuspendFunction
- )
- }
- val paramsNamesAndTypes = HashMap<String, TypeMirror>()
- for (param in method.parameters) {
- paramsNamesAndTypes.put(param.simpleName.toString(), param.asType())
- }
- val selectionVO = if (contentUpdateAnnotation.where.isEmpty()) {
- null
- } else {
- SelectionProcessor(
- method, contentUpdateAnnotation.where,
- paramsNamesAndTypes, errorReporter, resolvedContentEntity
- ).process()
- }
- val contentValues = mutableListOf<Pair<String, String>>()
- var foundContentColumnAnnotatedParameters = false
- for (param in method.parameters) {
- if (param.hasAnnotation(ContentColumn::class)) {
- foundContentColumnAnnotatedParameters = true
- val columnName = param.getAnnotation(ContentColumn::class.java).columnName
- if (!resolvedContentEntity.columns.containsKey(columnName)) {
- errorReporter.reportError(
- columnInContentUpdateParametersNotInEntity(
- param.simpleName.toString(), columnName,
- resolvedContentEntity.type.toString()
- ),
- method
- )
- } else if (param.asType().boxIfPrimitive(processingEnv) != resolvedContentEntity
- .columns.get(columnName)!!.type.boxIfPrimitive(processingEnv)
- ) {
- errorReporter.reportError(
- mismatchedColumnTypeForColumnToBeUpdated(
- param.simpleName.toString(),
- columnName, param.asType().toString(),
- resolvedContentEntity.type
- .toString(),
- resolvedContentEntity.columns.get(columnName)!!.type
- .toString()
- ),
- method
- )
- } else if (fieldIsNullable(param) && !resolvedContentEntity
- .columns.get(columnName)!!.isNullable
- ) {
- errorReporter.reportError(
- nullableUpdateParamForNonNullableEntityColumn(
- param.simpleName.toString(), columnName,
- resolvedContentEntity.type.toString()
- ),
- method
- )
- } else {
- contentValues.add(Pair(columnName, param.simpleName.toString()))
- }
- }
- }
- if (!foundContentColumnAnnotatedParameters) {
- errorReporter.reportError(unsureWhatToUpdate(), method)
- }
- return ContentUpdateVO(
- method.simpleName.toString(),
- contentValues,
- selectionVO,
- toBeUsedUri,
- method,
- isSuspendFunction
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
deleted file mode 100644
index 72220ae..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.Element
-import javax.tools.Diagnostic
-
-fun missingEntityPrimaryKeyErrorMessage(entityName: String): String {
- return "Content entity $entityName doesn't have a primary key, a content entity must have one" +
- " field annotated with @ContentPrimaryKey."
-}
-
-fun missingFieldsInContentEntityErrorMessage(entityName: String): String {
- return "Content entity $entityName has no fields, a content entity must have at least one " +
- "field and exactly one primary key."
-}
-
-fun missingAnnotationOnEntityFieldErrorMessage(fieldName: String, entityName: String): String {
- return "Field $fieldName in $entityName is neither annotated with @ContentPrimaryKey nor " +
- "with @ContentColumn, all fields in a content entity must be be annotated by one of " +
- "the two"
-}
-
-fun entityFieldWithBothAnnotations(columnName: String, entityName: String): String {
- return "Field $columnName in $entityName is annotated with both @ContentPrimaryKey and " +
- "@ContentColumn, these annotations are mutually exclusive and a field " +
- "can only be annotated by one of the two."
-}
-
-fun entityWithMultiplePrimaryKeys(entityName: String): String {
- return "Content entity $entityName has two or more " +
- "primary keys, a content entity must have exactly one field annotated with " +
- "@ContentPrimaryKey."
-}
-
-fun unsupportedColumnType(columnName: String, entityName: String, type: String): String {
- return "Field $columnName in $entityName is of type " +
- "$type which is not a supported column type."
-}
-
-fun nonInstantiableEntity(entityName: String): String {
- return "Entity $entityName is not instantiable. It has no non private non ignored " +
- "constructors, it must have one and only one such constructor, whether parametrized " +
- "or not."
-}
-
-fun entityWithMultipleConstructors(entityName: String): String {
- return "Entity $entityName has more than one non private non ignored constructor. Entities " +
- "should have only one non private non ignored constructor."
-}
-
-fun entityWithNullablePrimitiveType(fieldName: String, entityName: String): String {
- return "Field $fieldName of entity $entityName is of a primitive type but is marked as " +
- "nullable. Please use the boxed type instead of the primitive of type for nullable " +
- "fields"
-}
-
-fun missingEntityOnMethod(methodName: String): String {
- return "Method $methodName has no associated entity, " +
- "please ensure that either the content access object containing the method " +
- "specifies an entity inside the @ContentAccessObject annotation or that the " +
- "method specifies a content entity through the contentEntity parameter of " +
- "the annotation."
-}
-
-fun missingUriOnMethod(): String {
- return "Failed to determine URI for query, the " +
- "URI is neither specified in the associated ContentEntity, nor in the annotation " +
- "parameters."
-}
-
-fun badlyFormulatedOrderBy(orderByMember: String): String {
- return "orderBy member \"$orderByMember\" is either not " +
- "properly formulated or references columns that are not in the " +
- "associated entity. All members in the orderBy array should either be" +
- " a column name or a column name following by \"asc\" or \"desc\""
-}
-
-fun queriedColumnInProjectionNotInEntity(queriedColumn: String, entity: String): String {
- return "Column $queriedColumn being queried through the projection is not defined within the " +
- "specified entity $entity."
-}
-
-fun queriedColumnInProjectionTypeDoesntMatchReturnType(
- returnType: String,
- queriedColumnType: String,
- queriedColumn: String
-): String {
- return "Return type $returnType does not match type" +
- " $queriedColumnType of column $queriedColumn being queried."
-}
-
-fun pojoHasMoreThanOneQualifyingConstructor(pojo: String): String {
- return "Pojo $pojo has more than one non private" +
- " constructor. Pojos should have only one non private constructor."
-}
-
-fun pojoIsNotInstantiable(pojo: String): String {
- return "Pojo $pojo is not instantiable! It has no non private non ignored " +
- "constructors, it must have one and only one such constructor, whether " +
- "parametrized or not."
-}
-
-fun pojoWithNullablePrimitive(fieldName: String, pojo: String): String {
- return "Field $fieldName of pojo $pojo is of a primitive type but is marked as " +
- "nullable. Please use the boxed type instead of the primitive of type for nullable " +
- "fields"
-}
-
-fun pojoFieldNotInEntity(
- fieldName: String,
- fieldType: String,
- columnName: String,
- pojo: String,
- entity: String
-): String {
- return "Field $fieldName of type $fieldType corresponding to content" +
- " provider column $columnName in object $pojo doesn't match a field with same " +
- "type and content column in content entity $entity"
-}
-
-fun constructorFieldNotIncludedInProjectionNotNullable(fieldName: String, returnType: String):
- String {
- return "Field $fieldName in return object constructor $returnType is not included in the" +
- " supplied projection and is not nullable. Constructor fields that are not" +
- " included in a query projection should all be nullable."
- }
-
-fun columnInProjectionNotIncludedInReturnPojo(columnName: String, returnType: String):
- String {
- return "Column $columnName in projection array isn't included in " +
- "the return type $returnType"
- }
-
-fun nullableEntityColumnNotNullableInPojo(
- fieldName: String,
- fieldType: String,
- columnName: String,
- entity: String
-): String {
- return "Field $fieldName of type $fieldType corresponding to content provider column " +
- "$columnName is not nullable, however that column is declared as nullable in the " +
- "associated entity $entity. Please mark the field as nullable."
-}
-
-fun columnOnlyAsUri(): String = ": is an invalid uri, please follow it up with the parameter name"
-
-fun missingUriParameter(parameterName: String): String {
- return "Parameter $parameterName mentioned as the uri does not exist! Please add it to " +
- "the method parameters"
-}
-
-fun uriParameterIsNotString(parameterName: String): String {
- return "Parameter $parameterName mentioned as the uri should be of type String"
-}
-
-fun strayColumnInSelectionErrorMessage(): String = "Found stray \":\" in the selection"
-
-fun selectionParameterNotInMethodParameters(param: String): String {
- return "Selection argument $param is not specified in the method's parameters."
-}
-
-fun columnInSelectionMissingFromEntity(columnName: String, entity: String): String {
- return "Column $columnName in selection/where parameter" +
- " does not exist in content entity $entity"
-}
-
-fun columnInContentUpdateParametersNotInEntity(
- paramName: String,
- columnName: String,
- entity: String
-): String {
- return "Parameter $paramName is annotated with @ContentColumn and specifies that it should " +
- "update column $columnName, however that column was not found in content entity $entity"
-}
-
-fun mismatchedColumnTypeForColumnToBeUpdated(
- paramName: String,
- columnName: String,
- paramType:
- String,
- entityType: String,
- columnType: String
-): String {
- return "Parameter $paramName linked to column " +
- "$columnName is of type $paramType however that column's type " +
- "as specified by entity $entityType is $columnType"
-}
-
-fun methodSpecifiesWhereClauseWhenUpdatingUsingEntity(paramName: String): String {
- return "@ContentUpdate annotated method specifies an entity as" +
- " parameter $paramName but also specifies a where clause. " +
- "Updates using an entity happen by matching the primary key and do not " +
- "take into consideration the where clause."
-}
-
-fun updatingMultipleEntitiesAtTheSameType(entityType: String, methodName: String): String {
- return "There is more than one parameter of the entity type " +
- "$entityType to the @ContentUpdate annotated method" +
- " $methodName. Only one entity can be update at a time."
-}
-
-fun contentUpdateAnnotatedMethodNotReturningAnInteger(): String {
- return "Methods annotated with @ContentUpdate should return an integer."
-}
-
-fun contentDeleteAnnotatedMethodNotReturningAnInteger(): String {
- return "Methods annotated with @ContentDelete should return an integer."
-}
-
-fun contentInsertAnnotatedMethodNotReturningAUri(): String {
- return "Methods annotated with @ContentInsert should return a Uri."
-}
-
-fun insertMethodHasMoreThanOneEntity(): String {
- return "@ContentInsert annotated method has more than one content entity in its parameters." +
- " @ContentInsert annotated methods parameters should include one and only one " +
- "content entity parameter (@ContentEntity annotated object)."
-}
-
-fun insertMethodHasNoEntityInParameters(): String {
- return "@ContentInsert annotated method has no entity parameters. @ContentInsert annotated " +
- "methods parameters should include one and only one content entity parameter " +
- "(@ContentEntity annotated object)."
-}
-
-fun unsureWhatToUpdate(): String {
- return "Not sure what this @ContentUpdate annotated method is supposed" +
- " to update, @ContentUpdate annotated methods should either specify a parameter " +
- "of the entity's type which will update the existing row in the content provider " +
- "using info from the entity object and will match on the primary key, or specify " +
- "one or more parameters annotated with @ContentColumn which will result in updating" +
- " rows matching any given criteria in the where clause to the specified values"
-}
-
-fun nullableUpdateParamForNonNullableEntityColumn(
- paramName: String,
- columnName: String,
- entity: String
-): String {
- return "Parameter $paramName corresponding content column $columnName is nullable, however " +
- "that column is specified as non nullable in entity $entity. Please ensure that " +
- "parameter $paramName is non nullable too."
-}
-
-fun ProcessingEnvironment.warn(warning: String, element: Element) {
- this.messager.printMessage(Diagnostic.Kind.WARNING, warning, element)
-}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/PojoProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/PojoProcessor.kt
deleted file mode 100644
index 285222b..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/PojoProcessor.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.compiler.vo.PojoFieldVO
-import androidx.contentaccess.ext.hasAnnotation
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentPrimaryKey
-import androidx.contentaccess.compiler.vo.PojoVO
-import androidx.contentaccess.ext.getAllConstructorParamsOrPublicFields
-import asTypeElement
-import javax.lang.model.type.TypeMirror
-
-class PojoProcessor(val typeMirror: TypeMirror) {
- fun process(): PojoVO {
- val returnList = mutableListOf<PojoFieldVO>()
- val variables = typeMirror.asTypeElement()
- .getAllConstructorParamsOrPublicFields()
- for (v in variables) {
- val type = v.asType()
- val name = v.simpleName.toString()
- val columnName = if (v.hasAnnotation(ContentColumn::class)) {
- v.getAnnotation(ContentColumn::class.java).columnName
- } else if (v.hasAnnotation(ContentPrimaryKey::class)) {
- v.getAnnotation(ContentPrimaryKey::class.java).columnName
- } else {
- name
- }
- returnList.add(PojoFieldVO(name, columnName, type, fieldIsNullable(v)))
- }
- return PojoVO(returnList, typeMirror)
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
deleted file mode 100644
index 7e440f1..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.processor
-
-import androidx.contentaccess.compiler.utils.ErrorReporter
-import androidx.contentaccess.compiler.vo.ContentEntityVO
-import androidx.contentaccess.compiler.vo.SelectionVO
-import net.sf.jsqlparser.expression.ExpressionVisitorAdapter
-import net.sf.jsqlparser.parser.CCJSqlParserUtil
-import net.sf.jsqlparser.schema.Column
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.type.TypeMirror
-
-class SelectionProcessor(
- private val method: ExecutableElement,
- private val selection: String,
- private val paramsNamesAndTypes: HashMap<String, TypeMirror>,
- private val errorReporter: ErrorReporter,
- private val resolvedContentEntity: ContentEntityVO
-) {
-
- // TODO(obenabde): this is low priority but maybe validate that method arguments being compared
- // to columns have the same type (e.g "description = :param", if description is a string, then
- // ensure that param is a string as well.
- fun process(): SelectionVO? {
- // TODO(obenabde): Consider returning a kotlin Result to avoid returning null in case
- // of failure.
- var modifiedSelection = selection
- val selectionsArgs = ArrayList<String>()
- val wordsStartingWithColumn = findWordsStartingWithColumn(selection)
- for (wordStartingWithColumn in wordsStartingWithColumn) {
- if (wordStartingWithColumn.length == 1) {
- errorReporter.reportError(strayColumnInSelectionErrorMessage(), method)
- return null
- }
- val strippedParamName = wordStartingWithColumn.substring(1)
- if (!paramsNamesAndTypes.containsKey(strippedParamName)) {
- errorReporter.reportError(
- selectionParameterNotInMethodParameters
- (strippedParamName),
- method
- )
- return null
- }
- selectionsArgs.add(strippedParamName)
- modifiedSelection = modifiedSelection.replaceFirst(wordStartingWithColumn, "?")
- }
- val selectionExpression = CCJSqlParserUtil.parseCondExpression(modifiedSelection)
- var foundMissingColumn = false
- selectionExpression.accept(object : ExpressionVisitorAdapter() {
- override fun visit(column: Column?) {
- val columnString = column.toString()
- // So it seems to assume that in the expression col1 = "ll" that "ll" is a column
- // and doesn't understand that it's a string reference for some reasons... work
- // around this for now.
- if (!columnString.startsWith('"') || !columnString.endsWith('"')) {
- if (!resolvedContentEntity.columns.contains(columnString)) {
- errorReporter.reportError(
- columnInSelectionMissingFromEntity(
- columnString,
- resolvedContentEntity.type.toString()
- ),
- method
- )
- foundMissingColumn = true
- }
- }
- }
- })
- if (foundMissingColumn) {
- return null
- }
- return SelectionVO(modifiedSelection, selectionsArgs)
- }
-}
-
-fun findWordsStartingWithColumn(expression: String): List<String> {
- val wordsStartingWithColumn = mutableListOf<String>()
- var currIndex = 0
- while (currIndex < expression.length) {
- if (expression[currIndex] == ':') {
- val startingIndex = currIndex
- while (currIndex + 1 < expression.length && expression[currIndex + 1]
- .isLetterOrDigit()
- ) {
- currIndex++
- }
- wordsStartingWithColumn.add(expression.substring(startingIndex, currIndex + 1))
- }
- currIndex++
- }
- return wordsStartingWithColumn
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
deleted file mode 100644
index 96ece18..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.utils
-
-import javax.annotation.processing.Messager
-import javax.lang.model.element.Element
-import javax.tools.Diagnostic
-
-class ErrorReporter(private val messager: Messager) {
- var errorReported: Boolean = false
- private set
-
- fun reportError(error: String, element: Element) {
- errorReported = true
- messager.printMessage(
- Diagnostic.Kind.ERROR, error, element
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
deleted file mode 100644
index 228e596..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
+++ /dev/null
@@ -1,294 +0,0 @@
-package androidx.contentaccess.compiler.utils
-
-import com.google.auto.common.MoreElements
-import com.google.common.base.Preconditions
-import com.google.common.collect.ImmutableMap
-import java.io.Writer
-import java.util.ArrayList
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.AnnotationMirror
-import javax.lang.model.element.AnnotationValue
-import javax.lang.model.element.Element
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.Name
-import javax.lang.model.element.NestingKind
-import javax.lang.model.element.PackageElement
-import javax.lang.model.element.QualifiedNameable
-import javax.lang.model.element.TypeElement
-import javax.lang.model.type.ArrayType
-import javax.lang.model.type.DeclaredType
-import javax.lang.model.type.ErrorType
-import javax.lang.model.type.ExecutableType
-import javax.lang.model.type.IntersectionType
-import javax.lang.model.type.NoType
-import javax.lang.model.type.NullType
-import javax.lang.model.type.PrimitiveType
-import javax.lang.model.type.TypeKind
-import javax.lang.model.type.TypeMirror
-import javax.lang.model.type.TypeVariable
-import javax.lang.model.type.UnionType
-import javax.lang.model.type.WildcardType
-import javax.lang.model.util.AbstractTypeVisitor8
-import javax.lang.model.util.Elements
-import javax.lang.model.util.Types
-
-class JvmSignatureUtil(
- elements: Elements,
- types: Types
-) : Elements {
- internal val elements: Elements
- private val types: Types
-
- constructor(processingEnv: ProcessingEnvironment) : this(
- processingEnv.elementUtils,
- processingEnv.typeUtils
- ) {
- }
-
- override fun getTypeElement(name: CharSequence): TypeElement {
- return elements.getTypeElement(name)
- }
-
- /**
- * Invokes [Elements.getTypeElement], throwing [TypeNotPresentException]
- * if it is not accessible in the current compilation.
- */
- fun checkTypePresent(typeName: String?): TypeElement {
- return elements.getTypeElement(typeName) ?: throw TypeNotPresentException(typeName, null)
- }
-
- override fun getPackageElement(name: CharSequence): PackageElement {
- return elements.getPackageElement(name)
- }
-
- override fun getElementValuesWithDefaults(
- a: AnnotationMirror
- ): Map<out ExecutableElement, AnnotationValue> {
- return elements.getElementValuesWithDefaults(a)
- }
-
- /** Returns a map of annotation values keyed by attribute name. */
- fun getElementValuesWithDefaultsByName(
- a: AnnotationMirror
- ): Map<String, AnnotationValue?> {
- val builder =
- ImmutableMap.builder<String, AnnotationValue?>()
- val map =
- getElementValuesWithDefaults(a)
- for (e in map.keys) {
- builder.put(e.simpleName.toString(), map[e]!!)
- }
- return builder.build()
- }
-
- override fun getDocComment(e: Element): String {
- return elements.getDocComment(e)
- }
-
- override fun isDeprecated(e: Element): Boolean {
- return elements.isDeprecated(e)
- }
-
- override fun getBinaryName(type: TypeElement): Name {
- return elements.getBinaryName(type)
- }
-
- override fun getPackageOf(type: Element): PackageElement {
- return elements.getPackageOf(type)
- }
-
- override fun getAllMembers(type: TypeElement): List<Element> {
- return elements.getAllMembers(type)
- }
-
- override fun getAllAnnotationMirrors(e: Element): List<AnnotationMirror> {
- return elements.getAllAnnotationMirrors(e)
- }
-
- override fun hides(
- hider: Element,
- hidden: Element
- ): Boolean {
- return elements.hides(hider, hidden)
- }
-
- override fun overrides(
- overrider: ExecutableElement,
- overridden: ExecutableElement,
- type: TypeElement
- ): Boolean {
- return elements.overrides(overrider, overridden, type)
- }
-
- override fun getConstantExpression(value: Any): String {
- return elements.getConstantExpression(value)
- }
-
- override fun printElements(
- w: Writer,
- vararg elements: Element
- ) {
- this.elements.printElements(w, *elements)
- }
-
- override fun getName(cs: CharSequence): Name {
- return elements.getName(cs)
- }
-
- override fun isFunctionalInterface(type: TypeElement): Boolean {
- return elements.isFunctionalInterface(type)
- }
-
- companion object {
- fun getMethodDescriptor(element: ExecutableElement): String {
- return element.simpleName.toString() + getDescriptor(
- element.asType()
- )
- }
-
- private fun getDescriptor(t: TypeMirror): String {
- return t.accept(
- JVM_DESCRIPTOR_TYPE_VISITOR,
- null
- )
- }
-
- private val JVM_DESCRIPTOR_TYPE_VISITOR =
- object : AbstractTypeVisitor8<String, Void>() {
- override fun visitArray(
- arrayType: ArrayType,
- v: Void
- ): String {
- return "[" + getDescriptor(arrayType.componentType)
- }
-
- override fun visitDeclared(
- declaredType: DeclaredType,
- v: Void?
- ): String {
- return "L" + getInternalName(declaredType.asElement()) + ";"
- }
-
- override fun visitError(
- errorType: ErrorType,
- v: Void?
- ): String {
- return visitUnknown(errorType, null)
- }
-
- override fun visitExecutable(
- executableType: ExecutableType,
- v: Void?
- ): String {
- val descriptors =
- ArrayList<String>()
- for (tm in executableType.parameterTypes) {
- descriptors.add(getDescriptor(tm))
- }
- val parameterDescriptors = java.lang.String.join("", descriptors)
- val returnDescriptor =
- getDescriptor(executableType.returnType)
- return "($parameterDescriptors)$returnDescriptor"
- }
-
- override fun visitIntersection(
- intersectionType: IntersectionType,
- v: Void?
- ): String {
- return getDescriptor(
- intersectionType.bounds[0]
- )
- }
-
- override fun visitNoType(noType: NoType, v: Void): String {
- return "V"
- }
-
- override fun visitNull(
- nullType: NullType,
- v: Void?
- ): String {
- return visitUnknown(nullType, null)
- }
-
- override fun visitPrimitive(
- primitiveType: PrimitiveType,
- v: Void?
- ): String {
- return when (primitiveType.kind) {
- TypeKind.BOOLEAN -> "Z"
- TypeKind.BYTE -> "B"
- TypeKind.SHORT -> "S"
- TypeKind.INT -> "I"
- TypeKind.LONG -> "J"
- TypeKind.CHAR -> "C"
- TypeKind.FLOAT -> "F"
- TypeKind.DOUBLE -> "D"
- else -> throw IllegalArgumentException("Unknown primitive type.")
- }
- }
-
- override fun visitTypeVariable(
- typeVariable: TypeVariable,
- v: Void?
- ): String {
- return getDescriptor(typeVariable.upperBound)
- }
-
- override fun visitUnion(
- unionType: UnionType,
- v: Void?
- ): String {
- return visitUnknown(unionType, null)
- }
-
- override fun visitUnknown(
- typeMirror: TypeMirror,
- v: Void?
- ): String {
- throw IllegalArgumentException("Unsupported type: " + typeMirror)
- }
-
- override fun visitWildcard(
- wildcardType: WildcardType,
- v: Void?
- ): String {
- return ""
- }
-
- private fun getInternalName(element: Element): String {
- try {
- val typeElement =
- MoreElements.asType(element)
- return when (typeElement.getNestingKind()) {
- NestingKind.TOP_LEVEL ->
- typeElement.getQualifiedName()
- .toString().replace('.', '/')
- NestingKind.MEMBER -> getInternalName(
- typeElement.getEnclosingElement
- ()
- ) + "$" + typeElement.getSimpleName()
- else -> throw IllegalArgumentException("Unsupported nesting kind.")
- }
- } catch (e: IllegalArgumentException) {
- // Not a TypeElement, try something else...
- }
- if (element is QualifiedNameable) {
- val qualifiedNameElement = element
- return qualifiedNameElement.getQualifiedName()
- .toString().replace('.', '/')
- }
- return element.getSimpleName().toString()
- }
- }
- }
-
- init {
- this.elements =
- Preconditions.checkNotNull(
- elements
- )
- this.types =
- Preconditions.checkNotNull(types)
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentAccessObjectVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentAccessObjectVO.kt
deleted file mode 100644
index 35b804d..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentAccessObjectVO.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.element.Element
-import javax.lang.model.type.TypeMirror
-
-data class ContentAccessObjectVO (
- // TODO(obenabde): eventually clean up some of these fields if unused anywhere, same for all
- // other VOs.
- val contentEntity: ContentEntityVO?,
- val interfaceElement: Element,
- val interfaceName: String,
- val packageName: String,
- val interfaceType: TypeMirror,
- val queries: List<ContentQueryVO>,
- val updates: List<ContentUpdateVO>,
- val deletes: List<ContentDeleteVO>,
- val inserts: List<ContentInsertVO>
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentColumnVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentColumnVO.kt
deleted file mode 100644
index e7c084f..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentColumnVO.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.type.TypeMirror
-
-// Represents a column in a content provider
-data class ContentColumnVO(
- val name: String,
- val type: TypeMirror,
- val columnName: String = name,
- val isNullable: Boolean,
- val requiresApi: Int?
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentDeleteVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentDeleteVO.kt
deleted file mode 100644
index 978ab44..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentDeleteVO.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.element.ExecutableElement
-
-data class ContentDeleteVO(
- val name: String,
- val where: SelectionVO?,
- val uri: String,
- val method: ExecutableElement,
- val isSuspend: Boolean
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentEntityVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentEntityVO.kt
deleted file mode 100644
index b0bedb9..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentEntityVO.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.type.DeclaredType
-
-// Represents a column in a content provider
-data class ContentEntityVO(
- val defaultUri: String,
- val type: DeclaredType,
- val columns: Map<String, ContentColumnVO>,
- val primaryKeyColumn: ContentColumnVO
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentInsertVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentInsertVO.kt
deleted file mode 100644
index e6142bb..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentInsertVO.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.element.ExecutableElement
-
-data class ContentInsertVO(
- val name: String,
- val uri: String,
- val method: ExecutableElement,
- val isSuspend: Boolean,
- val parameterName: String,
- val columns: List<ContentColumnVO>
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentQueryVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentQueryVO.kt
deleted file mode 100644
index cde6a0f..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentQueryVO.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.type.TypeMirror
-
-data class ContentQueryVO(
- val name: String,
- val toQueryFor: List<ContentColumnVO>,
- val selection: SelectionVO?,
- val orderBy: String,
- val uri: String,
- val returnType: TypeMirror,
- val method: ExecutableElement,
- val isSuspend: Boolean
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentUpdateVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentUpdateVO.kt
deleted file mode 100644
index cbbdbf7..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/ContentUpdateVO.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.element.ExecutableElement
-
-data class ContentUpdateVO(
- val name: String,
- val toUpdate: List<Pair<String, String>>,
- val where: SelectionVO?,
- val uri: String,
- val method: ExecutableElement,
- val isSuspend: Boolean
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/PojoFieldVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/PojoFieldVO.kt
deleted file mode 100644
index 158b38b..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/PojoFieldVO.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.type.TypeMirror
-
-data class PojoFieldVO(
- val name: String,
- val columnName: String,
- val type: TypeMirror,
- val isNullable: Boolean
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/PojoVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/PojoVO.kt
deleted file mode 100644
index 54c6ae3..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/PojoVO.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-import javax.lang.model.type.TypeMirror
-
-data class PojoVO(
- val pojoFields: List<PojoFieldVO>,
- val type: TypeMirror
-)
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/SelectionVO.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/SelectionVO.kt
deleted file mode 100644
index afc6260..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/vo/SelectionVO.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.vo
-
-data class SelectionVO(
- val selection: String,
- val selectionArgs: List<String>
-)
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
deleted file mode 100644
index 5f4b88d..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.writer
-
-import androidx.contentaccess.compiler.vo.ContentAccessObjectVO
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.FileSpec
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.KModifier
-import com.squareup.kotlinpoet.PropertySpec
-import com.squareup.kotlinpoet.TypeSpec
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import androidx.contentaccess.ext.getKotlinFunspec
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.ExecutableElement
-
-class ContentAccessObjectWriter(
- val contentAccessObject: ContentAccessObjectVO,
- val processingEnv: ProcessingEnvironment
-) {
- @KotlinPoetMetadataPreview
- fun generateFile() {
- // We do this instead of getting the simple name of the class in case of nested classes.
- val generatedClassName =
- "${contentAccessObject.interfaceName.removePrefix(contentAccessObject.packageName)
- .replace(".", "_")}Impl"
- val fileSpecBuilder = FileSpec.builder(
- contentAccessObject.packageName,
- generatedClassName
- )
- val contentResolverTypePlaceholder = ClassName("android.content", "ContentResolver")
- val coroutineDispatcherTypePlaceholder = ClassName(
- "kotlinx.coroutines",
- "CoroutineDispatcher"
- )
- val generatedClassBuilder = TypeSpec.classBuilder(generatedClassName)
- .addSuperinterface(ClassName.bestGuess(contentAccessObject.interfaceName))
- .primaryConstructor(
- FunSpec.constructorBuilder()
- .addParameter("contentResolver", contentResolverTypePlaceholder)
- .addParameter("coroutineDispatcher", coroutineDispatcherTypePlaceholder)
- .build()
- )
- .addProperty(
- PropertySpec.builder(
- "_contentResolver",
- contentResolverTypePlaceholder
- ).initializer("contentResolver").build()
- )
- .addProperty(
- PropertySpec.builder(
- "_coroutineDispatcher",
- coroutineDispatcherTypePlaceholder
- )
- .initializer("coroutineDispatcher").build()
- )
-
- for (contentQuery in contentAccessObject.queries) {
- generatedClassBuilder.addFunction(
- ContentQueryMethodWriter(processingEnv, contentQuery)
- .createContentQueryMethod()!!
- )
- }
- for (contentUpdate in contentAccessObject.updates) {
- generatedClassBuilder.addFunction(
- ContentUpdateMethodWriter(processingEnv, contentUpdate)
- .createContentUpdateMethod()!!
- )
- }
-
- for (contentDelete in contentAccessObject.deletes) {
- generatedClassBuilder.addFunction(
- ContentDeleteMethodWriter(processingEnv, contentDelete)
- .createContentDeleteMethod()
- )
- }
-
- for (contentInsert in contentAccessObject.inserts) {
- generatedClassBuilder.addFunction(
- ContentInsertMethodWriter(processingEnv, contentInsert)
- .createContentDeleteMethod()
- )
- }
-
- val accessorFile = fileSpecBuilder.addType(
- generatedClassBuilder.addOriginatingElement
- (contentAccessObject.interfaceElement).build()
- ).build()
- accessorFile.writeTo(processingEnv.filer)
- }
-}
-
-@KotlinPoetMetadataPreview
-fun funSpecOverriding(element: ExecutableElement, processingEnv: ProcessingEnvironment):
- FunSpec.Builder {
- val builder = element.getKotlinFunspec(processingEnv).toBuilder()
- builder.modifiers.remove(KModifier.ABSTRACT)
- builder.annotations.removeAll { true }
- builder.addModifiers(KModifier.OVERRIDE)
- return builder
- }
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentDeleteMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentDeleteMethodWriter.kt
deleted file mode 100644
index 5aa2f84..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentDeleteMethodWriter.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.writer
-
-import androidx.contentaccess.compiler.vo.ContentDeleteVO
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.CodeBlock
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.MemberName
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import javax.annotation.processing.ProcessingEnvironment
-
-class ContentDeleteMethodWriter(
- val processingEnv: ProcessingEnvironment,
- private val contentDelete: ContentDeleteVO
-) {
- private val returnOrSet = if (contentDelete.isSuspend) "" else "return "
-
- @KotlinPoetMetadataPreview
- fun createContentDeleteMethod(): FunSpec {
- val methodBuilder = funSpecOverriding(contentDelete.method, processingEnv)
-
- if (contentDelete.isSuspend) {
- val withContext = MemberName("kotlinx.coroutines", "withContext")
- methodBuilder.beginControlFlow("return %M(_coroutineDispatcher)", withContext)
- }
-
- val selectionArgs = (contentDelete.where?.selectionArgs ?: emptyList())
- .joinToString { CodeBlock.of("%N.toString()", it).toString() }
-
- val whereCondition = if (contentDelete.where?.selection != null) {
- CodeBlock.of("%S", contentDelete.where.selection).toString()
- } else {
- "null"
- }
-
- methodBuilder.addStatement("val _where = $whereCondition")
- methodBuilder.addStatement("val _selectionArgs = arrayOf<String>($selectionArgs)")
-
- methodBuilder
- .addStatement(
- "$returnOrSet _contentResolver.delete(%T.parse(%S), %N, %N)",
- ClassName("android.net", "Uri"),
- contentDelete.uri,
- "_where",
- "_selectionArgs"
- )
-
- if (contentDelete.isSuspend) {
- methodBuilder.endControlFlow()
- }
-
- return methodBuilder.build()
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
deleted file mode 100644
index 4ccdaa9..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.writer
-
-import androidx.contentaccess.compiler.vo.ContentInsertVO
-import com.squareup.kotlinpoet.AnnotationSpec
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.MemberName
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import javax.annotation.processing.ProcessingEnvironment
-
-class ContentInsertMethodWriter(
- val processingEnv: ProcessingEnvironment,
- private val contentInsert: ContentInsertVO
-) {
- // TODO(yrezgui): Handle no return
- // TODO(yrezgui): Raise error if set return type isn't URI?
- private val returnOrSet = if (contentInsert.isSuspend) "" else "return "
-
- @KotlinPoetMetadataPreview
- fun createContentDeleteMethod(): FunSpec {
- val methodBuilder = funSpecOverriding(contentInsert.method, processingEnv)
- methodBuilder.annotations.add(
- AnnotationSpec.builder(Suppress::class).addMember("%S", "DEPRECATION").build()
- )
- if (contentInsert.isSuspend) {
- val withContext = MemberName("kotlinx.coroutines", "withContext")
- methodBuilder.beginControlFlow("return %M(_coroutineDispatcher)", withContext)
- }
-
- methodBuilder.beginControlFlow(
- "val newValues = %T().apply",
- ClassName("android.content", "ContentValues")
- )
-
- for (column in contentInsert.columns) {
- if (!column.isNullable) {
- methodBuilder.addStatement(
- "put(%2S, %1N.%3N)\n",
- contentInsert.parameterName,
- column.columnName,
- column.name
- )
- } else {
- methodBuilder.addStatement(
- "if (%1N.%3N != null) put(%2S, %1N.%3N)",
- contentInsert.parameterName,
- column.columnName,
- column.name
- )
- }
- }
-
- methodBuilder.endControlFlow()
-
- methodBuilder
- .addStatement(
- "$returnOrSet _contentResolver.insert(%T.parse(%S), %N)",
- ClassName("android.net", "Uri"),
- contentInsert.uri,
- "newValues"
- )
-
- if (contentInsert.isSuspend) {
- methodBuilder.endControlFlow()
- }
-
- return methodBuilder.build()
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
deleted file mode 100644
index 031bb0d..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.writer
-
-import androidx.contentaccess.compiler.processor.PojoProcessor
-import androidx.contentaccess.compiler.processor.warn
-import androidx.contentaccess.compiler.vo.ContentColumnVO
-import androidx.contentaccess.compiler.vo.ContentQueryVO
-import androidx.contentaccess.ext.getAllConstructorParamsOrPublicFields
-import androidx.contentaccess.ext.hasNonEmptyNonPrivateNonIgnoredConstructor
-import asTypeElement
-import com.squareup.kotlinpoet.AnnotationSpec
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.MemberName
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import extractIntendedReturnType
-import getCursorMethod
-import isList
-import isOptional
-import isSet
-import isSupportedColumnType
-import isSupportedGenericType
-import toKotlinClassName
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.type.TypeMirror
-
-class ContentQueryMethodWriter(
- val processingEnv: ProcessingEnvironment,
- val contentQuery: ContentQueryVO
-) {
- val returnOrSet = if (contentQuery.isSuspend) "" else "return "
- val buildClassPlaceHolder = ClassName("android.os", "Build")
-
- @KotlinPoetMetadataPreview
- fun createContentQueryMethod(): FunSpec? {
- val uriTypePlaceHolder = ClassName("android.net", "Uri")
- val methodBuilder = funSpecOverriding(contentQuery.method, processingEnv)
- methodBuilder.annotations.add(
- AnnotationSpec.builder(Suppress::class).addMember
- ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember(
- "%S",
- "PLATFORM_CLASS_MAPPED_TO_KOTLIN"
- ).addMember("%S", "DEPRECATION").build()
- )
- if (contentQuery.isSuspend) {
- val withContext = MemberName("kotlinx.coroutines", "withContext")
- methodBuilder.beginControlFlow(
- "return %M(_coroutineDispatcher)",
- withContext
- )
- }
- if (contentQuery.uri.startsWith(":")) {
- methodBuilder.addStatement(
- "val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
- contentQuery.uri.removePrefix(":")
- )
- } else {
- methodBuilder.addStatement(
- "val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
- contentQuery.uri
- )
- }
- methodBuilder.addStatement("val _projectionList = mutableListOf<String>()")
- for (column in contentQuery.toQueryFor) {
- if (column.requiresApi != null) {
- methodBuilder.beginControlFlow(
- "if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
- buildClassPlaceHolder
- )
- methodBuilder.addStatement("_projectionList.add(%S)", column.columnName)
- methodBuilder.endControlFlow()
- } else {
- methodBuilder.addStatement("_projectionList.add(%S)", column.columnName)
- }
- }
- methodBuilder.addStatement("val _projection = _projectionList.toTypedArray()")
- var noSelectionArgs = true
- if (contentQuery.selection != null) {
- methodBuilder.addStatement("val _selection = %S", contentQuery.selection.selection)
- val selectionArgs = contentQuery.selection.selectionArgs
- val joinedSelectionArgs = if (selectionArgs.size == 1) {
- "${selectionArgs[0]}.toString()"
- } else {
- selectionArgs.map { r -> "$r.toString()" }.joinToString(",")
- }
- if (selectionArgs.isNotEmpty()) {
- noSelectionArgs = false
- methodBuilder.addStatement("val _selectionArgs = arrayOf($joinedSelectionArgs)")
- }
- } else {
- methodBuilder.addStatement("val _selection = \"\"")
- }
- callResolverAndFormulateReturn(
- methodBuilder, contentQuery.returnType,
- noSelectionArgs
- )
-
- if (contentQuery.isSuspend) {
- methodBuilder.endControlFlow()
- }
- return methodBuilder.build()
- }
-
- fun callResolverAndFormulateReturn(
- methodBuilder: FunSpec.Builder,
- returnType: TypeMirror,
- noSelectionArgs: Boolean
- ) {
- methodBuilder.addStatement(
- "val _cursor = _contentResolver.query(_uri, _projection, " +
- "_selection, ${if (noSelectionArgs) "null" else "_selectionArgs"}, %S)",
- contentQuery.orderBy
- )
- methodBuilder.beginControlFlow("if (_cursor == null)")
- methodBuilder.addStatement(
- "throw NullPointerException(%S)",
- "Cursor returned by the " +
- "content provider was null!"
- )
- methodBuilder.endControlFlow()
- if (returnType.isSupportedGenericType()) {
- val realReturnType = returnType.extractIntendedReturnType()
- val returnTypeInKotlin = methodBuilder.build().returnType.toString()
- if (returnType.isOptional()) {
- populateAndReturnOptionalFromCursor(
- methodBuilder, realReturnType,
- checkIfTypeArgumentIsNullable(returnTypeInKotlin)
- )
- } else if (returnType.isList()) {
- populateAndReturnListFromCursor(
- methodBuilder, realReturnType,
- checkIfTypeArgumentIsNullable(returnTypeInKotlin)
- )
- } else if (returnType.isSet()) {
- populateAndReturnSetFromCursor(
- methodBuilder, realReturnType,
- checkIfTypeArgumentIsNullable(returnTypeInKotlin)
- )
- }
- } else {
- returnNonPojoTypeFromCursor(methodBuilder, returnType)
- }
- }
-
- fun populateAndReturnListFromCursor(
- methodBuilder: FunSpec.Builder,
- realReturnType: TypeMirror,
- typeArgumentIsNullable: Boolean
- ) {
- methodBuilder.addStatement(
- "val _returnList = %T()",
- ClassName("kotlin.collections", "ArrayList").parameterizedBy(
- realReturnType
- .toKotlinClassName().copy(typeArgumentIsNullable)
- )
- )
- methodBuilder.beginControlFlow("while (_cursor.moveToNext())")
- createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
- // Check !realReturnType.isSupportedColumnType() because POJOs cannot be null, their
- // fields can be, but that's a different check. We only check nullability when the return
- // type is a supported cursor type (long, int, String etc...) Same goes for other
- // collections.
- if (typeArgumentIsNullable || !realReturnType.isSupportedColumnType()) {
- methodBuilder.addStatement(
- "_returnList.add($RETURN_OBJECT_NAME as %T)",
- realReturnType
- .toKotlinClassName()
- )
- } else {
- methodBuilder.beginControlFlow("if ($RETURN_OBJECT_NAME != null)")
- methodBuilder.addStatement(
- "_returnList.add($RETURN_OBJECT_NAME as %T)",
- realReturnType
- .toKotlinClassName()
- )
- methodBuilder.endControlFlow()
- }
- methodBuilder.endControlFlow()
- methodBuilder.addStatement(
- "$returnOrSet _returnList.toList() as ${methodBuilder.build()
- .returnType}"
- )
- }
-
- fun populateAndReturnSetFromCursor(
- methodBuilder: FunSpec.Builder,
- realReturnType: TypeMirror,
- typeArgumentIsNullable: Boolean
- ) {
- methodBuilder.addStatement(
- "val _returnSet = %T()",
- ClassName("kotlin.collections", "HashSet").parameterizedBy(
- realReturnType
- .toKotlinClassName().copy(typeArgumentIsNullable)
- ).copy()
- )
- methodBuilder.beginControlFlow("while (_cursor.moveToNext())")
- createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
- if (typeArgumentIsNullable || !realReturnType.isSupportedColumnType()) {
- methodBuilder.addStatement(
- "_returnSet.add($RETURN_OBJECT_NAME as %T)",
- realReturnType.toKotlinClassName()
- )
- } else {
- methodBuilder.beginControlFlow("if ($RETURN_OBJECT_NAME != null)")
- methodBuilder.addStatement(
- "_returnSet.add($RETURN_OBJECT_NAME as %T)",
- realReturnType.toKotlinClassName()
- )
- methodBuilder.endControlFlow()
- }
-
- methodBuilder.endControlFlow()
- methodBuilder.addStatement(
- "$returnOrSet _returnSet.toSet() as ${methodBuilder.build()
- .returnType}"
- )
- }
-
- fun populateAndReturnOptionalFromCursor(
- methodBuilder: FunSpec.Builder,
- realReturnType: TypeMirror,
- typeArgumentIsNullable: Boolean
- ) {
- if (typeArgumentIsNullable) {
- processingEnv.warn(
- "Type argument $realReturnType of java.util.Optional is marked as " +
- "nullable, an Optional cannot contain a null reference, instead it will be " +
- "empty.",
- contentQuery.method
- )
- }
- methodBuilder.beginControlFlow("if (_cursor.moveToNext())")
- createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
- methodBuilder.addStatement(
- "$returnOrSet %T.ofNullable($RETURN_OBJECT_NAME as %T) as %L",
- ClassName("java.util", "Optional").copy(), realReturnType.toKotlinClassName(),
- methodBuilder.build().returnType.toString()
- )
- methodBuilder.nextControlFlow("else")
- .addStatement(
- "$returnOrSet Optional.empty<%T>() as %L",
- realReturnType.toKotlinClassName(),
- methodBuilder.build().returnType.toString()
- )
- .endControlFlow()
- }
-
- fun returnNonPojoTypeFromCursor(
- methodBuilder: FunSpec.Builder,
- returnType: TypeMirror
- ) {
- methodBuilder.beginControlFlow("if (_cursor.moveToNext())")
- createReturnTypeFromCursor(returnType, methodBuilder, contentQuery.toQueryFor)
- methodBuilder.addStatement(
- "$returnOrSet $RETURN_OBJECT_NAME as ${methodBuilder.build()
- .returnType}"
- )
- methodBuilder.nextControlFlow("else")
- .addStatement("$returnOrSet null")
- .endControlFlow()
- }
-
- fun createReturnTypeFromCursor(
- realReturnType: TypeMirror,
- methodBuilder: FunSpec.Builder,
- columns: List<ContentColumnVO>
- ) {
- if (realReturnType.isSupportedColumnType()) {
- // This isn't a pojo but a single column, get that type directly.
- methodBuilder.beginControlFlow("val %L = if (_cursor.isNull(0))", RETURN_OBJECT_NAME)
- methodBuilder.addStatement("null")
- methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement("_cursor.${realReturnType.getCursorMethod()}(0)")
- methodBuilder.endControlFlow()
- return
- }
- val pojo = PojoProcessor(realReturnType).process()
- val pojoColumnsToFieldNames = pojo.pojoFields.map { it.columnName to it.name }.toMap()
- if (realReturnType.asTypeElement().hasNonEmptyNonPrivateNonIgnoredConstructor()) {
- val constructorParams = ArrayList<String>()
- val constructorFieldNames = realReturnType.asTypeElement()
- .getAllConstructorParamsOrPublicFields().map { it.simpleName.toString() }
-
- val fieldNameValueMap = mutableMapOf<String, String>()
- for (column in columns) {
- if (column.isNullable) {
- if (column.requiresApi != null) {
- methodBuilder.beginControlFlow(
- "val _${pojoColumnsToFieldNames
- .get(column.columnName)}_value = if (%T.VERSION.SDK_INT >= ${column
- .requiresApi})",
- buildClassPlaceHolder
- )
- methodBuilder.beginControlFlow(
- "if (_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))",
- column.columnName
- )
- methodBuilder.addStatement("null")
- methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement(
- "_cursor" +
- ".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName
- )
- methodBuilder.endControlFlow()
- methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement("null")
- methodBuilder.endControlFlow()
- } else {
- methodBuilder.beginControlFlow(
- "val _${pojoColumnsToFieldNames
- .get(column.columnName)}_value = if (_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))",
- column.columnName
- )
- methodBuilder.addStatement("null")
- methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement(
- "_cursor" +
- ".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName
- )
- methodBuilder.endControlFlow()
- }
- } else {
- // We do not check SDK_INT for this because we should not have non nullable
- // fields that were added in a later API to the provider. If that ever happens
- // the bug ought to be with the entity or if it's legitimate then weird but
- // okay, warrants a special exception.
- methodBuilder.beginControlFlow(
- "val _${pojoColumnsToFieldNames.get(
- column
- .columnName
- )}_value" +
- " = if (_cursor.isNull(_cursor.getColumnIndex(%S)))",
- column.columnName
- )
- methodBuilder.addStatement(
- "throw NullPointerException(%S)",
- "Column ${column
- .columnName} associated with field ${column.name} in $realReturnType " +
- "return null, however field ${column.name} is not nullable"
- )
- methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement(
- "_cursor" +
- ".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName
- )
- methodBuilder.endControlFlow()
- }
- fieldNameValueMap.put(
- pojoColumnsToFieldNames.get(column.columnName)!!,
- "_${pojoColumnsToFieldNames.get(column.columnName)!!}_value"
- )
- }
- for (field in constructorFieldNames) {
- if (field in fieldNameValueMap) {
- constructorParams.add(fieldNameValueMap.get(field)!!)
- } else {
- constructorParams.add("null")
- }
- }
-
- methodBuilder.addStatement(
- "val $RETURN_OBJECT_NAME = %T(%L)", realReturnType,
- constructorParams.joinToString(",")
- )
- } else {
- // We should instead assign to public fields directly.
- methodBuilder.addStatement("val $RETURN_OBJECT_NAME = %T()", realReturnType)
- for (column in columns) {
- if (column.isNullable) {
- if (column.requiresApi != null) {
- methodBuilder.beginControlFlow(
- "if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
- buildClassPlaceHolder
- )
- methodBuilder.beginControlFlow(
- "if (!_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))",
- column.columnName
- )
- methodBuilder.addStatement(
- "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
- .get(column.columnName)} =" +
- " _cursor.${column.type.getCursorMethod()}" +
- "(_cursor.getColumnIndex(%S))",
- column.columnName
- )
- methodBuilder.endControlFlow()
- methodBuilder.endControlFlow()
- } else {
- methodBuilder.beginControlFlow(
- "if (!_cursor.isNull(_cursor" +
- ".getColumnIndex(%S)))",
- column.columnName
- )
- methodBuilder.addStatement(
- "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
- .get(column.columnName)} =" +
- " _cursor.${column.type.getCursorMethod()}" +
- "(_cursor.getColumnIndex(%S))",
- column.columnName
- )
- methodBuilder.endControlFlow()
- }
- } else {
- methodBuilder.beginControlFlow(
- "if (_cursor.isNull(" +
- "_cursor.getColumnIndex(%S)))",
- column.columnName
- )
- methodBuilder.addStatement(
- "throw NullPointerException(%S)",
- "Column ${column
- .columnName} associated with field ${column.name} in $realReturnType " +
- "return null, however field ${column.name} is not nullable"
- )
- methodBuilder.nextControlFlow("else")
- methodBuilder.addStatement(
- "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
- .get(column.columnName)} = " +
- "_cursor.${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
- column.columnName
- )
- methodBuilder.endControlFlow()
- }
- }
- }
- }
-
- fun checkIfTypeArgumentIsNullable(returnTypeInKotlin: String): Boolean {
- // TODO(obenabde): Hummmm beatiful code... is there a better way to do this.
- return returnTypeInKotlin.substringAfterLast("<").substringBefore(">").endsWith("?")
- }
-}
-
-internal val RETURN_OBJECT_NAME = "_returnObject"
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
deleted file mode 100644
index fab312d..0000000
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler.writer
-
-import androidx.contentaccess.compiler.vo.ContentUpdateVO
-import com.squareup.kotlinpoet.AnnotationSpec
-import com.squareup.kotlinpoet.ClassName
-import com.squareup.kotlinpoet.FunSpec
-import com.squareup.kotlinpoet.MemberName
-import com.squareup.kotlinpoet.metadata.KotlinPoetMetadataPreview
-import javax.annotation.processing.ProcessingEnvironment
-
-class ContentUpdateMethodWriter(
- val processingEnv: ProcessingEnvironment,
- val contentUpdate: ContentUpdateVO
-) {
-
- val returnOrSet = if (contentUpdate.isSuspend) "" else "return "
- @KotlinPoetMetadataPreview
- fun createContentUpdateMethod(): FunSpec? {
- val uriTypePlaceHolder = ClassName("android.net", "Uri")
- val contentValuesPlaceHolder = ClassName("android.content", "ContentValues")
- val methodBuilder = funSpecOverriding(contentUpdate.method, processingEnv)
- methodBuilder.annotations.add(
- AnnotationSpec.builder(Suppress::class).addMember
- ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember(
- "%S",
- "PLATFORM_CLASS_MAPPED_TO_KOTLIN"
- ).build()
- )
- if (contentUpdate.isSuspend) {
- val withContext = MemberName("kotlinx.coroutines", "withContext")
- methodBuilder.beginControlFlow(
- "return %M(_queryExecutor)",
- withContext
- )
- }
- if (contentUpdate.uri.startsWith(":")) {
- methodBuilder.addStatement(
- "val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
- contentUpdate.uri.removePrefix(":")
- )
- } else {
- methodBuilder.addStatement(
- "val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
- contentUpdate.uri
- )
- }
- methodBuilder.addStatement(
- "val _contentValues = %T(${contentUpdate.toUpdate
- .size})",
- contentValuesPlaceHolder
- )
- for (value in contentUpdate.toUpdate) {
- methodBuilder.addStatement("_contentValues.put(\"${value.first}\", ${value.second})")
- }
- var noSelectionArgs = true
- if (contentUpdate.where != null) {
- methodBuilder.addStatement("val _where = %S", contentUpdate.where.selection)
- val selectionArgs = contentUpdate.where.selectionArgs
- val joinedSelectionArgs = if (selectionArgs.size == 1) {
- "${selectionArgs[0]}.toString()"
- } else {
- selectionArgs.map { r -> "$r.toString()" }.joinToString(",")
- }
- if (selectionArgs.isNotEmpty()) {
- noSelectionArgs = false
- methodBuilder.addStatement("val _selectionArgs = arrayOf($joinedSelectionArgs)")
- }
- } else {
- methodBuilder.addStatement("val _where = \"\"")
- }
- methodBuilder.addStatement(
- "${returnOrSet}_contentResolver.update(_uri, _contentValues, " +
- "_where, ${if (noSelectionArgs) "null" else "_selectionArgs"})"
- )
-
- if (contentUpdate.isSuspend) {
- methodBuilder.endControlFlow()
- }
- return methodBuilder.build()
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
deleted file mode 100644
index 18ea44b..0000000
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.compiler.processor.columnInSelectionMissingFromEntity
-import androidx.contentaccess.compiler.processor.contentDeleteAnnotatedMethodNotReturningAnInteger
-import androidx.contentaccess.compiler.processor.missingUriOnMethod
-import com.tschuchort.compiletesting.SourceFile
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ContentDeleteProcessorTest {
-
- val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
-
- fun generateMainSourceFile(accessorBody: String, entityWithoutUri: Boolean = false):
- SourceFile {
- return SourceFile.kotlin(
- "MyClass.kt",
- """
- package androidx.contentaccess.compiler.processor.test
-
- import androidx.contentaccess.ContentAccessObject
- import androidx.contentaccess.ContentPrimaryKey
- import androidx.contentaccess.ContentColumn
- import androidx.contentaccess.ContentDelete
- import androidx.contentaccess.ContentEntity
-
- @ContentEntity("uri")
- data class Entity(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("dtend")
- val endTime: Long,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentEntity
- data class EntityWithoutUri(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentAccessObject(${if (entityWithoutUri) "EntityWithoutUri::class" else
- "Entity::class"})
- interface ContentAccessor {
- $accessorBody
- }
- """
- )
- }
-
- @Test
- fun validDelete() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentDelete
- fun deleteAll(): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun validDeleteWithUriLessEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentDelete(uri = ":uri")
- fun deleteUriLessEntity(uri: String): Int?
- """.trimIndent(),
- true
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun checkThereIsAUriSomewhere() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentDelete
- fun deleteWithNoUri(): Int?
- """.trimIndent(),
- true
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingUriOnMethod())
- }
-
- @Test
- fun ensureContentEntityInAnnotationTakesPrecedence() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentDelete(contentEntity = EntityWithoutUri::class)
- fun deleteAll(): Int?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- // If this says no uri, that means it did indeed consider the EntityWithoutUri instead of
- // Entity.
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingUriOnMethod())
- }
-
- @Test
- fun ensureReturnsAnInt() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentDelete
- fun deleteAll(): String?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- contentDeleteAnnotatedMethodNotReturningAnInteger()
- )
- }
-
- @Test
- fun ensureColumnsInWhereExist() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentDelete(where = "unknown_column = :param")
- fun deleteAll(param: String): Int?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- columnInSelectionMissingFromEntity("unknown_column", entityName)
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
deleted file mode 100644
index 8f303ed..0000000
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.compiler.processor.entityFieldWithBothAnnotations
-import androidx.contentaccess.compiler.processor.entityWithMultipleConstructors
-import androidx.contentaccess.compiler.processor.entityWithNullablePrimitiveType
-import androidx.contentaccess.compiler.processor.missingAnnotationOnEntityFieldErrorMessage
-import androidx.contentaccess.compiler.processor.missingEntityPrimaryKeyErrorMessage
-import androidx.contentaccess.compiler.processor.missingFieldsInContentEntityErrorMessage
-import androidx.contentaccess.compiler.processor.nonInstantiableEntity
-import androidx.contentaccess.compiler.processor.unsupportedColumnType
-import com.tschuchort.compiletesting.KotlinCompilation
-import com.tschuchort.compiletesting.SourceFile
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ContentEntityProcessorTest {
-
- val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
-
- fun generateMainSourceFile(entityCode: String = ""): SourceFile {
- return SourceFile.kotlin(
- "MyClass.kt",
- """
- package androidx.contentaccess.compiler.processor.test
-
- import androidx.contentaccess.ContentAccessObject
- import androidx.contentaccess.ContentPrimaryKey
- import androidx.contentaccess.ContentColumn
- import androidx.contentaccess.ContentQuery
- import androidx.contentaccess.ContentEntity
-
- @ContentAccessObject(Entity::class)
- interface ContentAccessor {
- @ContentQuery
- fun getAll(): List<Entity>
- }
-
- $entityCode
- """
- )
- }
-
- fun generateJavaEntity(entityBody: String): SourceFile {
- return SourceFile.java(
- "Entity.java",
- """
- package androidx.contentaccess.compiler.processor.test;
-
- import org.jetbrains.annotations.Nullable;
- import androidx.contentaccess.ContentColumn;
- import androidx.contentaccess.ContentPrimaryKey;
- import androidx.contentaccess.IgnoreConstructor;
- import androidx.contentaccess.ContentEntity;
-
- @ContentEntity(uri = "uri")
- public class Entity {
- $entityBody
- }
- """.trimIndent()
- )
- }
-
- @Test
- fun validContentEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity(
- @ContentPrimaryKey("_id") val id: Int,
- @ContentColumn("a_random_long") val randomLong: Long
- )
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun validJavaContentEntity() {
- val mainSourceFile = generateMainSourceFile()
- val javaEntityFile = generateJavaEntity(
- """
- @ContentPrimaryKey(columnName = "_id")
- public long eventId;
-
- @ContentColumn(columnName = "dtstart")
- public long startTime;
-
- @ContentColumn(columnName = "dtend")
- @Nullable
- public Long endTime;
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(mainSourceFile, javaEntityFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun ensureExistingContentPrimaryKey() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity(
- @ContentColumn("_id") val id: Int,
- @ContentColumn("a_random_long") val randomLong: Long
- )
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingEntityPrimaryKeyErrorMessage(entityName))
- }
-
- @Test
- fun ensureEntityContainsFields() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity()
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingFieldsInContentEntityErrorMessage(entityName))
- }
-
- @Test
- fun ensureAllFieldsAreAnnotated() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity(
- val id: Int
- )
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages)
- .contains(missingAnnotationOnEntityFieldErrorMessage("id", entityName))
- }
-
- @Test
- fun ensureOnlyOneAnnotation() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity(
- @ContentPrimaryKey("_id")
- @ContentColumn("_id")
- val id: Int,
- @ContentColumn("a_random_long") val randomLong: Long
- )
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages)
- .contains(entityFieldWithBothAnnotations("id", entityName))
- }
-
- @Test
- fun ensureSupportedColumnType() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity(
- @ContentPrimaryKey("_id") val id: List<Long>,
- @ContentColumn("a_random_long") val randomLong: Long
- )
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages)
- .contains(unsupportedColumnType("id", entityName, "java.util.List<java.lang.Long>"))
- }
-
- @Test
- fun ensureSingleNonPrivateNonIgnoredConstructor() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentEntity("example.uri")
- data class Entity(
- @ContentPrimaryKey("_id") val id: Long,
- @ContentColumn("a_random_long") val randomLong: Long?
- ) {
- constructor(@ContentPrimaryKey("_id") id: Long) : this(id, null)
- }
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(entityWithMultipleConstructors(entityName))
- }
-
- @Test
- fun ensureInstantiableEntity() {
- val mainSourceFile = generateMainSourceFile()
- val javaEntitySourceFile = generateJavaEntity(
- """
- @ContentColumn(columnName = "_id")
- public long eventId;
-
- @ContentColumn(columnName = "dtstart")
- @Nullable
- public Long startTime;
-
- // This constructor should be ignored.
- @IgnoreConstructor
- public Entity(int randomParameter) {}
-
- private Entity() {}
- """.trimIndent()
- )
- val result = runCompilation(listOf(mainSourceFile, javaEntitySourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(nonInstantiableEntity(entityName))
- }
-
- @Test
- fun ensureNonNullablePrimitives() {
- val mainSourceFile = generateMainSourceFile()
- val javaEntitySourceFile = generateJavaEntity(
- """
- @ContentPrimaryKey(columnName = "_id")
- public long eventId;
-
- @ContentColumn(columnName = "dtstart")
- @Nullable
- public long startTime;
- """.trimIndent()
- )
- val result = runCompilation(listOf(mainSourceFile, javaEntitySourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- entityWithNullablePrimitiveType(
- "startTime",
- entityName
- )
- )
- }
-}
-
-fun runCompilation(sourceFiles: List<SourceFile>): KotlinCompilation.Result {
- return KotlinCompilation().apply {
- sources = sourceFiles
- annotationProcessors = listOf(ContentAccessProcessor())
- inheritClassPath = true
- verbose = false
- }.compile()
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
deleted file mode 100644
index a1b2ce7b..0000000
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.compiler.processor.contentInsertAnnotatedMethodNotReturningAUri
-import androidx.contentaccess.compiler.processor.insertMethodHasMoreThanOneEntity
-import androidx.contentaccess.compiler.processor.insertMethodHasNoEntityInParameters
-import androidx.contentaccess.compiler.processor.missingUriOnMethod
-import com.tschuchort.compiletesting.SourceFile
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ContentInsertProcessorTest {
-
- fun generateMainSourceFile(accessorBody: String):
- SourceFile {
- return SourceFile.kotlin(
- "MyClass.kt",
- """
- package androidx.contentaccess.compiler.processor.test
-
- import androidx.contentaccess.ContentAccessObject
- import androidx.contentaccess.ContentPrimaryKey
- import androidx.contentaccess.ContentColumn
- import androidx.contentaccess.ContentInsert
- import androidx.contentaccess.ContentEntity
- import android.net.Uri
-
- @ContentEntity("uri")
- data class Entity(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("dtend")
- val endTime: Long,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentEntity
- data class EntityWithoutUri(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentAccessObject
- interface ContentAccessor {
- $accessorBody
- }
- """
- )
- }
-
- @Test
- fun validInsert() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentInsert
- fun insertEntity(entity: Entity): Uri?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun validInsertWithUriLessEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentInsert(uri = ":uri")
- fun insertUriLessEntity(
- entity: EntityWithoutUri,
- uri: String
- ): Uri?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun checkThereIsAnEntityInParameters() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentInsert
- fun insertWithNoEntity(randomNonEntityParam: String): Uri?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(insertMethodHasNoEntityInParameters())
- }
-
- @Test
- fun checkNoMoreThanOneEntityInParameters() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentInsert
- fun insertMultipleEntities(entity1: Entity, entity2: Entity): Uri?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(insertMethodHasMoreThanOneEntity())
- }
-
- @Test
- fun ensureReturnTypeIsUri() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentInsert
- fun insertEntity(entity: Entity): Int?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- contentInsertAnnotatedMethodNotReturningAUri()
- )
- }
-
- @Test
- fun ensureUriExists() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentInsert
- fun insertEntity(entity: EntityWithoutUri): Int?
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- missingUriOnMethod()
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
deleted file mode 100644
index 2021d8f..0000000
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.compiler.processor.badlyFormulatedOrderBy
-import androidx.contentaccess.compiler.processor.columnInProjectionNotIncludedInReturnPojo
-import androidx.contentaccess.compiler.processor.columnOnlyAsUri
-import androidx.contentaccess.compiler.processor.constructorFieldNotIncludedInProjectionNotNullable
-import androidx.contentaccess.compiler.processor.missingEntityOnMethod
-import androidx.contentaccess.compiler.processor.missingUriOnMethod
-import androidx.contentaccess.compiler.processor.missingUriParameter
-import androidx.contentaccess.compiler.processor.nullableEntityColumnNotNullableInPojo
-import androidx.contentaccess.compiler.processor.pojoFieldNotInEntity
-import androidx.contentaccess.compiler.processor.pojoHasMoreThanOneQualifyingConstructor
-import androidx.contentaccess.compiler.processor.pojoIsNotInstantiable
-import androidx.contentaccess.compiler.processor.pojoWithNullablePrimitive
-import androidx.contentaccess.compiler.processor.queriedColumnInProjectionNotInEntity
-import androidx.contentaccess.compiler.processor.queriedColumnInProjectionTypeDoesntMatchReturnType
-import androidx.contentaccess.compiler.processor.uriParameterIsNotString
-import com.tschuchort.compiletesting.SourceFile
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ContentQueryProcessorTest {
-
- val entityName = "androidx.contentaccess.compiler.processor.test.EntityWithUri"
- val pojoName = "androidx.contentaccess.compiler.processor.test.Pojo"
-
- fun generateMainSourceFile(
- accessorBody: String,
- pojos: String = "",
- withEntity: Boolean = true
- ): SourceFile {
- return SourceFile.kotlin(
- "MyClass.kt",
- """
- package androidx.contentaccess.compiler.processor.test
-
- import androidx.contentaccess.ContentAccessObject
- import androidx.contentaccess.ContentPrimaryKey
- import androidx.contentaccess.ContentColumn
- import androidx.contentaccess.ContentQuery
- import androidx.contentaccess.ContentEntity
- import java.util.Optional
-
- @ContentEntity("uri")
- data class EntityWithUri(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentEntity
- data class EntityWithoutUri(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentAccessObject(${if (withEntity) "EntityWithUri::class" else ""})
- interface ContentAccessor {
- $accessorBody
- }
-
- $pojos
- """
- )
- }
-
- fun generateJavaPojo(pojoBody: String): SourceFile {
- return SourceFile.java(
- "Pojo.java",
- """
- package androidx.contentaccess.compiler.processor.test;
-
- import org.jetbrains.annotations.Nullable;
- import androidx.contentaccess.ContentColumn;
- import androidx.contentaccess.ContentPrimaryKey;
- import androidx.contentaccess.IgnoreConstructor;
-
- public class Pojo {
- $pojoBody
- }
- """.trimIndent()
- )
- }
-
- @Test
- fun validQueries() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAllStartTimeDescriptionAnnotatedPojo(): List<StartTimeDescription2>
-
- @ContentQuery(projection = arrayOf("dtstart", "description"))
- fun getAllStartTimeDescriptionNonAnnotatedPojoWithProjection(): List<StartTimeDescription1>
-
- @ContentQuery(projection = arrayOf("description"))
- fun getSingleColumnWithoutUsingPojo(): String?
-
- @ContentQuery(projection = arrayOf("description"))
- fun getSetOfSingleColumnResultsWithoutUsingPojo(): Set<String>
-
- @ContentQuery(projection = arrayOf("description"))
- fun getOptionalSingleColumn(): Optional<String?>
-
- @ContentQuery(projection = arrayOf("description"))
- fun getOptionalSingleColumnNonNullable(): Optional<String>
-
- @ContentQuery(projection = arrayOf("dtstart"),
- selection = "description = \"whatever\" and dtstart > 1010101010")
- fun getBasedOnSelectionWithoutParameter(): List<Long?>
-
- @ContentQuery(projection = arrayOf("dtstart"),
- selection = "description = :descr and dtstart > :startTime")
- fun getBasedOnSelectionWithParameter(descr: String, startTime: Long): List<Long?>
-
- @ContentQuery(projection = arrayOf("_id"), orderBy = arrayOf("dtstart", "description"))
- fun getAllOrderBy(descr: String): List<Long?>
-
- @ContentQuery(projection = arrayOf("_id"),
- orderBy = arrayOf("dtstart asc", "description desc"))
- fun getAllOrderByAscDesc(): List<Long?>
-
- @ContentQuery(projection = arrayOf("description"), uri = ":uriParam")
- fun getAllWithSpecifiedUriThroughParameter(uriParam: String): String?
-
- @ContentQuery(projection = arrayOf("description"), uri = "uri://inAnnotation:D")
- fun getAllWithSpecifiedUriInAnnotation(): String?
-
- @ContentQuery
- suspend fun getAllEntitiesSuspend(): List<EntityWithUri>
- """.trimIndent(),
- """
- data class StartTimeDescription1(
- @ContentColumn("dtstart") val startingTime: Long?,
- @ContentColumn("description") val theDescription: String?
- )
- // Field name should be considered as the column name since no @ContentColumn annotation
- data class StartTimeDescription2(
- val dtstart: Long?,
- val description: String?
- )
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun checkExistingEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAll(): List<String>
- """.trimIndent(),
- withEntity = false
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingEntityOnMethod("getAll"))
- }
-
- @Test
- fun checkingExistingUri() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(contentEntity = EntityWithoutUri::class)
- fun getAll(): List<String>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingUriOnMethod())
- }
-
- @Test
- fun missingOrderByColumn() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(orderBy = arrayOf("nonExistingColumn"))
- fun getAll(): List<String>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(badlyFormulatedOrderBy("nonExistingColumn"))
- }
-
- @Test
- fun badlyFormulatedOrderBy() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(orderBy = arrayOf("dtstart desc thisshouldntbehere"))
- fun getAll(): List<String>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- badlyFormulatedOrderBy(
- "dtstart desc " +
- "thisshouldntbehere"
- )
- )
- }
-
- @Test
- fun ensureExistingColumn() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(projection = arrayOf("nonExisting"))
- fun getAll(): List<String>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- queriedColumnInProjectionNotInEntity(
- "nonExisting",
- "androidx.contentaccess.compiler.processor.test.EntityWithUri"
- )
- )
- }
-
- @Test
- fun ensureMatchingReturnTypeNonPojo() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(projection = arrayOf("description"))
- fun getAll(): Long
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- queriedColumnInProjectionTypeDoesntMatchReturnType(
- "long",
- "java.lang.String",
- "description"
- )
- )
- }
-
- @Test
- // A "qualifying" constructor is a non private and non ignored constructor
- fun ensurePojoHasNoMoreThanOneQualifyingConstructor() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAll(): Pojo
- """.trimIndent()
- )
- val javaPojoFile = generateJavaPojo(
- """
- // Two public constructors
- public Pojo() {}
- public Pojo(int unused) {}
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile, javaPojoFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(pojoHasMoreThanOneQualifyingConstructor(pojoName))
- }
-
- @Test
- fun ensurePojoIsInstantiable() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAll(): Pojo
- """.trimIndent()
- )
- val javaPojoFile = generateJavaPojo(
- """
- // Two public constructors
- private Pojo() {}
- @IgnoreConstructor
- public Pojo(int unused) {}
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile, javaPojoFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(pojoIsNotInstantiable(pojoName))
- }
-
- @Test
- fun ensurePojoDoesntHaveANullablePrimitive() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAll(): Pojo
- """.trimIndent()
- )
- val javaPojoFile = generateJavaPojo(
- """
- @Nullable
- public long dtstart;
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile, javaPojoFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(pojoWithNullablePrimitive("dtstart", pojoName))
- }
-
- @Test
- fun ensurePojoFieldsMatchOnesInEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAll(): IncorrectPojo
- """.trimIndent(),
- """
- data class IncorrectPojo(@ContentColumn("irrelevant_column")val irrelevantField: String)
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- pojoFieldNotInEntity(
- "irrelevantField",
- "java.lang.String", "irrelevant_column",
- "androidx.contentaccess.compiler.processor.test.IncorrectPojo",
- entityName
- )
- )
- }
-
- @Test
- fun ensureFieldsNotInProjectionButInConstructorAreNullable() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(projection = arrayOf("dtstart"))
- fun getAll(): CustomPojo
- """.trimIndent(),
- """
- data class CustomPojo(val dtstart: Long?, val nonNullableField: Long)
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- constructorFieldNotIncludedInProjectionNotNullable(
- "nonNullableField",
- "androidx.contentaccess.compiler.processor.test.CustomPojo"
- )
- )
- }
-
- @Test
- fun ensurePojoContainsAllProjectionFields() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(projection = arrayOf("dtstart", "description"))
- fun getAll(): PojoMissingField
- """.trimIndent(),
- """
- data class PojoMissingField(val dtstart: Long?)
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- columnInProjectionNotIncludedInReturnPojo(
- "description",
- "androidx.contentaccess.compiler.processor.test.PojoMissingField"
- )
- )
- }
-
- @Test
- fun ensureNullableEntityFieldsAreAlsoNullableInPojo() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery
- fun getAll(): PojoWithNonNullableField
- """.trimIndent(),
- """
- data class PojoWithNonNullableField(val dtstart: Long)
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- nullableEntityColumnNotNullableInPojo(
- "dtstart",
- "long",
- "dtstart",
- entityName
- )
- )
- }
-
- @Test
- fun ensureUriParameterProperlySpecified() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(uri = ":")
- fun getAll(): List<EntityWithUri>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(columnOnlyAsUri())
- }
-
- @Test
- fun ensureUriParameterExists() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(uri = ":param")
- fun getAll(): List<EntityWithUri>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(missingUriParameter("param"))
- }
-
- @Test
- fun ensureUriParameterIsString() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(uri = ":param")
- fun getAll(param: Long): List<EntityWithUri>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(uriParameterIsNotString("param"))
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
deleted file mode 100644
index 5072e95..0000000
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.compiler.processor.columnInContentUpdateParametersNotInEntity
-import androidx.contentaccess.compiler.processor.contentUpdateAnnotatedMethodNotReturningAnInteger
-import androidx.contentaccess.compiler.processor.methodSpecifiesWhereClauseWhenUpdatingUsingEntity
-import androidx.contentaccess.compiler.processor.mismatchedColumnTypeForColumnToBeUpdated
-import androidx.contentaccess.compiler.processor.nullableUpdateParamForNonNullableEntityColumn
-import androidx.contentaccess.compiler.processor.unsureWhatToUpdate
-import androidx.contentaccess.compiler.processor.updatingMultipleEntitiesAtTheSameType
-import com.tschuchort.compiletesting.SourceFile
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ContentUpdateProcessorTest {
-
- val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
-
- fun generateMainSourceFile(accessorBody: String, entityWithoutUri: Boolean = false):
- SourceFile {
- return SourceFile.kotlin(
- "MyClass.kt",
- """
- package androidx.contentaccess.compiler.processor.test
-
- import androidx.contentaccess.ContentAccessObject
- import androidx.contentaccess.ContentPrimaryKey
- import androidx.contentaccess.ContentColumn
- import androidx.contentaccess.ContentUpdate
- import androidx.contentaccess.ContentEntity
-
- @ContentEntity("uri")
- data class Entity(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("dtend")
- val endTime: Long,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentEntity("uri")
- data class EntityWithoutUri(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentAccessObject(${if (entityWithoutUri) "EntityWithoutUri::class" else
- "Entity::class"})
- interface ContentAccessor {
- $accessorBody
- }
- """
- )
- }
-
- @Test
- fun validUpdates() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate
- fun updateDescription(@ContentColumn("description") desc: String): Int
-
- @ContentUpdate(where = "_id = :id", uri = ":uri")
- fun updateDescriptionAndStartTime(
- @ContentColumn("description") desc: String,
- @ContentColumn("dtstart") startTime: Long?,
- id: Long,
- uri: String
- ): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun validUpdatesWithUriLessEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate(where = "_id = 123", uri = ":uri")
- fun updateDescriptionWithUri(
- @ContentColumn("description") desc: String,
- uri: String
- ): Int
-
- @ContentUpdate(where = "_id = 123", contentEntity = Entity::class)
- fun updateDescription(
- @ContentColumn("description") desc: String
- ): Int
- """.trimIndent(),
- entityWithoutUri = true
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun checkColumnsExist() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate(where = "_id = :id")
- fun updateDescription(@ContentColumn("nonexistent") desc: String, id: Long): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- columnInContentUpdateParametersNotInEntity(
- "desc",
- "nonexistent", entityName
- )
- )
- }
-
- @Test
- fun ensureTypesMatch() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate
- fun updateDescription(@ContentColumn("description") desc: Long): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- mismatchedColumnTypeForColumnToBeUpdated(
- "desc",
- "description", "long", entityName, "java.lang.String"
- )
- )
- }
-
- @Test
- fun ensureNoWhereClauseWhenUpdatingEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate(where = "_id = 123")
- fun updateDescription(entityParam: Entity): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- methodSpecifiesWhereClauseWhenUpdatingUsingEntity("entityParam")
- )
- }
-
- @Test
- fun ensureOnlyOneEntityIsUpdatedAtTheSameTime() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate
- fun updateDescription(entityParam1: Entity, entityParam2: Entity): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- updatingMultipleEntitiesAtTheSameType(entityName, "updateDescription")
- )
- }
-
- @Test
- fun ensureContentUpdateMethodReturnsAnInteger() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate
- fun updateDescription(entityParam1: Entity): Long
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(contentUpdateAnnotatedMethodNotReturningAnInteger())
- }
-
- @Test
- fun ensureSomethingIsBeingUpdated() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate
- fun updateDescription(entities: List<Entity>): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(unsureWhatToUpdate())
- }
-
- @Test
- fun ensureNonNullableUpdateParametersForNonNullablEntityColumn() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentUpdate
- fun updateDescription(@ContentColumn("dtend") newEndTime: Long?): Int
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- nullableUpdateParamForNonNullableEntityColumn
- ("newEndTime", "dtend", entityName)
- )
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
deleted file mode 100644
index 449aaf5..0000000
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.compiler
-
-import androidx.contentaccess.compiler.processor.columnInSelectionMissingFromEntity
-import androidx.contentaccess.compiler.processor.findWordsStartingWithColumn
-import androidx.contentaccess.compiler.processor.selectionParameterNotInMethodParameters
-import androidx.contentaccess.compiler.processor.strayColumnInSelectionErrorMessage
-import com.tschuchort.compiletesting.SourceFile
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class SelectionProcessorTest {
-
- val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
-
- fun generateMainSourceFile(accessorBody: String): SourceFile {
- return SourceFile.kotlin(
- "MyClass.kt",
- """
- package androidx.contentaccess.compiler.processor.test
-
- import androidx.contentaccess.ContentAccessObject
- import androidx.contentaccess.ContentPrimaryKey
- import androidx.contentaccess.ContentColumn
- import androidx.contentaccess.ContentQuery
- import androidx.contentaccess.ContentEntity
-
- @ContentEntity("uri")
- data class Entity(
- @ContentPrimaryKey("_id")
- val id: Long,
- @ContentColumn("dtstart")
- val startTime: Long?,
- @ContentColumn("description")
- val description: String?
- )
-
- @ContentAccessObject(Entity::class)
- interface ContentAccessor {
- $accessorBody
- }
- """
- )
- }
-
- @Test
- fun validSelection() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(selection = "dtstart > 1 OR (dtstart < 5 AND description = \"abc\")" +
- " OR ((description = :parameter AND (dtstart * 6 = 30)))")
- fun getAll(parameter: String): List<Entity>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.OK)
- }
-
- @Test
- fun ensureNoStraySelectionColumns() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(selection = "dtstart = : AND description > :parameter")
- fun getAll(parameter: String): List<Entity>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(strayColumnInSelectionErrorMessage())
- }
-
- @Test
- fun ensureSelectionArgumentsAreSpecifiedInParameter() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(selection = "description > :parameter")
- fun getAll(): List<Entity>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(selectionParameterNotInMethodParameters("parameter"))
- }
-
- @Test
- fun ensureColumnsMentionedInSelectionExistInEntity() {
- val sourceFile = generateMainSourceFile(
- """
- @ContentQuery(selection = "unknown_column > 5")
- fun getAll(): List<Entity>
- """.trimIndent()
- )
-
- val result = runCompilation(listOf(sourceFile))
-
- assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
- assertThat(result.messages).contains(
- columnInSelectionMissingFromEntity("unknown_column", entityName)
- )
- }
-
- @Test
- fun findsWordsStartingWithColumnInSelectionProperly() {
- val selection1 = "a = :a and b = :b"
- val wordsStartingWithColumnFromSelection1 = listOf(":a", ":b")
- assertThat(findWordsStartingWithColumn(selection1))
- .containsExactlyElementsOf(wordsStartingWithColumnFromSelection1)
-
- val selection2 = "a=:a and b=:b"
- val wordsStartingWithColumnFromSelection2 = listOf(":a", ":b")
- assertThat(findWordsStartingWithColumn(selection2))
- .containsExactlyElementsOf(wordsStartingWithColumnFromSelection2)
-
- val selection3 = "uri!=:uriParam"
- assertThat(findWordsStartingWithColumn(selection3)).containsOnly(":uriParam")
-
- val selection4 = "col = 1 and col2 = 2"
- assertThat(findWordsStartingWithColumn(selection4)).isEmpty()
-
- val selection5 = "a = :"
- assertThat(findWordsStartingWithColumn(selection5)).containsOnly(":")
- }
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-entities/build.gradle b/contentaccess/contentaccess-entities/build.gradle
deleted file mode 100644
index 21ef6d4..0000000
--- a/contentaccess/contentaccess-entities/build.gradle
+++ /dev/null
@@ -1,41 +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 static androidx.build.dependencies.DependenciesKt.*
-import androidx.build.LibraryGroups
-import androidx.build.AndroidXExtension
-import androidx.build.Publish
-
-plugins {
- id("AndroidXPlugin")
- id("com.android.library")
- id("kotlin-android")
-}
-
-dependencies {
- implementation(project(":contentaccess:contentaccess-annotations"))
- implementation(KOTLIN_STDLIB)
- api("androidx.annotation:annotation:1.0.0")
-}
-
-androidx {
- name = "Android ContentAccess - Entities"
- publish = Publish.SNAPSHOT_ONLY
- mavenGroup = LibraryGroups.CONTENTACCESS
- inceptionYear = "2020"
- description = "Contains predefined entities which can be used with ContentAccess."
- legacyDisableKotlinStrictApiMode = true
-}
diff --git a/contentaccess/contentaccess-entities/src/main/AndroidManifest.xml b/contentaccess/contentaccess-entities/src/main/AndroidManifest.xml
deleted file mode 100644
index 2136206..0000000
--- a/contentaccess/contentaccess-entities/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.contentaccess.entities">
- <application/>
-</manifest>
diff --git a/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt b/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
deleted file mode 100644
index 8ecc18a..0000000
--- a/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
+++ /dev/null
@@ -1,895 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.entities
-
-import android.provider.MediaStore
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentEntity
-import androidx.contentaccess.ContentPrimaryKey
-import androidx.annotation.RequiresApi
-
-class ContentAccessMediaStore {
-
- // TODO(obenabde): Investigate whether some of the columns marked as nullable here
- // actually have any default values.
- // TODO(obenabde): Formalize the comments below into a kdoc.
- open class MediaColumns {
- // PLEASE READ IF YOU EXTEND THIS CLASS:
- // ANY CLASS THAT EXTENDS THIS CLASS SHOULD ADD ALL THE FOLLOWING COLUMNS WITH THE
- // @RequiresApi AT THE API IT EXTENDED THE CLASS AT. THESE CONSTANTS ARE CURRENTLY
- // IN MediaStore.MediaColumns HOWEVER THEY WERE IN A SUBSET OF THE SUBCLASSES BEFORE
- // AND WERE LATER PROMOTED TO THIS CLASS SO ALL SUBCLASSES NOW INHERIT THEM. TO MAINTAIN
- // THE APPROPRIATE @RequiresApi LEVELS, WE DON'T ACTUALLY ADD THESE CONSTANTS TO THIS CLASS
- // BUT WE ADD THEM TO ALL THE SUBCLASSES WITH THE APPROPRIATE @RequiresApi API.
- // Columns that were promoted later from sublasses are:
- // DATE_TAKEN FROM ImageColumns,VideoColumns AT 29
- // BUCKET_ID FROM ImageColumns,VideoColumns AT 29
- // BUCKET_DISPLAY_NAME FROM ImageColumns,VideoColumns AT 29
- // ORIENTATION FROM ImageColumns AT 29
- // DURATION FROM AudioColumns,VideoColumns AT 29
- // ARTIST FROM AudioColumns, VideoColumns AT 30
- // ALBUM FROM AudioColumns, VideoColumns AT 30
- // COMPOSER FROM AudioColumns AT 30
- // RESOLUTION FROM VideoColumns AT 30
- // ALSO THE FOLLOWING COLUMN WAS NOT PRESENT IN AUDIOCOLUMNS IT SEEMS, SO ALL OTHER CLASSES
- // SHOULD ADD THEM
- // WIDTH
- // HEIGHT
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @Deprecated(
- "Apps may not have filesystem permissions to directly access this path. " +
- "Instead of trying to open this path directly, apps should use " +
- "ContentResolver#openFileDescriptor(Uri, String) to gain access."
- )
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATA)
- public var data: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.IS_DRM)
- public var isDrm: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.IS_TRASHED)
- public var isTrashed: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.SIZE)
- public var size: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DISPLAY_NAME)
- public var displayName: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.TITLE)
- public var title: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_ADDED)
- public var dateAdded: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_MODIFIED)
- public var dateModified: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.MIME_TYPE)
- public var mimeType: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.IS_PENDING)
- public var isPending: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_EXPIRES)
- public var dateExpires: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.OWNER_PACKAGE_NAME)
- public var ownerPackageName: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.VOLUME_NAME)
- public var volumeName: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.RELATIVE_PATH)
- public var relativePath: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DOCUMENT_ID)
- public var documentId: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.INSTANCE_ID)
- public var instanceId: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ORIGINAL_DOCUMENT_ID)
- public var originalDocumentId: String? = null
- }
-
- open class ImageColumns : MediaColumns() {
- @JvmField
- @Deprecated(
- "As of API 29, this value was only relevant for images hosted on Picasa, " +
- "which are no longer supported."
- )
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.PICASA_ID)
- public var picasaId: String? = null
-
- @JvmField
- @Deprecated(
- "As of API 29, location details are no longer indexed for privacy reasons, " +
- "and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[])."
- )
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.LATITUDE)
- public var latitude: Float? = null
-
- @JvmField
- @Deprecated(
- "As of API 29, location details are no longer indexed for privacy reasons, " +
- "and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[])."
- )
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.LONGITUDE)
- public var longitude: Float? = null
-
- @JvmField
- @Deprecated(
- "As of API 29, all thumbnails should be obtained via MediaStore.Images" +
- ".Thumbnails#getThumbnail, as this value is no longer supported."
- )
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.MINI_THUMB_MAGIC)
- public var miniThumbMagic: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.DESCRIPTION)
- public var description: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.IS_PRIVATE)
- public var isPrivate: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.SCENE_CAPTURE_TYPE)
- public var sceneCaptureType: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.EXPOSURE_TIME)
- public var exposureTime: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.F_NUMBER)
- public var fNumber: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Images.ImageColumns.ISO)
- public var iso: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_TAKEN)
- public var dateTaken: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_ID)
- public var bucketId: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_DISPLAY_NAME)
- public var bucketDisplayName: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ORIENTATION)
- public var orientation: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DURATION)
- public var duration: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ALBUM)
- public var album: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.COMPOSER)
- public var composer: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.RESOLUTION)
- public var resolution: String? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.WIDTH)
- public var width: Int? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.HEIGHT)
- public var height: Int? = null
- }
-
- @ContentEntity("content://media/external/images/media")
- class Image : ImageColumns()
-
- open class ImageThumbnailColumns {
-
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @Deprecated(
- "Deprecated in API 29. Apps may not have filesystem permissions to directly " +
- "access this path. Instead of trying to open this path directly, apps should use " +
- "ContentResolver#loadThumbnail to gain access."
- )
- @ContentColumn(android.provider.MediaStore.Images.Thumbnails.DATA)
- public var data: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Images.Thumbnails.IMAGE_ID)
- public var imageId: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Images.Thumbnails.KIND)
- public var kind: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Images.Thumbnails.WIDTH)
- public var width: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Images.Thumbnails.HEIGHT)
- public var height: Int? = null
- }
-
- @Deprecated(
- "Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
- "richer control over requested thumbnail sizes and cancellationbehavior."
- )
- @ContentEntity("content://media/external/images/thumbnails")
- class ImageThumbnail : ImageThumbnailColumns()
-
- open class VideoThumbnailColumns {
-
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @Deprecated(
- "Deprecated in API 29. Apps may not have filesystem permissions to directly " +
- "access this path. Instead of trying to open this path directly, apps should use " +
- "ContentResolver#loadThumbnail to gain access."
- )
- @ContentColumn(android.provider.MediaStore.Video.Thumbnails.DATA)
- public var data: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.Thumbnails.VIDEO_ID)
- public var videoId: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.Thumbnails.KIND)
- public var kind: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.Thumbnails.WIDTH)
- public var width: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.Thumbnails.HEIGHT)
- public var height: Int? = null
- }
-
- @Deprecated(
- "Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
- "richer control over requested thumbnail sizes and cancellationbehavior."
- )
- @ContentEntity("content://media/external/video/thumbnails")
- class VideoThumbnail : VideoThumbnailColumns()
-
- open class VideoColumns : MediaColumns() {
- @JvmField
- @Deprecated(
- "As of API 29, location details are no longer indexed for privacy reasons, " +
- "and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[])."
- )
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.LATITUDE)
- public var latitude: Float? = null
-
- @JvmField
- @Deprecated(
- "As of API 29, location details are no longer indexed for privacy reasons, " +
- "and this value is now always null. You can still manually obtain location " +
- "metadata using ExifInterface#getLatLong(float[])."
- )
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.LONGITUDE)
- public var longitude: Float? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.DESCRIPTION)
- public var description: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.IS_PRIVATE)
- public var isPrivate: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.TAGS)
- public var tags: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.CATEGORY)
- public var category: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.LANGUAGE)
- public var language: String? = null
-
- @JvmField
- @Deprecated(
- "As for API 29, all thumbnails should be obtained via MediaStore.Images" +
- ".Thumbnails#getThumbnail, as this value is no longer supported."
- )
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.MINI_THUMB_MAGIC)
- public var miniThumbMagic: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.BOOKMARK)
- public var bookmark: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.COLOR_STANDARD)
- public var colorStandard: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.COLOR_TRANSFER)
- public var colorTransfer: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Video.VideoColumns.COLOR_RANGE)
- public var colorRange: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_TAKEN)
- public var dateTaken: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_ID)
- public var bucketId: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_DISPLAY_NAME)
- public var bucketDisplayName: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ORIENTATION)
- @RequiresApi(29)
- public var orientation: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DURATION)
- public var duration: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ALBUM)
- public var album: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.COMPOSER)
- public var composer: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.RESOLUTION)
- public var resolution: String? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.WIDTH)
- public var width: Int? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.HEIGHT)
- public var height: Int? = null
- }
-
- @ContentEntity("content://media/external/video/media")
- class Video : VideoColumns()
-
- open class AudioColumns : MediaColumns() {
- @JvmField
- @Deprecated(
- "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
- "means they don't reflect locale-specific sorting preferences. To apply " +
- "locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. "
- )
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.TITLE_KEY)
- public var titleKey: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.BOOKMARK)
- public var bookmark: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ARTIST_ID)
- public var artistId: Int? = null
-
- @JvmField
- @Deprecated(
- "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
- "means they don't reflect locale-specific sorting preferences. To apply " +
- "locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. "
- )
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ARTIST_KEY)
- public var artistKey: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ALBUM_ID)
- public var albumId: Int? = null
-
- @JvmField
- @Deprecated(
- "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
- "means they don't reflect locale-specific sorting preferences. To apply " +
- "locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. "
- )
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ALBUM_KEY)
- public var albumKey: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.TRACK)
- public var track: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.YEAR)
- public var year: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.IS_MUSIC)
- public var isMusic: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.IS_PODCAST)
- public var isPodcast: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.IS_RINGTONE)
- public var isRingtone: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.IS_ALARM)
- public var isAlarm: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.IS_NOTIFICATION)
- public var isNotification: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.GENRE)
- public var genre: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.GENRE_ID)
- public var genreId: Int? = null
-
- @JvmField
- @Deprecated(
- "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
- "means they don't reflect locale-specific sorting preferences. To apply " +
- "locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE. "
- )
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.GENRE_KEY)
- public var genreKey: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.TITLE_RESOURCE_URI)
- public var titleResourceUri: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.IS_AUDIOBOOK)
- public var isAudioBook: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_TAKEN)
- public var dateTaken: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_ID)
- public var bucketId: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_DISPLAY_NAME)
- public var bucketDisplayName: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ORIENTATION)
- @RequiresApi(29)
- public var orientation: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.DURATION)
- public var duration: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ALBUM)
- public var album: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.COMPOSER)
- public var composer: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.RESOLUTION)
- public var resolution: String? = null
- }
-
- @ContentEntity("content://media/external/audio/media")
- class Audio : AudioColumns()
-
- open class AlbumColumns {
-
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM)
- public var album: String? = null
-
- @JvmField
- @Deprecated(
- "This constant was deprecated in API level 29. Apps may not have filesystem " +
- "permissions to directly access this path. Instead of trying to open this path " +
- "directly, apps should use ContentResolver#loadThumbnail to gain access."
- )
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_ART)
- public var albumArt: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_ID)
- public var albumId: Int? = null
-
- @JvmField
- @Deprecated(
- "This constant was deprecated in API level 30. These keys are generated using" +
- " Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
- ". To apply locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE."
- )
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_KEY)
- public var albumKey: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ARTIST_ID)
- public var artistId: Int? = null
-
- @JvmField
- @Deprecated(
- "This constant was deprecated in API level 30. These keys are generated using" +
- " Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
- ". To apply locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE."
- )
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ARTIST_KEY)
- public var artistKey: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.FIRST_YEAR)
- public var firstYear: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.LAST_YEAR)
- public var lastYear: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS)
- public var numberOfSongs: Int? = null
- // This is commented out because it doesn't really seem to be a column? It's in the
- // documentation but the resolver says it doesn't exist.
-// @JvmField
-// @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS_FOR_ARTIST)
-// public var numberOfSongsForArtist: Int? = null
- }
-
- @ContentEntity("content://media/external/audio/albums")
- class Album : AlbumColumns()
-
- open class ArtistColumns {
-
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @Deprecated(
- "This constant was deprecated in API level 30. These keys are generated using" +
- " Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
- ". To apply locale-specific sorting preferences, use " +
- "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
- "ContentResolver#QUERY_ARG_SORT_LOCALE."
- )
- @ContentColumn(android.provider.MediaStore.Audio.ArtistColumns.ARTIST_KEY)
- public var artistKey: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.ArtistColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.ArtistColumns.NUMBER_OF_ALBUMS)
- public var numberOfAlbums: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.ArtistColumns.NUMBER_OF_TRACKS)
- public var numberOfTracks: Int? = null
- }
-
- @ContentEntity("content://media/external/audio/artists")
- class Artist : ArtistColumns()
-
- open class GenresColumns {
-
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.GenresColumns.NAME)
- public var name: String? = null
- }
-
- @ContentEntity("content://media/external/audio/genres")
- class Genre : GenresColumns()
-
- open class PlaylistColumns {
-
- @JvmField
- @ContentPrimaryKey("_id")
- public var _id: Int? = null
-
- @JvmField
- @Deprecated(
- "This constant was deprecated in API level 29. Apps may not have filesystem " +
- "permissions to directly access this path. Instead of trying to open this path " +
- "directly, apps should use ContentResolver#openFileDescriptor(Uri, String) to " +
- "gain access."
- )
- @ContentColumn(android.provider.MediaStore.Audio.PlaylistsColumns.DATA)
- public var data: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.PlaylistsColumns.DATE_ADDED)
- public var dateAdded: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.PlaylistsColumns.DATE_MODIFIED)
- public var dateModified: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Audio.PlaylistsColumns.NAME)
- public var name: String? = null
- }
-
- @ContentEntity("content://media/external/audio/playlists")
- class Playlist : PlaylistColumns()
-
- open class DownloadColumns : MediaColumns() {
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.DownloadColumns.REFERER_URI)
- public var refererUri: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.DownloadColumns.DOWNLOAD_URI)
- public var downloadUri: String? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_TAKEN)
- public var dateTaken: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_ID)
- public var bucketId: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_DISPLAY_NAME)
- public var bucketDisplayName: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ORIENTATION)
- @RequiresApi(29)
- public var orientation: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ALBUM)
- public var album: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.COMPOSER)
- public var composer: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.RESOLUTION)
- public var resolution: String? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.WIDTH)
- public var width: Int? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.HEIGHT)
- public var height: Int? = null
- }
-
- @ContentEntity("content://media/external/downloads")
- @RequiresApi(29)
- class Download : DownloadColumns()
-
- open class FileColumns : MediaColumns() {
- @JvmField
- @ContentColumn(android.provider.MediaStore.Files.FileColumns.PARENT)
- public var parent: Int? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE)
- public var mediaType: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DATE_TAKEN)
- public var dateTaken: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_ID)
- public var bucketId: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.BUCKET_DISPLAY_NAME)
- public var bucketDisplayName: String? = null
-
- @JvmField
- @ContentColumn(android.provider.MediaStore.MediaColumns.ORIENTATION)
- @RequiresApi(29)
- public var orientation: Int? = null
-
- @JvmField
- @RequiresApi(29)
- @ContentColumn(android.provider.MediaStore.MediaColumns.DURATION)
- public var duration: Int? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ARTIST)
- public var artist: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.ALBUM)
- public var album: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.COMPOSER)
- public var composer: String? = null
-
- @JvmField
- @RequiresApi(30)
- @ContentColumn(android.provider.MediaStore.MediaColumns.RESOLUTION)
- public var resolution: String? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.WIDTH)
- public var width: Int? = null
-
- @JvmField
- @RequiresApi(16)
- @ContentColumn(android.provider.MediaStore.MediaColumns.HEIGHT)
- public var height: Int? = null
- }
-
- @ContentEntity
- class File : FileColumns()
-}
\ No newline at end of file
diff --git a/contentaccess/contentaccess-runtime/build.gradle b/contentaccess/contentaccess-runtime/build.gradle
deleted file mode 100644
index a7172c1..0000000
--- a/contentaccess/contentaccess-runtime/build.gradle
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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 static androidx.build.dependencies.DependenciesKt.*
-import androidx.build.LibraryGroups
-import androidx.build.AndroidXExtension
-import androidx.build.Publish
-
-plugins {
- id("AndroidXPlugin")
- id("com.android.library")
- id("kotlin-android")
-}
-
-dependencies {
- implementation(KOTLIN_STDLIB)
- api(KOTLIN_COROUTINES_ANDROID)
- implementation("androidx.arch.core:core-runtime:2.0.1")
-}
-
-androidx {
- name = "Android ContentAccess - Runtime"
- publish = Publish.SNAPSHOT_ONLY
- mavenGroup = LibraryGroups.CONTENTACCESS
- inceptionYear = "2019"
- description = "This library is the runtime component for ContentAccess, a Jetpack library for" +
- " simplifying ContentProvider usage."
-}
diff --git a/contentaccess/contentaccess-runtime/src/main/AndroidManifest.xml b/contentaccess/contentaccess-runtime/src/main/AndroidManifest.xml
deleted file mode 100644
index b6d5c2f..0000000
--- a/contentaccess/contentaccess-runtime/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.contentaccess">
- <application/>
-</manifest>
diff --git a/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt b/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
deleted file mode 100644
index 44befaa..0000000
--- a/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess
-
-import android.content.ContentResolver
-import kotlin.reflect.KClass
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.asCoroutineDispatcher
-import androidx.arch.core.executor.ArchTaskExecutor
-import java.util.concurrent.Executor
-
-public class ContentAccess {
- public companion object {
- @Suppress("UNCHECKED_CAST")
- public fun <T : Any> getAccessor(
- contentAccessObject: KClass<T>,
- contentResolver: ContentResolver,
- queryExecutor: Executor = ArchTaskExecutor.getIOThreadExecutor()
- ): T {
- val packageName = contentAccessObject.java.`package`!!.name
- // We do this instead of getting the simple name of the class in case of nested classes.
- val generatedClassName = "${contentAccessObject.qualifiedName!!
- .removePrefix(packageName).replace(".", "_")}Impl"
- try {
- val cl = Class.forName("$packageName.$generatedClassName")
- val constructor = cl.getConstructor(
- ContentResolver::class.java,
- CoroutineDispatcher::class.java
- )
- return constructor.newInstance(
- contentResolver,
- queryExecutor
- .asCoroutineDispatcher()
- ) as T
- } catch (e: ClassNotFoundException) {
- error(
- "Cannot find generated class for content accessor ${contentAccessObject
- .qualifiedName}, this is most likely because the class is not annotated " +
- "with @ContentAccessObject or because the contentaccess-compiler " +
- "annotation processor was not ran properly."
- )
- } catch (e: InstantiationException) {
- error(
- "Unable to instantiate implementation $packageName.$generatedClassName of " +
- "${contentAccessObject.qualifiedName}."
- )
- }
- }
- }
-}
diff --git a/contentaccess/integration-tests/testapp/build.gradle b/contentaccess/integration-tests/testapp/build.gradle
deleted file mode 100644
index 2d25e69..0000000
--- a/contentaccess/integration-tests/testapp/build.gradle
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 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 static androidx.build.dependencies.DependenciesKt.*
-
-plugins {
- id("AndroidXPlugin")
- id("com.android.application")
- id("kotlin-android")
- id("kotlin-android-extensions")
- id("kotlin-kapt")
-}
-
-android {
- buildTypes {
- release {
- minifyEnabled true
- shrinkResources true
- }
- }
-}
-
-dependencies {
- implementation("androidx.annotation:annotation:1.1.0")
- implementation(project(":contentaccess:contentaccess-annotations"))
- implementation(project(":contentaccess:contentaccess-entities"))
- implementation(project(":contentaccess:contentaccess-runtime"))
- kapt(project(":contentaccess:contentaccess-compiler"))
- implementation(KOTLIN_STDLIB)
- androidTestImplementation(TRUTH)
- kaptAndroidTest(project(":contentaccess:contentaccess-compiler"))
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
- androidTestImplementation(ANDROIDX_TEST_CORE)
- androidTestImplementation(ANDROIDX_TEST_RUNNER)
- androidTestImplementation(ANDROIDX_TEST_RULES)
-}
\ No newline at end of file
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/AndroidManifest.xml b/contentaccess/integration-tests/testapp/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index 7550603..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.contentaccess.integration.testapp"
- android:sharedUserId="androidx.contentaccess.integration.testapp.uid">
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <application />
-</manifest>
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContactsBasedTest.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContactsBasedTest.kt
deleted file mode 100644
index c5e24d6..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContactsBasedTest.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp
-
-import android.Manifest
-import android.content.ContentValues
-import android.provider.ContactsContract
-import android.provider.ContactsContract.RawContacts
-import android.provider.ContactsContract.Contacts.DISPLAY_NAME
-import android.provider.ContactsContract.Contacts.DISPLAY_NAME_SOURCE
-import androidx.test.filters.MediumTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-
-@MediumTest
-open class ContactsBasedTest {
-
- val contentResolver =
- InstrumentationRegistry.getInstrumentation().context.contentResolver
-
- @get:Rule
- var storagePermissions =
- GrantPermissionRule.grant(
- Manifest.permission.READ_CONTACTS,
- Manifest.permission
- .WRITE_CONTACTS
- )!!
-
- @Before
- fun setup() {
- val values = ContentValues().apply {
- putNull(RawContacts.ACCOUNT_TYPE)
- putNull(RawContacts.ACCOUNT_NAME)
- }
- val uri1 = contentResolver.insert(RawContacts.CONTENT_URI, values)!!
- val uri2 = contentResolver.insert(RawContacts.CONTENT_URI, values)!!
- values.clear()
- values.apply {
- put(DISPLAY_NAME, "displayName1")
- put(DISPLAY_NAME_SOURCE, "displayNameSource1")
- }
- contentResolver.update(uri1, values, null, null)
- values.clear()
- values.apply {
- put(DISPLAY_NAME, "displayName2")
- put(DISPLAY_NAME_SOURCE, "displayNameSource2")
- }
- contentResolver.update(uri2, values, null, null)
- }
-
- @After
- fun deleteAllAdded() {
- // For the tests to work properly in terms of the expected results, the provider should not
- // have prior rows, so make sure we delete everything at the end of the tests for proper
- // local testing.
- contentResolver.delete(ContactsContract.Data.CONTENT_URI, "", null)
- contentResolver.delete(RawContacts.CONTENT_URI, "", null)
- }
-}
\ No newline at end of file
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentDeleteTest.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentDeleteTest.kt
deleted file mode 100644
index c0efdb2..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentDeleteTest.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp
-
-import android.Manifest
-import android.content.ContentResolver
-import android.content.ContentValues
-import android.provider.MediaStore
-import android.provider.MediaStore.Images.Media.MIME_TYPE
-import android.provider.MediaStore.Images.Media.DATE_TAKEN
-import androidx.contentaccess.ContentAccess
-import androidx.contentaccess.entities.ContentAccessMediaStore.Image
-import androidx.contentaccess.entities.ContentAccessMediaStore.Video
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.ContentDelete
-import androidx.test.filters.MediumTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.runBlocking
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-
-@MediumTest
-class ContentDeleteTest {
-
- val contentResolver: ContentResolver =
- InstrumentationRegistry.getInstrumentation().context.contentResolver
- private val imageAccessor = ContentAccess.getAccessor(ImageAccessor::class, contentResolver)
-
- @JvmField
- @Rule
- var storagePermissions =
- GrantPermissionRule.grant(
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- )!!
-
- @Before
- fun setup() {
- val imageValues = ContentValues().apply {
- put(MediaStore.Images.Media.TITLE, "title1")
- put(MediaStore.Images.Media.DESCRIPTION, "description1")
- put(MIME_TYPE, "image/jpeg")
- put(DATE_TAKEN, 1000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues)
-
- imageValues.apply {
- put(MediaStore.Images.Media.TITLE, "title2")
- put(MediaStore.Images.Media.DESCRIPTION, "description2")
- put(MIME_TYPE, "image/jpeg")
- put(DATE_TAKEN, 2000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues)
-
- imageValues.apply {
- put(MediaStore.Images.Media.TITLE, "title3")
- put(MediaStore.Images.Media.DESCRIPTION, "description3")
- put(MIME_TYPE, "image/png")
- put(DATE_TAKEN, 3000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues)
-
- val videoValues = ContentValues().apply {
- put(MediaStore.Video.Media.TITLE, "title4")
- put(MediaStore.Video.Media.DESCRIPTION, "description4")
- put(MIME_TYPE, "video/mp4")
- put(MediaStore.Video.Media.DATE_TAKEN, 4000L)
- }
- contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, videoValues)
- }
-
- @After
- fun deleteAllAdded() {
- contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "", null)
- contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "", null)
- }
-
- @ContentAccessObject(Image::class)
- interface ImageAccessor {
- @ContentDelete
- fun deleteAll(): Int
-
- @ContentDelete
- suspend fun deleteAllSuspend(): Int
-
- @ContentDelete(where = "$MIME_TYPE != 'image/png'")
- fun deleteItemsWithWhereArgument(): Int
-
- @ContentDelete(where = "$DATE_TAKEN < :date")
- fun deleteItemsWithWhereParameter(date: Long): Int
-
- @ContentDelete(contentEntity = Video::class)
- fun deleteItemsFromDifferentEntity(): Int
-
- @ContentDelete(uri = "content://media/external/images/media")
- fun deleteItemsWithUriArgument(): Int
- }
-
- @Test
- fun testDeleteAllItems() {
- val beforeDeletionCursor = contentResolver.query(
- MediaStore.Images.Media
- .EXTERNAL_CONTENT_URI,
- arrayOf(MediaStore.Images.Media.TITLE), null, null, null
- )!!
- assertThat(beforeDeletionCursor.count).isEqualTo(3)
- assertThat(imageAccessor.deleteAll()).isEqualTo(3)
- val afterDeletionCursor = contentResolver.query(
- MediaStore.Images.Media
- .EXTERNAL_CONTENT_URI,
- arrayOf(MediaStore.Images.Media.TITLE), null, null, null
- )!!
- assertThat(afterDeletionCursor.count).isEqualTo(0)
- }
-
- @Test
- fun testDeleteAllItemsSuspend() {
- runBlocking {
- assertThat(imageAccessor.deleteAllSuspend()).isEqualTo(3)
- }
- }
-
- @Test
- fun testDeleteItemsWithWhereArgument() {
- assertThat(imageAccessor.deleteItemsWithWhereArgument()).isEqualTo(2)
- }
-
- @Test
- fun testDeleteItemsWithWhereParameter() {
- assertThat(imageAccessor.deleteItemsWithWhereParameter(date = 3000L)).isEqualTo(2)
- }
-
- @Test
- fun testDeleteItemsWithUriArgument() {
- assertThat(imageAccessor.deleteItemsWithUriArgument()).isEqualTo(3)
- }
-}
\ No newline at end of file
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentInsertTest.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentInsertTest.kt
deleted file mode 100644
index 498be8c..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentInsertTest.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 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.
- */
-package androidx.contentaccess.integration.testapp
-import android.Manifest
-import android.content.ContentResolver
-import android.net.Uri
-import android.provider.MediaStore
-import androidx.contentaccess.ContentAccess
-import androidx.contentaccess.entities.ContentAccessMediaStore.Image
-import androidx.contentaccess.entities.ContentAccessMediaStore.Video
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.ContentInsert
-import androidx.test.filters.MediumTest
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.runBlocking
-import org.junit.After
-import org.junit.Rule
-import org.junit.Test
-@MediumTest
-class ContentInsertTest {
-
- val contentResolver: ContentResolver =
- InstrumentationRegistry.getInstrumentation().context.contentResolver
- private val imageAccessor = ContentAccess.getAccessor(ImageAccessor::class, contentResolver)
-
- @JvmField
- @Rule
- var storagePermissions =
- GrantPermissionRule.grant(
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- )!!
-
- @After
- fun deleteAllAdded() {
- contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "", null)
- contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "", null)
- }
-
- @ContentAccessObject(Image::class)
- interface ImageAccessor {
- @ContentInsert
- fun insertItem(image: Image): Uri?
- @ContentInsert
- suspend fun insertItemSuspend(image: Image): Uri?
- @ContentInsert(uri = "content://media/external/images/media")
- fun insertItemWithUriArgument(image: ImageNoUri): Uri?
- @ContentInsert
- fun insertDifferentItem(video: Video): Uri?
- }
-
- @Test
- fun testInsertItem() {
- val newItem = Image()
- newItem.title = "Title1"
- newItem.description = "Description1"
- newItem.mimeType = "image/png"
- newItem.dateTaken = 1000
- val newUri = imageAccessor.insertItem(image = newItem)!!
- val cursor = contentResolver.query(newUri, null, null, null, null)!!
- val titleIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.TITLE)
- val descriptionIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DESCRIPTION)
- val mimeTypeIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.MIME_TYPE)
- val dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN)
- cursor.moveToFirst()
- assertThat(cursor.getString(titleIndex)).isEqualTo("Title1")
- assertThat(cursor.getString(descriptionIndex)).isEqualTo("Description1")
- assertThat(cursor.getString(mimeTypeIndex)).isEqualTo("image/png")
- assertThat(cursor.getInt(dateTakenIndex)).isEqualTo(1000)
- }
-
- @Test
- fun testInsertItemSuspend() {
- val newItem = Image()
- newItem.title = "Title1"
- newItem.description = "Description1"
- newItem.mimeType = "image/png"
- newItem.dateTaken = 1000
- runBlocking {
- assertThat(imageAccessor.insertItem(image = newItem)).isNotNull()
- }
- }
-
- @Test
- fun testInsertItemWithUriArgument() {
- val newItem = ImageNoUri(
- iD = null,
- title = "Title1",
- description = "Description1",
- mimeType = "image/png",
- dateAdded = null,
- dateTaken = null
- )
- val newUri = imageAccessor.insertItemWithUriArgument(image = newItem)!!
- assertThat(
- newUri.toString().startsWith(prefix = "content://media/external/images/media")
- ).isEqualTo(true)
- }
-
- @Test
- fun testInsertDifferentItem() {
- val newVideo = Video()
- newVideo.title = "Title1"
-
- val newUri = imageAccessor.insertDifferentItem(video = newVideo)!!
- val cursor = contentResolver.query(newUri, null, null, null, null)!!
- val titleIndex = cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE)
- cursor.moveToFirst()
- assertThat(cursor.getString(titleIndex)).isEqualTo("Title1")
- }
-}
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentQueryTest.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentQueryTest.kt
deleted file mode 100644
index 60612ec..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentQueryTest.kt
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp
-
-import com.google.common.truth.Truth.assertThat
-
-import android.Manifest
-import android.content.ContentValues
-import android.os.Build
-import android.provider.MediaStore
-import android.provider.MediaStore.Images.Media.DESCRIPTION
-import android.provider.MediaStore.Images.Media.TITLE
-import androidx.contentaccess.ContentAccess
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.entities.ContentAccessMediaStore.Image
-import androidx.contentaccess.entities.ContentAccessMediaStore.Video
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentQuery
-import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import java.util.Optional
-import kotlinx.coroutines.runBlocking
-
-@MediumTest
-class ContentQueryTest {
-
- val contentResolver =
- InstrumentationRegistry.getInstrumentation().context.contentResolver
- val imageAccessor = ContentAccess.getAccessor(ImageAccessor::class, contentResolver)
-
- @JvmField
- @Rule
- var storagePermissions =
- GrantPermissionRule.grant(
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission
- .WRITE_EXTERNAL_STORAGE
- )!!
-
- @Before
- fun setup() {
- val imageValues = ContentValues().apply {
- put(TITLE, "title1")
- put(DESCRIPTION, "description1")
- put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.DATE_TAKEN, 100000)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues)
-
- imageValues.apply {
- put(TITLE, "title2")
- put(DESCRIPTION, "description2")
- put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.DATE_TAKEN, 2000)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageValues)
- }
-
- @After
- fun deleteAllAdded() {
- // TODO(obenabde): create a rule that results in specified URIs being cleared
- // after tests (and asserted cleared.)
- // For the tests to work properly in terms of the expected results, the provider should not
- // have prior rows, so make sure we delete everything at the end of the tests for proper
- // local testing.
- contentResolver.delete(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- MediaStore.Images.Media.MIME_TYPE + "=?", arrayOf("image/jpeg")
- )
- contentResolver.delete(
- MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
- "", null
- )
- }
-
- @ContentAccessObject(Image::class)
- interface ImageAccessor {
- @ContentQuery
- fun getSingleEntity(): Image?
-
- @ContentQuery
- suspend fun getSingleEntitySuspend(): Image?
-
- @ContentQuery(contentEntity = Video::class)
- fun getSingleVideo(): Video?
-
- @ContentQuery
- fun getSingleEntityAsOptional(): Optional<Image>
-
- @ContentQuery
- suspend fun getSingleEntityAsOptionalSuspend(): Optional<Image>
-
- @ContentQuery
- fun getAllEntitiesAsList(): List<Image>
-
- @ContentQuery
- suspend fun getAllEntitiesAsListSuspend(): List<Image>
-
- @ContentQuery
- fun getAllEntitiesAsSet(): Set<Image>
-
- @ContentQuery
- suspend fun getAllEntitiesAsSetSuspend(): Set<Image>
-
- @ContentQuery
- fun getSinglePojo(): TitleDescriptionPojo?
-
- @ContentQuery
- fun getSingleAnnotatedPojo(): TitleDescriptionAnnotatedPojo?
-
- @ContentQuery
- fun getSinglePojoAsOptional(): Optional<TitleDescriptionPojo>
-
- @ContentQuery
- fun getAllPojosAsList(): List<TitleDescriptionPojo>
-
- @ContentQuery
- fun getAllPojosAsSet(): Set<TitleDescriptionPojo>
-
- @ContentQuery(projection = arrayOf(TITLE))
- fun getSingleColumn(): String?
-
- @ContentQuery(projection = arrayOf(TITLE))
- fun getSingleColumnOptional(): Optional<String>
-
- @ContentQuery(projection = arrayOf(TITLE))
- fun getSingleColumnList(): List<String>
-
- @ContentQuery(projection = arrayOf(TITLE))
- fun getSingleColumnSet(): Set<String>
-
- @ContentQuery(projection = arrayOf(TITLE))
- fun getPartiallyFilledPojo(): TitlePlusUnrelatedFieldPojo?
-
- @ContentQuery
- fun getPublicFieldsPojo(): PublicFieldsPojo?
-
- @ContentQuery
- fun getPojoWithIgnoredConstructor(): JavaPojoWithIgnoredConstructor?
-
- @ContentQuery(selection = "$TITLE = 'title2'")
- fun getPojoMatchingSelectionNoSelectionArgs(): List<TitleDescriptionPojo>
-
- @ContentQuery(selection = "$TITLE = :titleArg and $DESCRIPTION = :descriptionArg")
- fun getPojoMatchingSelectionWithSelectionArgs(
- titleArg: String,
- descriptionArg: String
- ): List<TitleDescriptionPojo>
-
- @ContentQuery(orderBy = arrayOf("$TITLE desc"))
- fun getAllOrderByTitleDescending(): List<TitleDescriptionPojo>
-
- @ContentQuery(orderBy = arrayOf("$TITLE asc"))
- fun getAllOrderByTitleAscending(): List<TitleDescriptionPojo>
-
- @ContentQuery(orderBy = arrayOf("$TITLE asc", "$DESCRIPTION desc"))
- fun getAllOrderByTitleAscDescriptionDesc(): List<TitleDescriptionPojo>
- }
-
- @ContentAccessObject(ImageNoUri::class)
- interface ImageAccessorEntityWithNoUri {
- @ContentQuery(uri = "content://media/external/images/media")
- fun getSingleElement(): ImageNoUri?
-
- @ContentQuery(uri = ":uriArg")
- fun getSingleElementWithArgumentUri(uriArg: String): ImageNoUri?
- }
-
- @ContentAccessObject
- interface ImageAccessorWithNoEntity {
- @ContentQuery(contentEntity = Image::class)
- fun getSingleElement(): Image?
- }
-
- data class TitleDescriptionPojo(val title: String?, val description: String?)
-
- data class TitlePlusUnrelatedFieldPojo(val title: String?, val unrelated: String?)
-
- data class TitleDescriptionAnnotatedPojo(
- @ContentColumn("title") val theTitle: String?,
- @ContentColumn("description") val theDescription: String?
- )
-
- @Test
- fun testUseUriInAnnotation() {
- val imageAccessorEntityWithNoUri = ContentAccess.getAccessor(
- ImageAccessorEntityWithNoUri::class, contentResolver
- )
- assertThat(imageAccessorEntityWithNoUri.getSingleElement()!!.title).isEqualTo("title1")
- }
-
- @Test
- fun testUseUriInArgument() {
- val imageAccessorEntityWithNoUri = ContentAccess.getAccessor(
- ImageAccessorEntityWithNoUri::class, contentResolver
- )
- assertThat(
- imageAccessorEntityWithNoUri
- .getSingleElementWithArgumentUri("content://media/external/images/media")!!.title
- )
- .isEqualTo("title1")
- }
-
- @Test
- fun testUseEntityInAnnotation() {
- val imageAccessorWithNoEntity = ContentAccess.getAccessor(
- ImageAccessorWithNoEntity::class, contentResolver
- )
- assertThat(imageAccessorWithNoEntity.getSingleElement()!!.title).isEqualTo("title1")
- }
-
- @Test
- fun testPrioritizesContentEntityInAnnotation() {
- val videoValues = ContentValues()
- videoValues.put(MediaStore.Video.Media.TITLE, "videotitle")
- contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, videoValues)
- assertThat(imageAccessor.getSingleVideo()!!.title).isEqualTo("videotitle")
- }
-
- @Test
- fun testGetsSingleEntityAndPopulatesProperly() {
- val result = imageAccessor.getSingleEntity()!!
- assertThat(result.title).isEqualTo("title1")
- assertThat(result.description).isEqualTo("description1")
- assertThat(result.mimeType).isEqualTo("image/jpeg")
- assertThat(result.dateTaken).isEqualTo(100000)
- }
-
- @Test
- fun testSuspendingGetSingleEntityAndPopulatesProperly() {
- runBlocking {
- val result = imageAccessor.getSingleEntitySuspend()!!
- assertThat(result.title).isEqualTo("title1")
- assertThat(result.description).isEqualTo("description1")
- assertThat(result.mimeType).isEqualTo("image/jpeg")
- assertThat(result.dateTaken).isEqualTo(100000)
- }
- }
-
- @Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
- fun testGetsSingleEntityAsOptional() {
- assertThat(imageAccessor.getSingleEntityAsOptional().get().title).isEqualTo("title1")
- }
-
- @Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
- fun testSuspendingGetSingleEntityAsOptional() {
- runBlocking {
- assertThat(imageAccessor.getSingleEntityAsOptionalSuspend().get().title)
- .isEqualTo("title1")
- }
- }
-
- @Test
- fun testGetAllEntitiesAsList() {
- assertThat(imageAccessor.getAllEntitiesAsList().size).isEqualTo(2)
- }
-
- @Test
- fun testSuspendingGetAllEntitiesAsList() {
- runBlocking {
- assertThat(imageAccessor.getAllEntitiesAsListSuspend().size).isEqualTo(2)
- }
- }
-
- // This test is somehow flaky in build server... makes no sense given that it does the same
- // thing as testGetAllEntitiesAsList or testSuspendingGetAllEntitiesAsSet but :shrug:...
- // TODO(obenabde): figure out why this is flaky.
- // @Test
- fun testGetAllEntitiesAsSet() {
- assertThat(imageAccessor.getAllEntitiesAsSet().size).isEqualTo(2)
- }
-
- @Test
- fun testSuspendingGetAllEntitiesAsSet() {
- runBlocking {
- assertThat(imageAccessor.getAllEntitiesAsSetSuspend().size).isEqualTo(2)
- }
- }
-
- @Test
- fun testGetSinglePojoAndPopulatesProperly() {
- val result = imageAccessor.getSinglePojo()!!
- assertThat(result.title).isEqualTo("title1")
- assertThat(result.description).isEqualTo("description1")
- }
-
- @Test
- fun testGetSingleAnnotatedPojoAndPopulatesProperly() {
- val result = imageAccessor.getSingleAnnotatedPojo()!!
- assertThat(result.theTitle).isEqualTo("title1")
- assertThat(result.theDescription).isEqualTo("description1")
- }
-
- @Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
- fun testGetSinglePojoAsOptional() {
- assertThat(imageAccessor.getSinglePojoAsOptional().get().title).isEqualTo("title1")
- }
-
- @Test
- fun testGetAllPojosAsList() {
- assertThat(imageAccessor.getAllPojosAsList().size).isEqualTo(2)
- }
-
- @Test
- fun testGetAllPojosAsSet() {
- assertThat(imageAccessor.getAllPojosAsSet().size).isEqualTo(2)
- }
-
- @Test
- fun testGetSingleColumn() {
- assertThat(imageAccessor.getSingleColumn()).isEqualTo("title1")
- }
-
- @Test
- @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
- fun testGetSingleColumnOptional() {
- assertThat(imageAccessor.getSinglePojoAsOptional().get().title).isEqualTo("title1")
- }
-
- @Test
- fun testGetSingleColumnList() {
- assertThat(imageAccessor.getAllPojosAsList().size).isEqualTo(2)
- }
-
- @Test
- fun testGetSingleColumnsSet() {
- assertThat(imageAccessor.getAllPojosAsSet().size).isEqualTo(2)
- }
-
- @Test
- fun testGetPartiallyPopulatedPojo() {
- val result = imageAccessor.getPartiallyFilledPojo()!!
- assertThat(result.title).isEqualTo("title1")
- assertThat(result.unrelated).isNull()
- }
-
- @Test
- fun testGetPojoWithPublicFields() {
- val result = imageAccessor.getPublicFieldsPojo()!!
- assertThat(result.title).isEqualTo("title1")
- assertThat(result.theDescription).isEqualTo("description1")
- }
-
- @Test
- fun testGetJavaPojoWithIgnoredConstructor() {
- val result = imageAccessor.getPojoWithIgnoredConstructor()!!
- assertThat(result.mTitle).isEqualTo("title1")
- assertThat(result.mDescription).isEqualTo("description1")
- }
-
- @Test
- fun testProperlyQueriesWithSelectionAndNoSelectionArgs() {
- val result = imageAccessor.getPojoMatchingSelectionNoSelectionArgs()
- assertThat(result.size).isEqualTo(1)
- assertThat(result.first().description).isEqualTo("description2")
- }
-
- @Test
- fun testProperlyQueriesWithSelectionAndSelectionArgs() {
- val result = imageAccessor.getPojoMatchingSelectionWithSelectionArgs(
- "title2",
- "description2"
- )
- assertThat(result.size).isEqualTo(1)
- assertThat(result.first().description).isEqualTo("description2")
- }
-
- @Test
- fun testOrderBySingleField() {
- val result1 = imageAccessor.getAllOrderByTitleDescending()
- assertThat(result1.size).isEqualTo(2)
- assertThat(result1.first().title).isEqualTo("title2")
- val result2 = imageAccessor.getAllOrderByTitleAscending()
- assertThat(result2.size).isEqualTo(2)
- assertThat(result2.first().title).isEqualTo("title1")
- }
-
- @Test
- fun testOrderByMultipleFields() {
- // Delete all the added ones
- contentResolver.delete(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- MediaStore.Images.Media.MIME_TYPE + "=?", arrayOf("image/jpeg")
- )
-
- val values = ContentValues().apply {
- put(TITLE, "title1")
- put(DESCRIPTION, "description1")
- put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.DATE_TAKEN, 1000000000000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
-
- values.apply {
- put(TITLE, "title1")
- put(DESCRIPTION, "description2")
- put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.DATE_TAKEN, 2000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
-
- values.apply {
- put(TITLE, "title2")
- put(DESCRIPTION, "description1")
- put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.DATE_TAKEN, 1000000000000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
-
- values.apply {
- put(TITLE, "title2")
- put(DESCRIPTION, "description2")
- put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.DATE_TAKEN, 2000L)
- }
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
-
- val result = imageAccessor.getAllOrderByTitleAscDescriptionDesc()
- assertThat(result.size).isEqualTo(4)
-
- assertThat(result.get(0).title).isEqualTo("title1")
- assertThat(result.get(0).description).isEqualTo("description2")
-
- assertThat(result.get(1).title).isEqualTo("title1")
- assertThat(result.get(1).description).isEqualTo("description1")
-
- assertThat(result.get(2).title).isEqualTo("title2")
- assertThat(result.get(2).description).isEqualTo("description2")
-
- assertThat(result.get(3).title).isEqualTo("title2")
- assertThat(result.get(3).description).isEqualTo("description1")
- }
-}
\ No newline at end of file
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentUpdateTest.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentUpdateTest.kt
deleted file mode 100644
index 0e408bd..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/ContentUpdateTest.kt
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp
-
-import com.google.common.truth.Truth.assertThat
-
-import android.provider.ContactsContract.Contacts.DISPLAY_NAME
-import android.provider.ContactsContract.Contacts.DISPLAY_NAME_SOURCE
-import android.provider.ContactsContract.Contacts.CONTENT_URI
-import androidx.contentaccess.ContentAccess
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentUpdate
-import androidx.test.filters.MediumTest
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-
-@MediumTest
-class ContentUpdateTest : ContactsBasedTest() {
-
- val contactsAccessor = ContentAccess.getAccessor(ContactsAccessor::class, contentResolver)
-
- @ContentAccessObject(Contact::class)
- interface ContactsAccessor {
-
- @ContentUpdate
- fun updateDisplayNamesAndDisplayNamesPrimary(
- @ContentColumn(DISPLAY_NAME) displayName: String,
- @ContentColumn(DISPLAY_NAME_SOURCE) displayNameSource: String
- ): Int
-
- @ContentUpdate
- fun suspendingUpdateDisplayNamesAndDisplayNamesPrimary(
- @ContentColumn(DISPLAY_NAME) displayName: String,
- @ContentColumn(DISPLAY_NAME_SOURCE) displayNameSource: String
- ): Int
-
- @ContentUpdate(where = "$DISPLAY_NAME = \"displayName1\"")
- fun updateDisplayNameWithWhereConditionNoSelectionArgs(
- @ContentColumn(DISPLAY_NAME) displayName: String
- ): Int
-
- @ContentUpdate(where = "$DISPLAY_NAME = :displayNameArg")
- fun updateDisplayNameWithWhereConditionAndSelectionArgs(
- @ContentColumn(DISPLAY_NAME) displayName: String,
- displayNameArg: String
- ): Int
- }
-
- @ContentAccessObject(ContactNoUri::class)
- interface ContactsAccessorEntityWithNoUri {
- @ContentUpdate(uri = "content://com.android.contacts/raw_contacts")
- fun updateAllDisplayNames(
- @ContentColumn(DISPLAY_NAME) displayName: String
- ): Int
-
- @ContentUpdate(uri = ":uriArg")
- fun updateDisplayNameWithUriArgument(
- @ContentColumn(DISPLAY_NAME) displayName: String,
- uriArg: String
- ): Int
- }
-
- // TODO(obenabde): add a test for overriding content entity through annotation parameter.
-
- @ContentAccessObject
- interface ContactsAccessorWithNoEntity {
- @ContentUpdate(contentEntity = Contact::class)
- fun updateDisplayName(@ContentColumn(DISPLAY_NAME) displayName: String): Int
- }
-
- @Test
- fun testUseUriInAnnotation() {
- val contactsAccessorEntityWithNoUri = ContentAccess.getAccessor(
- ContactsAccessorEntityWithNoUri::class, contentResolver
- )
- assertThat(contactsAccessorEntityWithNoUri.updateAllDisplayNames("updated-displayName"))
- .isEqualTo(2)
- val cursor = contentResolver.query(
- CONTENT_URI, arrayOf(DISPLAY_NAME), null, null, null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-displayName")
- }
-
- @Test
- fun testUseUriInArgument() {
- val contactsAccessorEntityWithNoUri = ContentAccess.getAccessor(
- ContactsAccessorEntityWithNoUri::class, contentResolver
- )
- assertThat(
- contactsAccessorEntityWithNoUri.updateDisplayNameWithUriArgument(
- "updated-displayName",
- "content://com.android.contacts/raw_contacts"
- )
- ).isEqualTo(2)
- val cursor = contentResolver.query(
- CONTENT_URI, arrayOf(DISPLAY_NAME), null, null, null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-displayName")
- }
-
- @Test
- fun testUseEntityInAnnotation() {
- val contactsAccessorWithNoEntity = ContentAccess.getAccessor(
- ContactsAccessorWithNoEntity::class, contentResolver
- )
- assertThat(
- contactsAccessorWithNoEntity
- .updateDisplayName("updated-description")
- ).isEqualTo(2)
- val cursor = contentResolver.query(
- CONTENT_URI,
- arrayOf(
- DISPLAY_NAME
- ),
- null, null, null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-description")
- }
-
- @Test
- fun testUpdatesAllColumns() {
- assertThat(
- contactsAccessor.updateDisplayNamesAndDisplayNamesPrimary(
- "updated-display-name",
- "updated-display-name-source"
- )
- )
- .isEqualTo(2)
- val cursor = contentResolver.query(
- CONTENT_URI,
- arrayOf(
- DISPLAY_NAME, DISPLAY_NAME_SOURCE
- ),
- null, null, null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-display-name")
- assertThat(cursor.getString(1)).isEqualTo("updated-display-name-source")
- }
-
- @Test
- fun testSuspendingUpdatesAllColumns() {
- runBlocking {
- assertThat(
- contactsAccessor.suspendingUpdateDisplayNamesAndDisplayNamesPrimary
- (
- "updated-display-name",
- "updated-display-name-source"
- )
- )
- .isEqualTo(2)
- val cursor = contentResolver.query(
- CONTENT_URI,
- arrayOf(
- DISPLAY_NAME, DISPLAY_NAME_SOURCE
- ),
- null, null, null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-display-name")
- assertThat(cursor.getString(1)).isEqualTo("updated-display-name-source")
- }
- }
-
- @Test
- fun testUpdatesColumnsWithSelection() {
- assertThat(
- contactsAccessor.updateDisplayNameWithWhereConditionNoSelectionArgs(
- "updated-display-name"
- )
- ).isEqualTo(1)
- val cursor = contentResolver.query(
- CONTENT_URI,
- arrayOf(
- DISPLAY_NAME
- ),
- null, null, null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-display-name")
- }
-
- @Test
- fun testUpdatesColumnsWithSelectionAndSelectionArgs() {
- assertThat(
- contactsAccessor.updateDisplayNameWithWhereConditionAndSelectionArgs(
- "updated-display-name",
- "displayName2"
- )
- ).isEqualTo(1)
- val cursor = contentResolver.query(
- CONTENT_URI,
- arrayOf(
- DISPLAY_NAME
- ),
- "$DISPLAY_NAME_SOURCE=?", arrayOf("displayNameSource2"), null
- )!!
- cursor.moveToFirst()
- assertThat(cursor.getString(0)).isEqualTo("updated-display-name")
- }
-}
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/Entities.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/Entities.kt
deleted file mode 100644
index fa91f4d..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/Entities.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp
-
-import android.provider.ContactsContract
-import android.provider.MediaStore
-import androidx.contentaccess.ContentColumn
-import androidx.contentaccess.ContentEntity
-import androidx.contentaccess.ContentPrimaryKey
-
-@ContentEntity
-data class ImageNoUri(
- @ContentPrimaryKey(MediaStore.Images.Media._ID)
- var iD: Long?,
- @ContentColumn(MediaStore.Images.Media.TITLE)
- var title: String?,
- @ContentColumn(MediaStore.Images.Media.DESCRIPTION)
- var description: String?,
- @ContentColumn(MediaStore.Images.Media.MIME_TYPE)
- var mimeType: String?,
- @ContentColumn(MediaStore.Images.Media.DATE_ADDED)
- var dateAdded: Long?,
- @ContentColumn(MediaStore.Images.Media.DATE_TAKEN)
- var dateTaken: Long?
-)
-
-@ContentEntity("content://com.android.contacts/raw_contacts")
-data class Contact(
- @ContentPrimaryKey(ContactsContract.Contacts._ID)
- var iD: Long,
- @ContentColumn(ContactsContract.Contacts.DISPLAY_NAME)
- var displayName: String?,
- @ContentColumn(ContactsContract.Contacts.DISPLAY_NAME_SOURCE)
- var displayNameSource: String?,
- @ContentColumn(ContactsContract.Contacts.HAS_PHONE_NUMBER)
- var hasPhoneNumber: Int?
-)
-
-@ContentEntity
-data class ContactNoUri(
- @ContentPrimaryKey(ContactsContract.Contacts._ID)
- var iD: Long,
- @ContentColumn(ContactsContract.Contacts.DISPLAY_NAME)
- var displayName: String?,
- @ContentColumn(ContactsContract.Contacts.DISPLAY_NAME_SOURCE)
- var displayNameSource: String?,
- @ContentColumn(ContactsContract.Contacts.HAS_PHONE_NUMBER)
- var hasPhoneNumber: Int?
-)
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/JavaPojoWithIgnoredConstructor.java b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/JavaPojoWithIgnoredConstructor.java
deleted file mode 100644
index 85f1252..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/JavaPojoWithIgnoredConstructor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp;
-
-import androidx.annotation.Nullable;
-import androidx.contentaccess.IgnoreConstructor;
-
-public class JavaPojoWithIgnoredConstructor {
-
-
- public String mTitle;
-
- public String mDescription;
-
- public JavaPojoWithIgnoredConstructor(@Nullable String title, @Nullable String description) {
- mTitle = title;
- mDescription = description;
- }
-
- @IgnoreConstructor
- public JavaPojoWithIgnoredConstructor(String title) {}
-}
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/MediaStoreEntitiesTest.kt b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/MediaStoreEntitiesTest.kt
deleted file mode 100644
index d79f87f..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/MediaStoreEntitiesTest.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp
-
-import android.Manifest
-import android.content.ContentValues
-import android.provider.MediaStore
-import androidx.contentaccess.ContentAccess
-import androidx.contentaccess.ContentAccessObject
-import androidx.contentaccess.ContentQuery
-import androidx.contentaccess.entities.ContentAccessMediaStore
-import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
-import org.junit.After
-import org.junit.Rule
-import org.junit.Test
-
-@MediumTest
-class MediaStoreEntitiesTest {
-
- val contentResolver = InstrumentationRegistry.getInstrumentation().context.contentResolver
- val accessor = ContentAccess.getAccessor(MediaStoreAccessor::class, contentResolver)
-
- @After
- fun deleteAllAdded() {
- contentResolver.delete(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- MediaStore.Images.Media.MIME_TYPE + "=?", arrayOf("image/jpeg")
- )
- }
-
- @JvmField
- @Rule
- var storagePermissions =
- GrantPermissionRule.grant(
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission
- .WRITE_EXTERNAL_STORAGE
- )!!
-
- @ContentAccessObject
- @Suppress("deprecation")
- interface MediaStoreAccessor {
- @ContentQuery(contentEntity = ContentAccessMediaStore.Image::class)
- fun getImage(): ContentAccessMediaStore.Image?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Video::class)
- fun getVideo(): ContentAccessMediaStore.Video?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Audio::class)
- fun getAudio(): ContentAccessMediaStore.Audio?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Download::class)
- fun getDownload(): ContentAccessMediaStore.Download?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Artist::class)
- fun getArtist(): ContentAccessMediaStore.Artist?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Album::class)
- fun getAlbum(): ContentAccessMediaStore.Album?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Genre::class)
- fun getGenre(): ContentAccessMediaStore.Genre?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.ImageThumbnail::class)
- fun getImageThumbnail(): ContentAccessMediaStore.ImageThumbnail?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.VideoThumbnail::class)
- fun getVideoThumbnail(): ContentAccessMediaStore.VideoThumbnail?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.Playlist::class)
- fun getPlaylist(): ContentAccessMediaStore.Playlist?
-
- @ContentQuery(contentEntity = ContentAccessMediaStore.File::class, uri = ":uri")
- fun getFile(uri: String): ContentAccessMediaStore.File?
- }
-
- @Test
- fun testEntities() {
- // The results should be empty, but we want to make sure we are querying the correct uris
- // and the correct columns on all API levels, as we should get an error if something
- // is mal-defined.
- accessor.getImage()
- accessor.getVideo()
- accessor.getAudio()
- accessor.getArtist()
- accessor.getAlbum()
- accessor.getGenre()
- accessor.getImageThumbnail()
- accessor.getVideoThumbnail()
- accessor.getPlaylist()
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 29)
- fun testApi29IntroducedEntities() {
- accessor.getDownload()
- }
-
- @Test
- fun testFileEntity() {
- val contentValues = ContentValues()
- // Media type is image, so should be cleaned up.
- contentValues.put("media_type", 1)
- contentValues.put("_data", "random")
- val uri = MediaStore.Files.getContentUri("external")
- contentResolver.insert(uri, contentValues)
- accessor.getFile(uri.toString())
- }
-}
\ No newline at end of file
diff --git a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/PublicFieldsPojo.java b/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/PublicFieldsPojo.java
deleted file mode 100644
index cd259ee..0000000
--- a/contentaccess/integration-tests/testapp/src/androidTest/java/androidx/contentaccess/integration/testapp/PublicFieldsPojo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 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.
- */
-
-package androidx.contentaccess.integration.testapp;
-
-import androidx.annotation.Nullable;
-import androidx.contentaccess.ContentColumn;
-
-public class PublicFieldsPojo {
- @Nullable
- public String title;
-
- @ContentColumn(columnName = "description")
- @Nullable
- public String theDescription;
-}
diff --git a/contentaccess/integration-tests/testapp/src/main/AndroidManifest.xml b/contentaccess/integration-tests/testapp/src/main/AndroidManifest.xml
deleted file mode 100644
index 7550603..0000000
--- a/contentaccess/integration-tests/testapp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.contentaccess.integration.testapp"
- android:sharedUserId="androidx.contentaccess.integration.testapp.uid">
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <application />
-</manifest>
diff --git a/settings.gradle b/settings.gradle
index a1846dc..aa755ce 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -261,11 +261,6 @@
includeProject(":compose:ui:ui:ui-samples", "compose/ui/ui/samples", [BuildType.COMPOSE])
includeProject(":concurrent:concurrent-futures", "concurrent/futures", [BuildType.MAIN])
includeProject(":concurrent:concurrent-futures-ktx", "concurrent/futures-ktx", [BuildType.MAIN])
-includeProject(":contentaccess:contentaccess-annotations", "contentaccess/contentaccess-annotations", [BuildType.MAIN])
-includeProject(":contentaccess:contentaccess-compiler", "contentaccess/contentaccess-compiler", [BuildType.MAIN])
-includeProject(":contentaccess:contentaccess-entities", "contentaccess/contentaccess-entities", [BuildType.MAIN])
-includeProject(":contentaccess:contentaccess-runtime", "contentaccess/contentaccess-runtime", [BuildType.MAIN])
-includeProject(":contentaccess:integration-tests:testapp", "contentaccess/integration-tests/testapp", [BuildType.MAIN])
includeProject(":contentpager:contentpager", "contentpager/contentpager", [BuildType.MAIN])
includeProject(":coordinatorlayout:coordinatorlayout", "coordinatorlayout/coordinatorlayout", [BuildType.MAIN])
includeProject(":core-role", "core/core-role", [BuildType.MAIN])