Kotlinx.serialization: Cannot compile class with default value that depends on parameters

Created on 20 May 2018  路  7Comments  路  Source: Kotlin/kotlinx.serialization

When using version 0.5.0 trying to compile this class:

@Serializable
data class Name(
    val first: String,
    val last: String,
    @Optional val full: String = "$first $last"
)

gives this compile error:

Cause: Don't know how to generate outer expression: Class: class Name
The root cause was thrown at: CodegenContext.java:215
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:319)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:280)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:325)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:333)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:329)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl.genInitProperty(SerializableCodegenImpl.kt:216)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl.doGenerateConstructorImpl(SerializableCodegenImpl.kt:153)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl.access$doGenerateConstructorImpl(SerializableCodegenImpl.kt:41)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl$generateInternalConstructor$1.invoke(SerializableCodegenImpl.kt:65)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl$generateInternalConstructor$1.invoke(SerializableCodegenImpl.kt:41)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.JVMCodegenUtilKt$generateMethod$1.doGenerateBody(JVMCodegenUtil.kt:109)
    at org.jetbrains.kotlin.codegen.FunctionGenerationStrategy$CodegenBased.generateBody(FunctionGenerationStrategy.java:80)
    at org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethodBody(FunctionCodegen.java:620)
    at org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethodBody(FunctionCodegen.java:391)
    at org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethod(FunctionCodegen.java:244)
    at org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethod(FunctionCodegen.java:168)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.JVMCodegenUtilKt.generateMethod(JVMCodegenUtil.kt:106)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl.generateInternalConstructor(SerializableCodegenImpl.kt:65)
    at org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen.generateSyntheticInternalConstructor(SerializableCodegen.kt:39)
    at org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen.generate(SerializableCodegen.kt:33)
    at org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCodegenImpl$Companion.generateSerializableExtensions(SerializableCodegenImpl.kt:52)
    at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationCodegenExtension.generateClassSyntheticParts(SerializationCodegenExtension.kt:29)
    at org.jetbrains.kotlin.codegen.ImplementationBodyCodegen.generateSyntheticPartsAfterBody(ImplementationBodyCodegen.java:424)
    at org.jetbrains.kotlin.codegen.MemberCodegen.generate(MemberCodegen.java:134)
    at org.jetbrains.kotlin.codegen.MemberCodegen.genClassOrObject(MemberCodegen.java:305)
    at org.jetbrains.kotlin.codegen.MemberCodegen.genClassOrObject(MemberCodegen.java:289)
    at org.jetbrains.kotlin.codegen.PackageCodegenImpl.generateClassOrObject(PackageCodegenImpl.java:161)
    at org.jetbrains.kotlin.codegen.PackageCodegenImpl.generateClassesAndObjectsInFile(PackageCodegenImpl.java:86)
    at org.jetbrains.kotlin.codegen.PackageCodegenImpl.generateFile(PackageCodegenImpl.java:119)
    at org.jetbrains.kotlin.codegen.PackageCodegenImpl.generate(PackageCodegenImpl.java:66)
    at org.jetbrains.kotlin.codegen.DefaultCodegenFactory.generatePackage(CodegenFactory.kt:97)
    at org.jetbrains.kotlin.codegen.DefaultCodegenFactory.generateModule(CodegenFactory.kt:68)
    at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.doGenerateFiles(KotlinCodegenFacade.java:47)
    at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.compileCorrectFiles(KotlinCodegenFacade.java:39)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.generate(KotlinToJVMBytecodeCompiler.kt:454)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:150)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:161)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:63)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:107)
    at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:51)
    at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:96)
    at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:463)
    at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:98)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:228)
    at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:99)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.execIncrementalCompiler(CompileServiceImpl.kt:538)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.access$execIncrementalCompiler(CompileServiceImpl.kt:98)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:418)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:98)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:920)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:98)
    at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:950)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.doCompile(CompileServiceImpl.kt:919)
    at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:417)
    at sun.reflect.GeneratedMethodAccessor94.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.UnsupportedOperationException: Don't know how to generate outer expression: Class: class Name
    at org.jetbrains.kotlin.codegen.context.CodegenContext.getOuterExpression(CodegenContext.java:215)
    at org.jetbrains.kotlin.codegen.context.CodegenContext.lookupInContext(CodegenContext.java:540)
    at org.jetbrains.kotlin.codegen.context.MethodContext.lookupInContext(MethodContext.java:81)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.findCapturedValue(ExpressionCodegen.java:1854)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.findLocalOrCapturedValue(ExpressionCodegen.java:1845)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.visitSimpleNameExpression(ExpressionCodegen.java:1760)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.visitSimpleNameExpression(ExpressionCodegen.java:110)
    at org.jetbrains.kotlin.psi.KtNameReferenceExpression.accept(KtNameReferenceExpression.kt:59)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:298)
    ... 70 more
1 bug compiler-plugin design

Most helpful comment

Any updates on this?

All 7 comments

I suppose that supporting that specific case would require a lot of effort. In general, for every serialization framework you can apply recommendation 'if value can be computed from other values, better to make it transient'.

Well, it not always computed from a default value. Perhaps the user has a middle name that is in the full name.

Does it take a lot of effort because you are not calling the generated constructor for default values but rather compute them yourselves?

Any updates on this?

Adding transient does not solve it for me either (it does not exist in my json)

Moshi was handling that without complaining or requiring any special decoration.

I got the exact same problem. Anyone got a solution?

I can confirm that this bug is still present and that there are use cases where this would be very useful. I now have to decide how to circumvent this problem in my application. If someone knows some kind of workaround, I'd be very thankful for that.

If I remeber it right, it worked for me to use init:

@Serializable
data class Name(
    val first: String,
    val last: String
){
    val full:String
    init{
        full = "$first $last"
    }
}
Was this page helpful?
0 / 5 - 0 ratings