Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move Java reflect specific extensions into a separate package #299

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/com/squareup/kotlinpoet/AnnotationSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asClassName
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These imports will disappear when the factory methods that use them are moved into "jvm"

import java.lang.reflect.Array
import java.util.Objects
import javax.lang.model.element.AnnotationMirror
Expand Down
53 changes: 0 additions & 53 deletions src/main/java/com/squareup/kotlinpoet/ClassName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@

package com.squareup.kotlinpoet

import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.NestingKind.MEMBER
import javax.lang.model.element.NestingKind.TOP_LEVEL
import javax.lang.model.element.PackageElement
import javax.lang.model.element.TypeElement
import kotlin.reflect.KClass

/** A fully-qualified class name for top-level and member classes. */
Expand Down Expand Up @@ -156,55 +150,8 @@ class ClassName internal constructor(
}
}

@JvmName("get")
fun Class<*>.asClassName(): ClassName {
require(!isPrimitive) { "primitive types cannot be represented as a ClassName" }
require(Void.TYPE != this) { "'void' type cannot be represented as a ClassName" }
require(!isArray) { "array types cannot be represented as a ClassName" }
val names = mutableListOf<String>()
var c = this
while (true) {
names += c.simpleName
val enclosing = c.enclosingClass ?: break
c = enclosing
}
// Avoid unreliable Class.getPackage(). https://github.com/square/javapoet/issues/295
val lastDot = c.name.lastIndexOf('.')
if (lastDot != -1) names += c.name.substring(0, lastDot)
names.reverse()
return ClassName(names)
}

@JvmName("get")
fun KClass<*>.asClassName(): ClassName {
qualifiedName?.let { return ClassName.bestGuess(it) }
throw IllegalArgumentException("$this cannot be represented as a ClassName")
}

/** Returns the class name for `element`. */
@JvmName("get")
fun TypeElement.asClassName(): ClassName {
fun isClassOrInterface(e: Element) = e.kind.isClass || e.kind.isInterface

fun getPackage(type: Element): PackageElement {
var t = type
while (t.kind != ElementKind.PACKAGE) {
t = t.enclosingElement
}
return t as PackageElement
}

val names = mutableListOf<String>()
var e: Element = this
while (isClassOrInterface(e)) {
val eType = e as TypeElement
require(eType.nestingKind.isOneOf(TOP_LEVEL, MEMBER)) {
"unexpected type testing"
}
names += eType.simpleName.toString()
e = eType.enclosingElement
}
names += getPackage(this).qualifiedName.toString()
names.reverse()
return ClassName(names)
}
1 change: 1 addition & 0 deletions src/main/java/com/squareup/kotlinpoet/CodeBlock.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import javax.lang.model.element.Element
import javax.lang.model.type.TypeMirror
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/squareup/kotlinpoet/FileSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.AnnotationSpec.UseSiteTarget.FILE
import com.squareup.kotlinpoet.jvm.asClassName
import java.io.ByteArrayInputStream
import java.io.File
import java.io.IOException
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/squareup/kotlinpoet/FunSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import com.squareup.kotlinpoet.KModifier.EXPECT
import com.squareup.kotlinpoet.KModifier.EXTERNAL
import com.squareup.kotlinpoet.KModifier.INLINE
import com.squareup.kotlinpoet.KModifier.VARARG
import com.squareup.kotlinpoet.jvm.asClassName
import com.squareup.kotlinpoet.jvm.asTypeName
import com.squareup.kotlinpoet.jvm.asTypeVariableName
import java.lang.reflect.Type
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.Modifier
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/squareup/kotlinpoet/ParameterSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asClassName
import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("ParameterizedTypeNames")

package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asClassName
import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Modifier
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
Expand Down Expand Up @@ -109,7 +109,3 @@ class ParameterizedTypeName internal constructor(
}
}
}

/** Returns a parameterized type equivalent to `type`. */
@JvmName("get")
fun ParameterizedType.asParameterizedTypeName() = ParameterizedTypeName.get(this, mutableMapOf())
2 changes: 2 additions & 0 deletions src/main/java/com/squareup/kotlinpoet/PropertySpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.FunSpec.Companion.GETTER
import com.squareup.kotlinpoet.FunSpec.Companion.SETTER
import com.squareup.kotlinpoet.jvm.asClassName
import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import kotlin.reflect.KClass

Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/squareup/kotlinpoet/TypeAliasSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.squareup.kotlinpoet.KModifier.ACTUAL
import com.squareup.kotlinpoet.KModifier.INTERNAL
import com.squareup.kotlinpoet.KModifier.PRIVATE
import com.squareup.kotlinpoet.KModifier.PUBLIC
import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import kotlin.reflect.KClass

Expand Down
9 changes: 1 addition & 8 deletions src/main/java/com/squareup/kotlinpoet/TypeName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asClassName
import java.lang.reflect.GenericArrayType
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
Expand Down Expand Up @@ -217,14 +218,6 @@ abstract class TypeName internal constructor(
@JvmField val FLOAT = ClassName("kotlin", "Float")
@JvmField val DOUBLE = ClassName("kotlin", "Double")

/** Returns a [TypeName] equivalent to this [TypeMirror]. */
@JvmName("get")
fun TypeMirror.asTypeName() = TypeName.get(this, mutableMapOf())

/** Returns a [TypeName] equivalent to this [KClass]. */
@JvmName("get")
fun KClass<*>.asTypeName() = asClassName()

/** Returns a [TypeName] equivalent to this [Type]. */
@JvmName("get")
fun Type.asTypeName() = TypeName.get(this, mutableMapOf())
2 changes: 2 additions & 0 deletions src/main/java/com/squareup/kotlinpoet/TypeSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.KModifier.PUBLIC
import com.squareup.kotlinpoet.jvm.asClassName
import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import kotlin.reflect.KClass

Expand Down
16 changes: 1 addition & 15 deletions src/main/java/com/squareup/kotlinpoet/TypeVariableName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("TypeVariableNames")

package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import java.util.Collections
import javax.lang.model.element.TypeParameterElement
Expand Down Expand Up @@ -132,16 +131,3 @@ class TypeVariableName private constructor(
}
}
}

