Serialization plugin GSK build

Fixed issue when serialDesc property getter was generated, but backing field not.

Respect @Serializable(with=...) on property

Calling 3-arg readElementValue for support of custom contexts

Ability to nest context-based serializer

Migration to 1.2-Beta2

Use polymorphicSerializer prior to default

Don't use polymorphic serializers for all java classes

Docs and maven project update

Remove plugin runtime dependency on stdlib
This commit is contained in:
Leonid Startsev
2017-10-06 17:52:46 +03:00
parent 8a250b07df
commit f42767fcc2
21 changed files with 133 additions and 437 deletions
+2
View File
@@ -88,6 +88,7 @@ val commonLocalDataDir = "$rootDir/local"
val ideaSandboxDir = "$commonLocalDataDir/ideaSandbox"
val ideaUltimateSandboxDir = "$commonLocalDataDir/ideaUltimateSandbox"
val ideaPluginDir = "$distDir/artifacts/ideaPlugin/Kotlin"
val serialPluginDir = "$distDir/artifacts/Serialization"
val ideaUltimatePluginDir = "$distDir/artifacts/ideaUltimatePlugin/Kotlin"
val cidrPluginDir = "$distDir/artifacts/cidrPlugin/Kotlin"
@@ -98,6 +99,7 @@ extra["commonLocalDataDir"] = project.file(commonLocalDataDir)
extra["ideaSandboxDir"] = project.file(ideaSandboxDir)
extra["ideaUltimateSandboxDir"] = project.file(ideaUltimateSandboxDir)
extra["ideaPluginDir"] = project.file(ideaPluginDir)
extra["serialPluginDir"] = project.file(serialPluginDir)
extra["ideaUltimatePluginDir"] = project.file(ideaUltimatePluginDir)
extra["cidrPluginDir"] = project.file(cidrPluginDir)
extra["isSonatypeRelease"] = false
+3 -2
View File
@@ -11,7 +11,7 @@ dependencies {
compileOnly(project(":idea:idea-jvm"))
compile(intellijDep())
runtimeOnly(files(toolsJar()))
}
@@ -19,5 +19,6 @@ val ideaPluginDir: File by rootProject.extra
val ideaSandboxDir: File by rootProject.extra
runIdeTask("runIde", ideaPluginDir, ideaSandboxDir) {
dependsOn(":dist", ":ideaPlugin")
// TODO: add serialization plugin to pluginDir
dependsOn(":dist", ":ideaPlugin", ":kotlinx-serialization-compiler-plugin:dist")
}
@@ -11,14 +11,13 @@
<serialization.maven.plugin.resources>${basedir}/src/main/resources</serialization.maven.plugin.resources>
<serialization.target-src>${basedir}/target/src/main/kotlin</serialization.target-src>
<serialization.target-resources>${basedir}/target/resource</serialization.target-resources>
<kotlin.version>1.1-SNAPSHOT</kotlin.version>
<kotlin.version>1.2-SNAPSHOT</kotlin.version>
</properties>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-maven-serialization-plugin</artifactId>
<packaging>jar</packaging>
<version>0.1.1</version>
<version>0.2</version>
<description>Serialization plugin for Maven</description>
<repositories>
@@ -33,6 +32,7 @@
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
@@ -2,12 +2,16 @@ plugins {
id "com.jfrog.bintray" version "1.7.3"
}
group = 'org.jetbrains.kotlinx'
version = '0.1.1'
apply plugin: 'kotlin'
configureJvmProject(project)
configurePublishing(project)
group = 'org.jetbrains.kotlinx'
version = '0.2'
if (!project.hasProperty("deploy")) {
version = "$version-SNAPSHOT"
}
compileJava {
sourceCompatibility = 1.8
@@ -24,55 +28,35 @@ repositories {
dependencies {
compileOnly project(':kotlin-gradle-plugin-api')
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlin_version"
compileOnly project(':kotlin-stdlib')
compileOnly project(path: ':kotlin-compiler-embeddable', configuration: 'runtimeJar')
compileOnly project(':kotlin-allopen-compiler-plugin')
compileOnly 'org.jetbrains.kotlin:gradle-api:1.6'
}
def originalSrc = "$kotlin_root/plugins/kotlin-serialization/kotlin-serialization-compiler/src"
def targetSrc = file("$buildDir/kotlin-serialization-target-src")
task preprocessSources(type: Copy) {
from originalSrc
into targetSrc
filter { it.replaceAll('(?<!\\.)com\\.intellij', 'org.jetbrains.kotlin.com.intellij') }
}
sourceSets.main.java.srcDirs += targetSrc
compileKotlin.dependsOn preprocessSources
evaluationDependsOn(":kotlinx-serialization-compiler-plugin")
jar {
from(targetSrc) { include("META-INF/**") }
from(project(":kotlinx-serialization-compiler-plugin").sourceSets.main.output.classesDirs)
from(project(":kotlinx-serialization-compiler-plugin").sourceSets.main.output.resourcesDir)
manifestAttributes(manifest, project)
}
apply plugin: 'maven-publish'
ArtifactsKt.runtimeJar(project, EmbeddableKt.rewriteDepsToShadedCompiler(project, jar, {}), {})
task sourceJar(type: Jar, dependsOn: classes) {
classifier 'sources'
from sourceSets.main.allSource
}
publishing {
publications {
mavenProject(MavenPublication) {
from components.java
groupId project.group
artifactId project.name
version project.version
artifact sourceJar {
classifier "sources"
}
}
}
artifacts {
archives sourcesJar
archives javadocJar
}
bintray {
user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
publications = ['mavenProject']
configurations = ['archives']
if (!project.hasProperty("deploy")) {
dryRun = true
}
pkg {
repo = 'kotlinx'
name = 'kotlinx.serialization.plugin'
@@ -1,30 +1,38 @@
# Kotlin serialization IDEA plugin
Kotlin serialization plugin consists of three parts: a gradle compiler plugin, an IntelliJ plugin and a runtime library.
This is the IDEA plugin. Gradle plugin can be found in `libraries` folder.
Kotlin serialization plugin consists of three parts: a compiler plugin, an IntelliJ plugin and a runtime library.
This is the IDEA plugin. Gradle and Maven plugins can be found in `libraries` folder.
Please note that this plugin currently works only for highlighting and resolving symbols, and it doesn't work with embedded IDEA compiler.
To build any project with serialization within IDEA, you'll need to delegate all build actions to gradle:
`File - Settings - Build, Execution, Deployment - Build Tools - Gradle - Runner -` tick `Delegate IDE build/run actions to gradle`.
Maven and IntelliJ projects currently are not supported.
`File - Settings - Build, Execution, Deployment - Build Tools - Gradle - Runner -` tick `Delegate IDE build/run actions to gradle`.
IntelliJ projects currently are not supported.
Compiler plugins are uploaded on bintray: https://bintray.com/kotlin/kotlinx/kotlinx.serialization.plugin
## Building and usage
### Prerequisites:
Before all, follow the instructions from root README.md to download dependencies and build Kotlin compiler. (`ant -f update_dependencies.xml && ant dist`)
Before all, follow the instructions from root README.md to download dependencies and build Kotlin compiler. (`ant -f update_dependencies.xml && ./gradlew dist`)
**Plugin works only with IntelliJIDEA 2017.2 and higher.**
Make sure you have latest dev version of Kotlin plugin installed:
Open `Settings - Plugins - Browse Repositories... - Manage repositories` and add `https://teamcity.jetbrains.com/guestAuth/repository/download/Kotlin_master_CompilerAndPlugin_NoTests/.lastSuccessful/updatePlugins-IJ2017.2.xml`.
Update Kotlin plugin from new repository.
Make sure you have latest dev version of Kotlin plugin installed.
### With gradle:
Run `./gradlew buildPlugin`.
In IDEA, open `Settings - Plugins - Install plugin from disk...` and choose `build/distributions/Kotlin-serialization-0.1-SNAPSHOT.zip`
Run `./gradlew :kotlinx-serialization-compiler-plugin:dist`.
In IDEA, open `Settings - Plugins - Install plugin from disk...` and choose `$kotlin_root/dist/artifacts/Serialization/lib/kotlinx-serialization-compiler-plugin.jar`
### From within IDE (for development):
Open whole Kotlin project. Choose run configuration `IDEA` and run it. You'll get a fresh copy of IDEA with Kotlin and Kotlin-serialization plugins built from sources.
Run `./gradlew runIde` You'll get a fresh copy of IDEA with Kotlin and Kotlin-serialization plugins built from sources.
## Building gradle plugin
Run `./gradlew :kotlinx-gradle-serialization-plugin:install`
## Building maven plugin
Go to `$kotlin_root/libraries/tools/kotlin-maven-serialization`. Run `mvn install`
@@ -1,65 +0,0 @@
buildscript {
ext {
kotlin_root = file("$rootDir/../../..")
distDir = file("$kotlin_root/dist")
bootstrapCompilerFile = file("$distDir/kotlin-compiler-for-maven.jar")
kotlin_version = "1.1.3"
}
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
}
}
plugins {
id "org.jetbrains.intellij" version "0.2.15"
}
group 'org.jetbrains.kotlinx'
version '0.1-SNAPSHOT'
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
repositories {
mavenCentral()
}
dependencies {
compileOnly "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
compileOnly files(bootstrapCompilerFile.toString())
}
sourceSets {
main {
java {
srcDir 'src'
}
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile) {
compilerJarFile = bootstrapCompilerFile
}
jar {
from ('./src') {
include 'META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar'
include 'META-INF/plugin.xml'
}
}
apply plugin: 'org.jetbrains.intellij'
intellij {
if (findProperty("noIdeaSDK") == null) {
localPath "$kotlin_root/ideaSDK"
}
pluginName 'Kotlin-serialization'
downloadSources false
}
@@ -0,0 +1,35 @@
description = "Kotlin Serialization Compiler Plugin"
apply { plugin("kotlin") }
dependencies {
compileOnly(ideaSdkCoreDeps("intellij-core"))
compileOnly(project(":compiler:plugin-api"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:backend"))
compileOnly(project(":js:js.frontend"))
compileOnly(project(":js:js.translator"))
runtime(projectRuntimeJar(":kotlin-compiler"))
runtime(projectDist(":kotlin-stdlib"))
// val compileOnly by configurations
// val runtime by configurations
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
val jar = runtimeJar {
from(fileTree("$projectDir/src")) { include("META-INF/**") }
}
val serialPluginDir: File by rootProject.extra
dist(targetDir = File(serialPluginDir,"lib"), targetName = the<BasePluginConvention>().archivesBaseName.removePrefix("kotlin-") + ".jar")
ideaPlugin {
from(jar)
rename("^kotlin-", "")
}
@@ -1,6 +0,0 @@
#Mon Jul 31 13:14:07 MSK 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip
@@ -1,172 +0,0 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@@ -1,84 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="plugin-api" scope="PROVIDED" />
<orderEntry type="module" module-name="frontend" scope="PROVIDED" />
<orderEntry type="module" module-name="frontend.java" scope="PROVIDED" />
<orderEntry type="module" module-name="util" scope="PROVIDED" />
<orderEntry type="module" module-name="backend" scope="PROVIDED" />
<orderEntry type="module" module-name="js.translator" scope="PROVIDED" />
</component>
</module>
@@ -1 +0,0 @@
rootProject.name='serialization-plugin'
@@ -38,10 +38,10 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
fun generate() {
check(properties.isExternallySerializable) { "Class ${serializableDescriptor.name} is not externally serializable" }
generateSerializableClassPropertyIfNeeded()
val prop = generateSerializableClassPropertyIfNeeded()
val save = generateSaveIfNeeded()
val load = generateLoadIfNeeded()
if (save || load)
if (save || load || prop)
generateSerialDesc()
}
@@ -55,10 +55,11 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
protected abstract fun generateLoad(function: FunctionDescriptor)
private fun generateSerializableClassPropertyIfNeeded() {
private fun generateSerializableClassPropertyIfNeeded(): Boolean {
val property = serialDescPropertyDescriptor
?: return
?: return false
generateSerializableClassProperty(property)
return true
}
private fun generateSaveIfNeeded(): Boolean {
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
@@ -52,12 +53,12 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
KotlinBuiltIns.isUnit(T) -> SerialTypeInfo(property, "Unit", unit = true)
KotlinBuiltIns.isPrimitiveArray(T) -> TODO("primitive arrays are not supported yet")
KotlinBuiltIns.isNonPrimitiveArray(T.toClassDescriptor!!) -> {
val serializer = property.serializer?.toClassDescriptor ?:
val serializer = property.serializableWith?.toClassDescriptor ?:
property.module.findClassAcrossModuleDependencies(referenceArraySerializerId)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> {
val serializer = property.serializer?.toClassDescriptor ?:
val serializer = property.serializableWith?.toClassDescriptor ?:
property.module.findClassAcrossModuleDependencies(enumSerializerId)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
@@ -73,6 +74,7 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri
else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
?: findStandardKotlinTypeSerializer(module, kType) // otherwise see if there is a standard serializer
?: findEnumTypeSerializer(module, kType)
?: module.findClassAcrossModuleDependencies(contextSerializerId)
}
fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
@@ -105,7 +107,7 @@ fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDe
fun KotlinType.requiresPolymorphism(): Boolean {
return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true
|| this.toClassDescriptor?.modality == Modality.OPEN
|| (this.toClassDescriptor?.modality == Modality.OPEN && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class
|| this.containsTypeProjectionsInTopLevelArguments() // List<*>
}
@@ -35,6 +35,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCod
import org.jetbrains.kotlinx.serialization.compiler.backend.common.annotationVarsAndDesc
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -158,7 +159,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
return getQualifiedClassReferenceName(serializerClass)
}
else {
var args = if (serializerClass.classId == enumSerializerId)
var args = if (serializerClass.classId == enumSerializerId || serializerClass.classId == contextSerializerId)
listOf(createGetKClassExpression(kType.toClassDescriptor!!))
else kType.arguments.map {
val argSer = findTypeSerializer(module, it.type) ?: return null
@@ -166,7 +167,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
if (it.type.isMarkedNullable) JsNew(nullableSerClass, listOf(expr)) else expr
}
if (serializerClass.classId == referenceArraySerializerId)
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
args = listOf(createGetKClassExpression(kType.arguments[0].type.toClassDescriptor!!)) + args
return JsNew(getQualifiedClassReferenceName(serializerClass), args)
}
}
@@ -215,7 +216,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
JsInvocation(JsNameRef(readElementF, inputVar), serialClassDescRef)
).makeStmt()
// switch(index)
jsSwitch (indexVar) {
jsSwitch(indexVar) {
// -2: readAll = true
case(JsIntLiteral(-2)) {
+JsAstUtils.assignment(
@@ -230,12 +231,15 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
val sti = getSerialTypeInfo(property)
val innerSerial = if (sti.serializer == null) null else serializerInstance(sti.serializer, property.module, property.type)
val call = if (innerSerial == null) {
val unknownSer = (sti.elementMethodPrefix.isEmpty())
val readFunc =
inputClass.getFuncDesc("read${sti.elementMethodPrefix}ElementValue").single()
inputClass.getFuncDesc("read${sti.elementMethodPrefix}ElementValue")
// if readElementValue, must have 3 parameters, if readXXXElementValue - 2
.single { !unknownSer || (it is FunctionDescriptor && it.valueParameters.size == 3) }
.let { context.getNameForDescriptor(it) }
JsInvocation(JsNameRef(readFunc, inputVar),
serialClassDescRef,
JsIntLiteral(i))
val readArgs = mutableListOf(serialClassDescRef, JsIntLiteral(i))
if (unknownSer) readArgs.add(createGetKClassExpression(property.type.toClassDescriptor!!))
JsInvocation(JsNameRef(readFunc, inputVar), readArgs)
}
else {
val readFunc =
@@ -262,7 +266,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
if (KotlinBuiltIns.isCharOrNullableChar(property.type)) {
+JsAstUtils.assignment(
localProps[i],
TranslationUtils.coerce(context, localProps[i], TranslationUtils.getReturnTypeForCoercion(property.descriptor.getter!!))
TranslationUtils.coerce(context, localProps[i], context.currentModule.builtIns.charType)
).makeStmt()
}
@@ -298,6 +302,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject,
).makeStmt()
// deserialization constructor call
// todo: external deserialization with primary constructor and setters calls after resolution of KT-11586
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, context.bindingContext())
val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef()
val args: MutableList<JsExpression> = mutableListOf(bitMasks[0])
@@ -31,10 +31,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInf
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findEnumTypeSerializer
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findPolymorphicSerializer
import org.jetbrains.kotlinx.serialization.compiler.backend.common.requiresPolymorphism
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperty
import org.jetbrains.kotlinx.serialization.compiler.resolve.internalPackageFqName
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
import org.jetbrains.kotlinx.serialization.compiler.resolve.typeSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -113,8 +110,9 @@ internal fun ImplementationBodyCodegen.generateMethod(function: FunctionDescript
internal val enumSerializerId = ClassId(internalPackageFqName, Name.identifier("EnumSerializer"))
internal val polymorphicSerializerId = ClassId(internalPackageFqName, Name.identifier("PolymorphicSerializer"))
internal val polymorphicSerializerId = ClassId(packageFqName, Name.identifier("PolymorphicSerializer"))
internal val referenceArraySerializerId = ClassId(internalPackageFqName, Name.identifier("ReferenceArraySerializer"))
internal val contextSerializerId = ClassId(packageFqName, Name.identifier("ContextSerializer"))
// returns false is property should not use serializer
internal fun InstructionAdapter.stackValueSerializerInstance(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
@@ -150,7 +148,7 @@ internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: Mod
// instantiate all arg serializers on stack
val signature = StringBuilder("(")
when (serializer.classId) {
enumSerializerId -> {
enumSerializerId, contextSerializerId -> {
// a special way to instantiate enum -- need a enum KClass reference
aconst(codegen.typeMapper.mapType(kType))
AsmUtil.wrapJavaClassIntoKClass(this)
@@ -202,7 +200,7 @@ fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialType
}
ARRAY -> {
// check for explicit serialization annotation on this property
var serializer = property.serializer.toClassDescriptor
var serializer = property.serializableWith.toClassDescriptor
if (serializer == null) {
// no explicit serializer for this property. Select strategy by element type
when (type.elementType.sort) {
@@ -224,7 +222,8 @@ fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialType
return JVMSerialTypeInfo(property, Type.getType("Lkotlin/Unit;"), "Unit", unit = true)
// todo: more efficient enum support here, but only for enums that don't define custom serializer
// otherwise, it is a serializer for some other type
val serializer = findTypeSerializer(property.module, property.type, type)
val serializer = property.serializableWith?.toClassDescriptor
?: findTypeSerializer(property.module, property.type, type)
return JVMSerialTypeInfo(property, Type.getType("Ljava/lang/Object;"),
if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
@@ -237,6 +236,7 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType, asmType: Typ
else kType.typeSerializer.toClassDescriptor // check for serializer defined on the type
?: findStandardAsmTypeSerializer(module, asmType) // otherwise see if there is a standard serializer
?: findEnumTypeSerializer(module, kType)
?: module.findClassAcrossModuleDependencies(contextSerializerId)
}
fun findStandardAsmTypeSerializer(module: ModuleDescriptor, asmType: Type): ClassDescriptor? {
@@ -16,13 +16,11 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.annotationVarsAndDesc
@@ -238,10 +236,16 @@ class SerializerCodegenImpl(
val sti = getSerialTypeInfo(property, propertyType)
val useSerializer = stackValueSerializerInstance(codegen, sti)
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
if (unknownSer) {
aconst(codegen.typeMapper.mapType(property.type))
AsmUtil.wrapJavaClassIntoKClass(this)
}
invokevirtual(kInputType.internalName,
"read" + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + "ElementValue",
"(" + descType.descriptor + "I" +
(if (useSerializer) kSerialLoaderType.descriptor else "")
+ (if (unknownSer) AsmTypes.K_CLASS_TYPE.descriptor else "")
+ ")" + (if (sti.unit) "V" else sti.type.descriptor), false)
if (sti.unit) {
StackValue.putUnitInstance(this)
@@ -128,15 +128,8 @@ internal val ClassDescriptor?.classSerializer: KotlinType?
}
// serializer that was declared for this specific type or annotation from a class declaration
val KotlinType?.typeSerializer: KotlinType?
get() = this?.let {
// serializer annotation on this type or from a class
return it.annotations.serializableWith ?: (it.toClassDescriptor).classSerializer
}
// serializer that was declared specifically for this property via its own annotation or via annotation on its type
val PropertyDescriptor.propertySerializer: KotlinType?
get() = annotations.serializableWith ?: type.typeSerializer
val KotlinType.typeSerializer: KotlinType?
get() = this.annotations.serializableWith ?: (this.toClassDescriptor).classSerializer
fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
@@ -23,7 +23,7 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
val type = descriptor.type
val module = descriptor.module
val serializer = descriptor.propertySerializer
val serializableWith = descriptor.annotations.serializableWith
val optional = descriptor.annotations.serialOptional
val transient = descriptor.annotations.serialTransient
val annotations = descriptor.annotations
+7 -1
View File
@@ -180,7 +180,10 @@ include ":kotlin-build-common",
':kotlin-gradle-plugin:plugin-marker',
':kotlin-allopen:plugin-marker',
':kotlin-noarg:plugin-marker',
":test-instrumenter"
":test-instrumenter",
":kotlinx-serialization-compiler-plugin",
":kotlinx-gradle-serialization-plugin"
def isTeamcityBuild = hasProperty("teamcity") || System.getenv("TEAMCITY_VERSION") != null
def includeUltimate = hasProperty("intellijUltimateEnabled") && intellijUltimateEnabled != 'false'
@@ -294,3 +297,6 @@ project(':libraries:kotlin-prepush-hook').projectDir = "$rootDir/libraries/tools
project(':kotlin-gradle-plugin:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-gradle-plugin/plugin-marker")
project(':kotlin-allopen:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-allopen/plugin-marker")
project(':kotlin-noarg:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-noarg/plugin-marker")
project(':kotlinx-serialization-compiler-plugin').projectDir = file("$rootDir/plugins/kotlin-serialization/kotlin-serialization-compiler")
project(':kotlinx-gradle-serialization-plugin').projectDir = file("$rootDir/libraries/tools/kotlin-serialization")