SchemaFileResolver.kt
/*
* Copyright 2021 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.room.util
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.nio.file.Path
import java.util.ServiceLoader
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.outputStream
/**
* A service provider interface to resolve a schema path to a file. An implementation of this
* interfaces is discovered by Room via a [ServiceLoader].
*/
interface SchemaFileResolver {
/**
* Requests an input stream to be opened for a given path. The function implementation might
* return `null` if such path does not exist.
*
* The path will be a either a sibling of Room's schema location or the folder itself as
* provided via the annotation processor options 'room.schemaLocation' or 'roomSchemaInput.
*/
@Throws(IOException::class)
fun readPath(path: Path): InputStream?
/**
* Requests an input stream to be opened for a given path.
*
* The path will be a either a sibling of Room's schema location or the folder itself as
* provided via the annotation processor options 'room.schemaLocation' or 'roomSchemaOutput.
*/
@Throws(IOException::class)
fun writePath(path: Path): OutputStream
companion object {
val RESOLVER: SchemaFileResolver by lazy {
// Search is performed using the default ServiceLoader.load() class loader and the
// interface's. This is because build tools will isolate annotation processor's
// classpath and the default class loader (i.e. current thread's context class
// loader) might miss a provided implementation.
ServiceLoader.load(
SchemaFileResolver::class.java,
).firstOrNull() ?: ServiceLoader.load(
SchemaFileResolver::class.java,
SchemaFileResolver::class.java.classLoader
).firstOrNull() ?: DEFAULT_RESOLVER
}
private val DEFAULT_RESOLVER = object : SchemaFileResolver {
override fun readPath(path: Path): InputStream? {
return if (path.exists()) path.inputStream() else null
}
override fun writePath(path: Path): OutputStream {
val parent = path.parent
if (parent != null && !parent.exists()) {
parent.createDirectories()
}
return path.outputStream()
}
}
}
}