Skip to content

Fix @QueryProjection constructor generation for Kotlin value classes (@JvmInline)#1762

Merged
velo merged 2 commits into
OpenFeign:masterfrom
s-chan-o:fix/query-projection-kotlin-value-class
May 27, 2026
Merged

Fix @QueryProjection constructor generation for Kotlin value classes (@JvmInline)#1762
velo merged 2 commits into
OpenFeign:masterfrom
s-chan-o:fix/query-projection-kotlin-value-class

Conversation

@s-chan-o
Copy link
Copy Markdown
Contributor

Problem

When a DTO annotated with @QueryProjection has constructor parameters of Kotlin value class (@JvmInline) types, the APT processor fails to generate a constructor in the Q-type.

Reproducer:

@JvmInline
value class UserId(val value: String)

data class UserDto @QueryProjection constructor(
    val id: UserId,
    val name: String
)

Expected: QUserDto is generated with a constructor accepting Expression<String>
Actual: QUserDto is generated without a constructor

Root Cause

In ExtendedTypeFactory.createClassType(), Kotlin value classes are treated as opaque class types. TypeCategory.get(name) returns TypeCategory.SIMPLE for them, but there is no registered mapping from the value class type (e.g. UserId) to a QueryDSL path type (e.g. StringPath), so type resolution returns null.

By contrast, @Entity fields work correctly because the Kotlin compiler exposes them at the JVM field level as their underlying type (e.g. String).

Note: This issue was already fixed for KSP codegen in #1404. This PR applies the same fix to the APT/kapt processor.

Fix

  1. ExtendedTypeFactory: Detect @JvmInline-annotated classes in createClassType() and unwrap them to the type of their single underlying field before type resolution.

  2. TypeElementHandler: Add a null guard in getType(VariableElement) as a defensive measure.

Test

Added queryProjection_withKotlinValueClassParameter_generatesConstructor() to QuerydslAnnotationProcessorCompileTest using the existing google/compile-testing infrastructure. The test verifies that QUserDto is generated with a constructor accepting Expression<String> when the DTO uses a @JvmInline value class parameter.

When a DTO annotated with @QueryProjection has constructor parameters
of Kotlin value class types (@JvmInline), the APT processor failed to
generate a constructor in the Q-type because ExtendedTypeFactory could
not resolve the value class to a QueryDSL path type.

Fix by detecting @JvmInline annotated classes in createClassType() and
unwrapping them to their single underlying field type before type
resolution. Also add null guard in TypeElementHandler.getType() as a
defensive measure.
…n-kotlin-value-class

# Conflicts:
#	querydsl-tooling/querydsl-apt/src/test/java/com/querydsl/apt/QuerydslAnnotationProcessorCompileTest.java
@velo velo enabled auto-merge (squash) May 27, 2026 20:00
@velo velo merged commit 072009e into OpenFeign:master May 27, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants