From 13bda7371cc60beaa4cc8302239efd21695b9e1f Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Fri, 2 Dec 2016 23:46:16 +0300 Subject: Now dokka-fatjar complete isolated from poisonous Gradle environment --- core/build.gradle | 2 +- core/src/main/kotlin/DokkaBootstrapImpl.kt | 55 ++++++++++++++++ core/src/main/kotlin/Utilities/DokkaLogging.kt | 6 -- integration/build.gradle | 13 ++++ .../kotlin/org/jetbrains/dokka/DokkaBootstrap.kt | 22 +++++++ .../main/kotlin/org/jetbrains/dokka/DokkaLogger.kt | 8 +++ .../main/kotlin/org/jetbrains/dokka/ProxyUtils.kt | 76 ++++++++++++++++++++++ runners/android-gradle-plugin/build.gradle | 3 +- runners/cli/src/main/kotlin/cli/main.kt | 7 -- runners/fatjar/build.gradle | 23 ------- runners/gradle-plugin/build.gradle | 19 ++++-- runners/gradle-plugin/src/main/kotlin/main.kt | 76 +++++++++++++++++++--- .../gradle-plugins/org.jetbrains.dokka.properties | 3 +- settings.gradle | 2 +- 14 files changed, 260 insertions(+), 55 deletions(-) create mode 100644 core/src/main/kotlin/DokkaBootstrapImpl.kt create mode 100644 integration/build.gradle create mode 100644 integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt create mode 100644 integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt create mode 100644 integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt diff --git a/core/build.gradle b/core/build.gradle index 72eb6baf..08be76c0 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -47,7 +47,7 @@ dependencies { //tools.jar provided files(((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs().findAll { it.path.endsWith("jar") }) - + compile project(":integration") testCompile group: 'junit', name: 'junit', version: '4.12' testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-test-junit', version: kotlin_version diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt new file mode 100644 index 00000000..cbec4985 --- /dev/null +++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt @@ -0,0 +1,55 @@ +package org.jetbrains.dokka + +import java.io.File + +fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition { + val (path, urlAndLine) = srcLink.split('=') + return SourceLinkDefinition(File(path).absolutePath, + urlAndLine.substringBefore("#"), + urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it }) +} + + +class DokkaBootstrapImpl : DokkaBootstrap { + + lateinit var generator: DokkaGenerator + + override fun configure(logger: DokkaLogger, + moduleName: String, + classpath: List, + sources: List, + samples: List, + includes: List, + outputDir: String, + format: String, + includeNonPublic: Boolean, + reportUndocumented: Boolean, + skipEmptyPackages: Boolean, + skipDeprecated: Boolean, + jdkVersion: Int, + generateIndexPages: Boolean, + sourceLinks: List) { + generator = DokkaGenerator( + logger, + classpath, + sources, + samples, + includes, + moduleName, + DocumentationOptions( + outputDir, + format, + includeNonPublic, + reportUndocumented, + skipEmptyPackages, + skipDeprecated, + jdkVersion, + generateIndexPages, + sourceLinks.map(::parseSourceLinkDefinition) + ) + ) + + } + + override fun generate() = generator.generate() +} \ No newline at end of file diff --git a/core/src/main/kotlin/Utilities/DokkaLogging.kt b/core/src/main/kotlin/Utilities/DokkaLogging.kt index 1ef52837..2e0fb395 100644 --- a/core/src/main/kotlin/Utilities/DokkaLogging.kt +++ b/core/src/main/kotlin/Utilities/DokkaLogging.kt @@ -1,11 +1,5 @@ package org.jetbrains.dokka -interface DokkaLogger { - fun info(message: String) - fun warn(message: String) - fun error(message: String) -} - object DokkaConsoleLogger : DokkaLogger { var warningCount: Int = 0 diff --git a/integration/build.gradle b/integration/build.gradle new file mode 100644 index 00000000..db2d6d78 --- /dev/null +++ b/integration/build.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'kotlin' + + +dependencies { + compile group: 'org.jetbrains.kotlin', name: 'kotlin-runtime', version: kotlin_version + compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlin_version +} \ No newline at end of file diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt new file mode 100644 index 00000000..548aceb0 --- /dev/null +++ b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt @@ -0,0 +1,22 @@ +package org.jetbrains.dokka + +interface DokkaBootstrap { + + fun configure(logger: DokkaLogger, + moduleName: String, + classpath: List, + sources: List, + samples: List, + includes: List, + outputDir: String, + format: String, + includeNonPublic: Boolean, + reportUndocumented: Boolean, + skipEmptyPackages: Boolean, + skipDeprecated: Boolean, + jdkVersion: Int, + generateIndexPages: Boolean, + sourceLinks: List) + + fun generate() +} \ No newline at end of file diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt new file mode 100644 index 00000000..fc1fac22 --- /dev/null +++ b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt @@ -0,0 +1,8 @@ +package org.jetbrains.dokka + +interface DokkaLogger { + fun info(message: String) + fun warn(message: String) + fun error(message: String) +} + diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt b/integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt new file mode 100644 index 00000000..66356f66 --- /dev/null +++ b/integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt @@ -0,0 +1,76 @@ +package org.jetbrains.dokka + +import java.lang.reflect.InvocationHandler +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method +import java.lang.reflect.Proxy +import java.util.function.Predicate + + +/** + * Warning! Hard reflection magic used here. + * + * Creates [java.lang.reflect.Proxy] with pass through invocation algorithm, + * to create access proxy for [delegate] from [targetClassLoader] to [delegateClassLoader]. + * + * Every object type contained in method calls will be translated to proxy, if [filter.test] will success for it's class + * + */ +@Suppress("UNCHECKED_CAST") +fun automagicTypedProxy(targetClassLoader: ClassLoader, targetType: Class, + delegateClassLoader: ClassLoader, delegate: Any, + filter: Predicate>): T = + automagicProxy(targetClassLoader, targetType, delegateClassLoader, delegate, filter) as T + + +/** + * Warning! Hard reflection magic used here. + * + * Creates [java.lang.reflect.Proxy] with pass through invocation algorithm, + * to create access proxy for [delegate] from [targetClassLoader] to [delegateClassLoader]. + * + * Every object type contained in method calls will be translated to proxy, if [filter.test] will success for it's class + * + */ +fun automagicProxy(targetClassLoader: ClassLoader, targetType: Class<*>, + delegateClassLoader: ClassLoader, delegate: Any, + filter: Predicate>): Any = + Proxy.newProxyInstance( + targetClassLoader, + arrayOf(targetType), + DelegatedInvocationHandler( + delegate, + delegateClassLoader, + filter + ) + ) + +class DelegatedInvocationHandler(private val delegate: Any, + private val delegateClassLoader: ClassLoader, + private val filter: Predicate>) + : InvocationHandler { + + @Throws(Throwable::class) + override fun invoke(proxy: Any, method: Method, args: Array?): Any? { + val (argTypes, argValues) = method.parameterTypes.zip(args ?: emptyArray()).map { typeAndValue -> + val (type, value) = typeAndValue + if (filter.test(type)) { + val newType = delegateClassLoader.loadClass(type.name) + val newValue = value?.let { + automagicProxy(delegateClassLoader, newType, type.classLoader, value, filter) + } + newType to newValue + } else + typeAndValue + }.unzip() + + val delegateMethod = delegate.javaClass.getMethod(method.name, *argTypes.toTypedArray()) + try { + delegateMethod.isAccessible = true + return delegateMethod.invoke(delegate, *argValues.toTypedArray()) + } catch (ex: InvocationTargetException) { + throw ex.targetException + } + + } +} diff --git a/runners/android-gradle-plugin/build.gradle b/runners/android-gradle-plugin/build.gradle index 6e8da695..4ea12edb 100644 --- a/runners/android-gradle-plugin/build.gradle +++ b/runners/android-gradle-plugin/build.gradle @@ -19,7 +19,7 @@ repositories { dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' - shadow project(':runners:fatjar') + shadow project(':runners:gradle-plugin') provided gradleApi() @@ -35,7 +35,6 @@ task sourceJar(type: Jar) { shadowJar { baseName = 'dokka-android-gradle-plugin' classifier = '' - relocate('kotlin.', 'dokkakotlin.') } apply plugin: 'maven-publish' diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 68192dc7..b31894eb 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -45,13 +45,6 @@ class DokkaArguments { var jdkVersion: Int = 6 } -private fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition { - val (path, urlAndLine) = srcLink.split('=') - return SourceLinkDefinition(File(path).absolutePath, - urlAndLine.substringBefore("#"), - urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it }) -} - fun main(args: Array) { val arguments = DokkaArguments() val freeArgs: List = Args.parse(arguments, args, false) ?: listOf() diff --git a/runners/fatjar/build.gradle b/runners/fatjar/build.gradle index d888a1ac..a9f0c721 100644 --- a/runners/fatjar/build.gradle +++ b/runners/fatjar/build.gradle @@ -22,29 +22,6 @@ shadowJar { exclude provided } - relocate('com.', 'dokkacom.') { - exclude 'com.sun.**' - } - - relocate('org.', 'dokkaorg.') { - exclude 'org.jetbrains.dokka.**' - exclude 'org.xml.**' - exclude 'org.w3c.**' - exclude 'org.jaxen.**' - exclude 'org.apache.xerces.**' - exclude 'org.apache.xml.**' - exclude 'org.fusesource.jansi.**' - exclude 'org.apache.tools.ant.**' - } - - - relocate('kotlin.', 'dokkakotlin.') { - exclude '**.*kotlin_builtins' //For kotlin_builtins, still not sure that we should relocate kotlin stdlib - exclude 'kotlin.reflect' /* WAT? Ok, ok. Relocate works as Ctrl + Shift + R for ALL class files, so, - if you have string "kotlin.reflect", it will be rewritten to not relevant "dokkakotlin.reflect" and you will got - builtins crash in runtime, cause could not find dokkakotlin/reflect/reflect.kotlin_builtins */ - } - transform(ServiceFileTransformer) transform(PluginXmlTransformer) diff --git a/runners/gradle-plugin/build.gradle b/runners/gradle-plugin/build.gradle index 3c330d18..8e6f11df 100644 --- a/runners/gradle-plugin/build.gradle +++ b/runners/gradle-plugin/build.gradle @@ -14,12 +14,13 @@ tasks.withType(AbstractCompile) { } dependencies { - - shadow project(':runners:fatjar') testCompile group: 'junit', name: 'junit', version: '4.12' - provided group: 'org.jetbrains.kotlin', name: 'kotlin-runtime', version: kotlin_version - provided group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlin_version + compile group: 'org.jetbrains.kotlin', name: 'kotlin-runtime', version: kotlin_version + compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlin_version + + compile project(":integration") + provided gradleApi() provided localGroovy() } @@ -28,11 +29,19 @@ task sourceJar(type: Jar) { from sourceSets.main.allSource } +processResources { + eachFile { + if (it.name == "org.jetbrains.dokka.properties") { + it.filter { line -> + line.replace("", dokka_version) + } + } + } +} shadowJar { baseName = 'dokka-gradle-plugin' classifier = '' - relocate('kotlin.', 'dokkakotlin.') } apply plugin: 'maven-publish' diff --git a/runners/gradle-plugin/src/main/kotlin/main.kt b/runners/gradle-plugin/src/main/kotlin/main.kt index 49c3b8ba..f3e46c4d 100644 --- a/runners/gradle-plugin/src/main/kotlin/main.kt +++ b/runners/gradle-plugin/src/main/kotlin/main.kt @@ -8,15 +8,24 @@ import org.gradle.api.file.FileCollection import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.* -import org.jetbrains.dokka.DocumentationOptions -import org.jetbrains.dokka.DokkaGenerator -import org.jetbrains.dokka.SourceLinkDefinition +import org.jetbrains.dokka.DokkaBootstrap +import org.jetbrains.dokka.automagicTypedProxy +import org.jetbrains.dokka.gradle.ClassloaderContainer.fatJarClassLoader import java.io.File import java.io.Serializable +import java.net.URLClassLoader import java.util.* +import java.util.function.Predicate open class DokkaPlugin : Plugin { + + val properties = Properties() + + init { + properties.load(javaClass.getResourceAsStream("/META-INF/gradle-plugins/org.jetbrains.dokka.properties")) + } override fun apply(project: Project) { + version = properties.getProperty("dokka-version") project.tasks.create("dokka", DokkaTask::class.java).apply { moduleName = project.name outputDirectory = File(project.buildDir, "dokka").absolutePath @@ -24,6 +33,13 @@ open class DokkaPlugin : Plugin { } } +var version: String? = null + +object ClassloaderContainer { + @JvmField + var fatJarClassLoader: ClassLoader? = null +} + open class DokkaTask : DefaultTask() { init { group = JavaBasePlugin.DOCUMENTATION_GROUP @@ -47,6 +63,8 @@ open class DokkaTask : DefaultTask() { var jdkVersion: Int = 6 @Input var sourceDirs: Iterable = emptyList() + @Input + var dokkaFatJar: Any = "org.jetbrains.dokka:dokka-fatjar:$version" protected open val sdkProvider: SdkProvider? = null @@ -65,8 +83,27 @@ open class DokkaTask : DefaultTask() { linkMappings.add(mapping) } + + fun loadFatJar() { + if (fatJarClassLoader == null) { + val fatjar = if (dokkaFatJar is File) + dokkaFatJar as File + else { + val dependency = project.buildscript.dependencies.create(dokkaFatJar) + val configuration = project.buildscript.configurations.detachedConfiguration(dependency) + configuration.description = "Dokka main jar" + configuration.resolve().first() + } + + fatJarClassLoader = URLClassLoader(arrayOf(fatjar.toURI().toURL())) + } + } + + @TaskAction fun generate() { + loadFatJar() + val project = project val sdkProvider = sdkProvider val sourceDirectories = getSourceDirectories() @@ -83,17 +120,38 @@ open class DokkaTask : DefaultTask() { return } - DokkaGenerator( + val bootstrapClass = fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl") + + val bootstrapInstance = bootstrapClass.constructors.first().newInstance() + + val bootstrapProxy = automagicTypedProxy(javaClass.classLoader, + DokkaBootstrap::class.java, + fatJarClassLoader!!, + bootstrapInstance, + Predicate { it.name.startsWith("org.jetbrains.dokka") } + ) + + bootstrapProxy.configure( DokkaGradleLogger(logger), + moduleName, classpath.map { it.absolutePath }, sourceDirectories.map { it.absolutePath }, samples.filterNotNull().map { project.file(it).absolutePath }, includes.filterNotNull().map { project.file(it).absolutePath }, - moduleName, - DocumentationOptions(outputDirectory, outputFormat, - sourceLinks = linkMappings.map { SourceLinkDefinition(project.file(it.dir).absolutePath, it.url, it.suffix) }, - jdkVersion = jdkVersion) - ).generate() + outputDirectory, + outputFormat, + false, + false, + false, + false, + 6, + true, + linkMappings.map { + val path = project.file(it.dir).absolutePath + return@map "$path=${it.url}${it.suffix}" + }) + + bootstrapProxy.generate() } fun getSourceDirectories(): Collection { diff --git a/runners/gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.jetbrains.dokka.properties b/runners/gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.jetbrains.dokka.properties index b42cfe9f..068bd352 100644 --- a/runners/gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.jetbrains.dokka.properties +++ b/runners/gradle-plugin/src/main/resources/META-INF/gradle-plugins/org.jetbrains.dokka.properties @@ -1 +1,2 @@ -implementation-class=org.jetbrains.dokka.gradle.DokkaPlugin \ No newline at end of file +implementation-class=org.jetbrains.dokka.gradle.DokkaPlugin +dokka-version= \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 4ffd0211..9da9e303 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include 'core', 'runners:fatjar', 'runners:ant', 'runners:cli', 'runners:maven-plugin', 'runners:gradle-plugin', 'runners:android-gradle-plugin' +include 'core', 'runners:fatjar', 'runners:ant', 'runners:cli', 'runners:maven-plugin', 'runners:gradle-plugin', 'runners:android-gradle-plugin', 'integration' -- cgit From 546e8edfd95c16665319bc371c6ccf63706ad1e4 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Tue, 6 Dec 2016 16:05:01 +0300 Subject: Post-review changes, simplified proxies --- core/src/main/kotlin/DokkaBootstrapImpl.kt | 20 +++++- core/src/main/kotlin/Utilities/DokkaLogging.kt | 6 ++ .../kotlin/org/jetbrains/dokka/DokkaBootstrap.kt | 4 +- .../main/kotlin/org/jetbrains/dokka/DokkaLogger.kt | 8 --- .../main/kotlin/org/jetbrains/dokka/ProxyUtils.kt | 76 ---------------------- .../gradle-plugin/src/main/kotlin/ProxyUtils.kt | 46 +++++++++++++ runners/gradle-plugin/src/main/kotlin/logger.kt | 18 ----- runners/gradle-plugin/src/main/kotlin/main.kt | 19 +++--- 8 files changed, 82 insertions(+), 115 deletions(-) delete mode 100644 integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt delete mode 100644 integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt create mode 100644 runners/gradle-plugin/src/main/kotlin/ProxyUtils.kt delete mode 100644 runners/gradle-plugin/src/main/kotlin/logger.kt diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt index cbec4985..eb2b2a65 100644 --- a/core/src/main/kotlin/DokkaBootstrapImpl.kt +++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt @@ -1,6 +1,7 @@ package org.jetbrains.dokka import java.io.File +import java.util.function.BiConsumer fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition { val (path, urlAndLine) = srcLink.split('=') @@ -9,12 +10,25 @@ fun parseSourceLinkDefinition(srcLink: String): SourceLinkDefinition { urlAndLine.substringAfter("#", "").let { if (it.isEmpty()) null else "#" + it }) } - class DokkaBootstrapImpl : DokkaBootstrap { + class DokkaProxyLogger(val consumer: BiConsumer) : DokkaLogger { + override fun info(message: String) { + consumer.accept("info", message) + } + + override fun warn(message: String) { + consumer.accept("warn", message) + } + + override fun error(message: String) { + consumer.accept("error", message) + } + } + lateinit var generator: DokkaGenerator - override fun configure(logger: DokkaLogger, + override fun configure(logger: BiConsumer, moduleName: String, classpath: List, sources: List, @@ -30,7 +44,7 @@ class DokkaBootstrapImpl : DokkaBootstrap { generateIndexPages: Boolean, sourceLinks: List) { generator = DokkaGenerator( - logger, + DokkaProxyLogger(logger), classpath, sources, samples, diff --git a/core/src/main/kotlin/Utilities/DokkaLogging.kt b/core/src/main/kotlin/Utilities/DokkaLogging.kt index 2e0fb395..1ef52837 100644 --- a/core/src/main/kotlin/Utilities/DokkaLogging.kt +++ b/core/src/main/kotlin/Utilities/DokkaLogging.kt @@ -1,5 +1,11 @@ package org.jetbrains.dokka +interface DokkaLogger { + fun info(message: String) + fun warn(message: String) + fun error(message: String) +} + object DokkaConsoleLogger : DokkaLogger { var warningCount: Int = 0 diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt index 548aceb0..50e8fb8d 100644 --- a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt +++ b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaBootstrap.kt @@ -1,8 +1,10 @@ package org.jetbrains.dokka +import java.util.function.BiConsumer + interface DokkaBootstrap { - fun configure(logger: DokkaLogger, + fun configure(logger: BiConsumer, moduleName: String, classpath: List, sources: List, diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt b/integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt deleted file mode 100644 index fc1fac22..00000000 --- a/integration/src/main/kotlin/org/jetbrains/dokka/DokkaLogger.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.jetbrains.dokka - -interface DokkaLogger { - fun info(message: String) - fun warn(message: String) - fun error(message: String) -} - diff --git a/integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt b/integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt deleted file mode 100644 index 66356f66..00000000 --- a/integration/src/main/kotlin/org/jetbrains/dokka/ProxyUtils.kt +++ /dev/null @@ -1,76 +0,0 @@ -package org.jetbrains.dokka - -import java.lang.reflect.InvocationHandler -import java.lang.reflect.InvocationTargetException -import java.lang.reflect.Method -import java.lang.reflect.Proxy -import java.util.function.Predicate - - -/** - * Warning! Hard reflection magic used here. - * - * Creates [java.lang.reflect.Proxy] with pass through invocation algorithm, - * to create access proxy for [delegate] from [targetClassLoader] to [delegateClassLoader]. - * - * Every object type contained in method calls will be translated to proxy, if [filter.test] will success for it's class - * - */ -@Suppress("UNCHECKED_CAST") -fun automagicTypedProxy(targetClassLoader: ClassLoader, targetType: Class, - delegateClassLoader: ClassLoader, delegate: Any, - filter: Predicate>): T = - automagicProxy(targetClassLoader, targetType, delegateClassLoader, delegate, filter) as T - - -/** - * Warning! Hard reflection magic used here. - * - * Creates [java.lang.reflect.Proxy] with pass through invocation algorithm, - * to create access proxy for [delegate] from [targetClassLoader] to [delegateClassLoader]. - * - * Every object type contained in method calls will be translated to proxy, if [filter.test] will success for it's class - * - */ -fun automagicProxy(targetClassLoader: ClassLoader, targetType: Class<*>, - delegateClassLoader: ClassLoader, delegate: Any, - filter: Predicate>): Any = - Proxy.newProxyInstance( - targetClassLoader, - arrayOf(targetType), - DelegatedInvocationHandler( - delegate, - delegateClassLoader, - filter - ) - ) - -class DelegatedInvocationHandler(private val delegate: Any, - private val delegateClassLoader: ClassLoader, - private val filter: Predicate>) - : InvocationHandler { - - @Throws(Throwable::class) - override fun invoke(proxy: Any, method: Method, args: Array?): Any? { - val (argTypes, argValues) = method.parameterTypes.zip(args ?: emptyArray()).map { typeAndValue -> - val (type, value) = typeAndValue - if (filter.test(type)) { - val newType = delegateClassLoader.loadClass(type.name) - val newValue = value?.let { - automagicProxy(delegateClassLoader, newType, type.classLoader, value, filter) - } - newType to newValue - } else - typeAndValue - }.unzip() - - val delegateMethod = delegate.javaClass.getMethod(method.name, *argTypes.toTypedArray()) - try { - delegateMethod.isAccessible = true - return delegateMethod.invoke(delegate, *argValues.toTypedArray()) - } catch (ex: InvocationTargetException) { - throw ex.targetException - } - - } -} diff --git a/runners/gradle-plugin/src/main/kotlin/ProxyUtils.kt b/runners/gradle-plugin/src/main/kotlin/ProxyUtils.kt new file mode 100644 index 00000000..7bdf2f9d --- /dev/null +++ b/runners/gradle-plugin/src/main/kotlin/ProxyUtils.kt @@ -0,0 +1,46 @@ +package org.jetbrains.dokka + +import java.lang.reflect.InvocationHandler +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method +import java.lang.reflect.Proxy + + +/** + * Warning! Hard reflection magic used here. + * + * Creates [java.lang.reflect.Proxy] with pass through invocation algorithm, + * to create access proxy for [delegate] into [targetClassLoader]. + */ +@Suppress("UNCHECKED_CAST") +inline fun automagicTypedProxy(targetClassLoader: ClassLoader, delegate: Any): T = + automagicProxy(targetClassLoader, T::class.java, delegate) as T + + +/** + * Warning! Hard reflection magic used here. + * + * Creates [java.lang.reflect.Proxy] with pass through invocation algorithm, + * to create access proxy for [delegate] into [targetClassLoader]. + * + */ +fun automagicProxy(targetClassLoader: ClassLoader, targetType: Class<*>, delegate: Any): Any = + Proxy.newProxyInstance( + targetClassLoader, + arrayOf(targetType), + DelegatedInvocationHandler(delegate) + ) + +class DelegatedInvocationHandler(private val delegate: Any) : InvocationHandler { + + @Throws(Throwable::class) + override fun invoke(proxy: Any, method: Method, args: Array?): Any? { + val delegateMethod = delegate.javaClass.getMethod(method.name, *method.parameterTypes) + try { + delegateMethod.isAccessible = true + return delegateMethod.invoke(delegate, *(args ?: emptyArray())) + } catch (ex: InvocationTargetException) { + throw ex.targetException + } + } +} diff --git a/runners/gradle-plugin/src/main/kotlin/logger.kt b/runners/gradle-plugin/src/main/kotlin/logger.kt deleted file mode 100644 index 715c1f04..00000000 --- a/runners/gradle-plugin/src/main/kotlin/logger.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.jetbrains.dokka.gradle - -import org.gradle.api.logging.Logger -import org.jetbrains.dokka.DokkaLogger - -class DokkaGradleLogger(val logger: Logger) : DokkaLogger { - override fun error(message: String) { - logger.error(message) - } - - override fun info(message: String) { - logger.info(message) - } - - override fun warn(message: String) { - logger.warn(message) - } -} \ No newline at end of file diff --git a/runners/gradle-plugin/src/main/kotlin/main.kt b/runners/gradle-plugin/src/main/kotlin/main.kt index f3e46c4d..51061415 100644 --- a/runners/gradle-plugin/src/main/kotlin/main.kt +++ b/runners/gradle-plugin/src/main/kotlin/main.kt @@ -15,7 +15,7 @@ import java.io.File import java.io.Serializable import java.net.URLClassLoader import java.util.* -import java.util.function.Predicate +import java.util.function.BiConsumer open class DokkaPlugin : Plugin { @@ -124,15 +124,16 @@ open class DokkaTask : DefaultTask() { val bootstrapInstance = bootstrapClass.constructors.first().newInstance() - val bootstrapProxy = automagicTypedProxy(javaClass.classLoader, - DokkaBootstrap::class.java, - fatJarClassLoader!!, - bootstrapInstance, - Predicate { it.name.startsWith("org.jetbrains.dokka") } - ) + val bootstrapProxy: DokkaBootstrap = automagicTypedProxy(javaClass.classLoader, bootstrapInstance) bootstrapProxy.configure( - DokkaGradleLogger(logger), + BiConsumer { level, message -> + when (level) { + "info" -> logger.info(message) + "warn" -> logger.warn(message) + "error" -> logger.error(message) + } + }, moduleName, classpath.map { it.absolutePath }, sourceDirectories.map { it.absolutePath }, @@ -148,7 +149,7 @@ open class DokkaTask : DefaultTask() { true, linkMappings.map { val path = project.file(it.dir).absolutePath - return@map "$path=${it.url}${it.suffix}" + "$path=${it.url}${it.suffix}" }) bootstrapProxy.generate() -- cgit