/** Returns type variable equivalent to `mirror`. */
@JvmName("get")
fun TypeVariable.asTypeVariableName()
= (asElement() as TypeParameterElement).asTypeVariableName()

/** Returns type variable equivalent to `element`. */
@JvmName("get")
fun TypeParameterElement.asTypeVariableName(): TypeVariableName {
val name = simpleName.toString()
val boundsTypeNames = bounds.map { it.asTypeName() }
return TypeVariableName.of(name, boundsTypeNames, variance = null)
}
10 changes: 1 addition & 9 deletions src/main/java/com/squareup/kotlinpoet/WildcardTypeName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("WildcardTypeNames")

package com.squareup.kotlinpoet

import com.squareup.kotlinpoet.jvm.asTypeName
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
import javax.lang.model.element.TypeParameterElement
Expand Down Expand Up @@ -105,10 +104,3 @@ class WildcardTypeName private constructor(
}
}
}

@JvmName("get")
fun javax.lang.model.type.WildcardType.asWildcardTypeName()
= WildcardTypeName.get(this, mutableMapOf())

@JvmName("get")
fun WildcardType.asWildcardTypeName() = WildcardTypeName.get(this, mutableMapOf())
73 changes: 73 additions & 0 deletions src/main/java/com/squareup/kotlinpoet/jvm/ClassNames.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2017 Square, Inc.
*
* 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.
*/
@file:JvmName("ClassNamesJvm")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally that should remain as "ClassNames", but there's the KClass<*>.asClassName() function that stays in the main module and Java clients that need methods from both versions will have to use fully-qualified class names. Maybe there's a better way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about @JvmMultifileClass and the same @JvmName?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt it'll work across multiple modules, but I can give it a try

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There won't be multiple modules. You'll have the common module with common code and then the jvm module will implement the common module and add JVM-specific things. There will only be one class file in the final artifact. And then for JS there will be a JS module, etc., and they're free to have platform-specific things as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. Didn't think about it from the perspective of cross-platform modules, rather that kotlinpoet-jvm will just provide extensions for kotlinpoet. I'm curious to try the cross-platform approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah the nice thing about using multiplatform rather than multiple modules is that you pick one artifact based on the platform on which your code generator runs. And if your code generator is multiplatform, then you only get the common stuff.

If we can do multifile classes for now let's do that. If we end up doing two artifacts it's an easy change to make.


package com.squareup.kotlinpoet.jvm

import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.isOneOf
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.NestingKind
import javax.lang.model.element.PackageElement
import javax.lang.model.element.TypeElement

@JvmName("get")
fun Class<*>.asClassName(): ClassName {
require(!isPrimitive) { "primitive types cannot be represented as a ClassName" }
require(Void.TYPE != this) { "'void' type cannot be represented as a ClassName" }
require(!isArray) { "array types cannot be represented as a ClassName" }
val names = mutableListOf<String>()
var c = this
while (true) {
names += c.simpleName
val enclosing = c.enclosingClass ?: break
c = enclosing
}
// Avoid unreliable Class.getPackage(). https://github.com/square/javapoet/issues/295
val lastDot = c.name.lastIndexOf('.')
if (lastDot != -1) names += c.name.substring(0, lastDot)
names.reverse()
return ClassName(names)
}

/** Returns the class name for `element`. */
@JvmName("get")
fun TypeElement.asClassName(): ClassName {
fun isClassOrInterface(e: Element) = e.kind.isClass || e.kind.isInterface

fun getPackage(type: Element): PackageElement {
var t = type
while (t.kind != ElementKind.PACKAGE) {
t = t.enclosingElement
}
return t as PackageElement
}

val names = mutableListOf<String>()
var e: Element = this
while (isClassOrInterface(e)) {
val eType = e as TypeElement
require(eType.nestingKind.isOneOf(NestingKind.TOP_LEVEL, NestingKind.MEMBER)) {
"unexpected type testing"
}
names += eType.simpleName.toString()
e = eType.enclosingElement
}
names += getPackage(this).qualifiedName.toString()
names.reverse()
return ClassName(names)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2017 Square, Inc.
*
* 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.
*/
@file:JvmName("ParameterizedTypeNames")

package com.squareup.kotlinpoet.jvm

import com.squareup.kotlinpoet.ParameterizedTypeName
import java.lang.reflect.ParameterizedType

/** Returns a parameterized type equivalent to `type`. */
@JvmName("get")
fun ParameterizedType.asParameterizedTypeName() = ParameterizedTypeName.get(this, mutableMapOf())
30 changes: 30 additions & 0 deletions src/main/java/com/squareup/kotlinpoet/jvm/TypeNames.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2017 Square, Inc.
*
* 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.
*/
@file:JvmName("TypeNamesJvm")

package com.squareup.kotlinpoet.jvm

import com.squareup.kotlinpoet.TypeName
import java.lang.reflect.Type
import javax.lang.model.type.TypeMirror

/** Returns a [TypeName] equivalent to this [TypeMirror]. */
@JvmName("get")
fun TypeMirror.asTypeName() = TypeName.get(this, mutableMapOf())

/** Returns a [TypeName] equivalent to this [Type]. */
@JvmName("get")
fun Type.asTypeName() = TypeName.get(this, mutableMapOf())