square / javapoet

A Java API for generating .java source files.
Apache License 2.0
10.82k stars 1.37k forks source link

Provide an API to set TypeVariableName bounds lazily #842

Open yigit opened 3 years ago

yigit commented 3 years ago

Currently, there is no way to set bounds of a TypeVariableName after it is constructed (which makes sense as they are designed to be immutable).

Unfortunately, creating TypeName for self referencing types becomes impossible without it (class SelfReferencing<T : SelfReferencing<T>>)

JavaPoet solves this problem internally by using a private constructor: https://github.com/square/javapoet/blame/master/src/main/java/com/squareup/javapoet/TypeVariableName.java#L108

Would it be possible to open up a builder that receives a List (and keeps it as is) so we can implement the same workaround for KSP ?

For reference, here is the WIP CL in Room where we are trying to workaround this issue. Unfortunately, the only solution we have is reflection which does not feel great.

tbroyer commented 3 years ago

You can use a TypeVariableName.get(name) to reference the "outer" type variable, it doesn't have to represent the recursion.

$ jshell --class-path ~/.m2/repository/com/squareup/javapoet/1.13.0/javapoet-1.13.0.jar
|  Welcome to JShell -- Version 11.0.11
|  For an introduction type: /help intro

jshell> import com.squareup.javapoet.*;

jshell> JavaFile.builder("pkg",
   ...>   TypeSpec.classBuilder("Cls")
   ...>    .addTypeVariable(TypeVariableName.get("T", ParameterizedTypeName.get(ClassName.get("pkg", "Cls"), TypeVariableName.get("T"))))
   ...>    .build()).build()
$2 ==> package pkg;

class Cls<T extends Cls<T>> {
}

jshell> 
yigit commented 3 years ago

Thanks for the tip.

Unfortunately, this happens at a lower layer. We have some wrapper around KSP - KSType (kotlin symbol processing) and JavaAP-TypeMirror both of which provide an API to get a typeName. I'm trying to make sure they return the exactly same TypeName for the same type.