Skip to content

Commit

Permalink
Working on analyzing JPA entities in blaze processor
Browse files Browse the repository at this point in the history
  • Loading branch information
kurbaniec committed Dec 14, 2023
1 parent 6833ad7 commit 0511656
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 1 deletion.
10 changes: 10 additions & 0 deletions bee.persistent.test/datasource.a/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ plugins {
alias(libs.plugins.spring.boot).apply(false)
alias(libs.plugins.spring.dependencymanagement)
alias(libs.plugins.ksp)
alias(libs.plugins.kotlin.allopen)
alias(libs.plugins.kotlin.noarg)
id("bee.generative")
}

Expand Down Expand Up @@ -63,3 +65,11 @@ beeGenerative {
arg("datasource", "a")
}

noArg {
annotations("jakarta.persistence.Entity", "jakarta.persistence.Embeddable")
}

allOpen {
annotations("jakarta.persistence.Entity")
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.beeproduced.datasource.a

import jakarta.persistence.*
import java.io.Serializable
import java.util.*

/**
*
*
* @author Kacper Urbaniec
* @version 2023-12-14
*/

@Entity
@Table(name = "songs")
data class Song(
@Id
@GeneratedValue
val id: UUID,
val name: String,
@Column(name = "interpret_id")
val interpretId: UUID,
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "interpret_id", insertable = false, updatable = false)
val interpret: Person?,
@Column(name = "producer_id")
val producerId: UUID,
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "producer_id", insertable = false, updatable = false)
val producer: Company?,
) {
@Transient
var altName: String = ""
@Column(name = "secret_info")
private val secretInfo = "secret!"
}

@Entity
@Table(name = "persons")
data class Person(
@Id
@GeneratedValue
val id: UUID,
val firstname: String,
val lastname: String,
@OneToMany(fetch = FetchType.LAZY, mappedBy = "person")
val companies: Set<CompanyPerson>? = null
)

@Entity
@Table(name = "companies")
data class Company(
@Id
@GeneratedValue
val id: UUID,
@OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
val employees: Set<CompanyPerson>?
)

@Embeddable
data class CompanyPersonId(
@Column(name = "company_id")
val companyId: UUID,
@Column(name = "person_id")
val personId: UUID
) : Serializable

@Entity
@Table(name = "company_persons")
data class CompanyPerson(
@EmbeddedId
val id: CompanyPersonId,
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "company_id", referencedColumnName = "id", insertable = false, updatable = false)
val company: Company?,
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "person_id", referencedColumnName = "id", insertable = false, updatable = false)
val person: Person?,
)

data class FooBar(
val foo: String,
val bar: String
)

@Converter
class FooBarConverter : AttributeConverter<FooBar, String> {
override fun convertToDatabaseColumn(attribute: FooBar?): String? {
return if (attribute == null) null
else "${attribute.foo}$$${attribute.bar}"
}

override fun convertToEntityAttribute(dbData: String?): FooBar? {
if (dbData.isNullOrEmpty()) return null
val data = dbData.split("$$")
if (data.count() < 2) return null
return FooBar(data[0], data[1])
}
}

@JvmInline
value class Foxtrot(private val s: String)

// https://youtrack.jetbrains.com/issue/KT-50518/Boxing-Unboxing-methods-for-JvmInline-value-classes-should-be-public-accessible
fun unwrapInline(v: Any): Any = v.javaClass.getMethod("unbox-impl").invoke(v)

@Entity
data class WeirdClass(
@Id
val id: UUID,
@Convert(converter = FooBarConverter::class)
val fooBar: FooBar,
val foxtrot: Foxtrot
)
10 changes: 10 additions & 0 deletions bee.persistent.test/datasource.b/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ plugins {
alias(libs.plugins.spring.boot).apply(false)
alias(libs.plugins.spring.dependencymanagement)
alias(libs.plugins.ksp)
alias(libs.plugins.kotlin.allopen)
alias(libs.plugins.kotlin.noarg)
id("bee.generative")
}

Expand Down Expand Up @@ -62,3 +64,11 @@ tasks.withType<Test> {
beeGenerative {
arg("datasource", "b")
}

noArg {
annotations("jakarta.persistence.Entity", "jakarta.persistence.Embeddable")
}

allOpen {
annotations("jakarta.persistence.Entity")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import com.beeproduced.bee.generative.BeeGenerativeFeature
import com.beeproduced.bee.generative.BeeGenerativeInput
import com.beeproduced.bee.generative.Shared
import com.beeproduced.bee.generative.processor.Options
import com.beeproduced.bee.generative.util.resolveTypeAlias
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.symbol.*
import jakarta.persistence.Entity
import jakarta.persistence.Transient

/**
*
Expand All @@ -23,13 +28,62 @@ class BeePersistentBlazeFeature : BeeGenerativeFeature {
shared["datasource$name"] = "Hey"
return BeeGenerativeConfig(
packages = setOf(),
annotatedBy = setOf(),
annotatedBy = setOf(Entity::class.qualifiedName!!),
)
}

override fun process(input: BeeGenerativeInput) {
val logger = input.logger
logger.info("Hey")
logger.info(input.shared.keys.toString())

val symbols = input.symbols

val types = symbols.annotatedBy.getValue(Entity::class.qualifiedName!!)

for (t in types) {
logger.info(t.simpleName.asString())
logger.info(t.packageName.asString())

// Properties
val properties = t.declarations
.filterIsInstance<KSPropertyDeclaration>()
.filter { it.annotations.none { isTransientAnnotation(it, logger)} }
.filter { it.hasBackingField }
for (p in properties) {
val simpleName = p.simpleName.asString()
val typeName = p.type.resolve().resolveTypeAlias().declaration.qualifiedName?.asString()
val modifier = p.modifiers
val valueClass = if (isValueClass(p))
getUnderlyingTypeOfValueClass(p)?.declaration?.qualifiedName?.asString()
else "not value class"
logger.info(" $simpleName, $typeName, $modifier, $valueClass")
}

logger.info("---")
}
}

private fun isTransientAnnotation(annotation: KSAnnotation, logger: KSPLogger): Boolean {
// Resolve the annotation to its KSClassDeclaration and compare it with Transient::class
val check = annotation.annotationType.resolve().declaration.qualifiedName?.asString()
val anno = Transient::class.qualifiedName
// logger.info("check $check")
// logger.info("anno $anno")
return check == anno
}

fun isValueClass(property: KSPropertyDeclaration): Boolean {
val type = property.type.resolve().declaration
return type is KSClassDeclaration && type.annotations.any { it.shortName.asString() == "JvmInline" }
}

fun getUnderlyingTypeOfValueClass(property: KSPropertyDeclaration): KSType? {
val type = property.type.resolve().declaration
if (type is KSClassDeclaration && type.annotations.any { it.shortName.asString() == "JvmInline" }) {
// Assuming value classes have only one primary constructor property
return type.primaryConstructor?.parameters?.firstOrNull()?.type?.resolve()
}
return null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.beeproduced.bee.persistent.blaze.processor.codegen

/**
*
*
* @author Kacper Urbaniec
* @version 2023-12-14
*/
object BeePersistentBlazeOptions {
const val scanPackage = "persistentScanPackage"
}

0 comments on commit 0511656

Please sign in to comment.