spring-projects / spring-projects/spring-framework
IllegalArgumentException: argument type mismatch": Delegate 'by' pattern breaks when property type is a nullable Value Class
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
If I have something like this:
@Repository
internal class ContractDomainRepositoryImpl (
private val contractRepositoryImpl: ContractRepositoryImpl,
private val contractDomainEntityMapper: ContractDomainEntityMapperImpl,
) : ContractDomainRepository,
ContractDomainPostRepository by ContractDomainPostRepositoryDelegate(
contractRepositoryImpl,
contractDomainEntityMapper
),
ContractDomainPutRepository by ContractDomainPutRepositoryDelegate(
contractRepositoryImpl,
contractDomainEntityMapper
),
ContractDomainDeleteRepository by ContractDomainDeleteRepositoryDelegate(
contractRepositoryImpl
)
And the interface for ContractDomainPutRepository looks something like:
interface ContractDomainPutRepository {
suspend fun updateContract(
contract: Contract,
operationalData: ContractOperationalData,
userId: UserId,
organisationId: OrganisationId?,
projectId: ProjectId?,
): Pair<Contract, ContractOperationalData>
}
And UserId is a value class, like:
@JvmInline
value class UserId(override val value: Long) : Identifier<Long> {
init {
// TODO() here it is ok for UserId to be 0, for testing purposes only. Adjust later!
if (value < 0) {
throw ValidationError(
message = "UserId must be a positive value",
)
}
}
},
then trying to call ContractDomainPutRepository.updateContract (from the service layer, that injects ContractDomainRepositoryImpl) will not work
I keep getting Exception caught in ContractDomainServiceImpl: java.lang.IllegalArgumentException: argument type mismatch
Removing the nullable Value Classes, like:
interface ContractDomainPutRepository {
suspend fun updateContract(
contract: Contract,
operationalData: ContractOperationalData,
userId: UserId,
organisationId: OrganisationId,
projectId: ProjectId,
): Pair<Contract, ContractOperationalData>
},
makes the issue go away
But I need some of value classes to be nullable
The root cause I believe is that Spring's CGLIB proxying doesn't work well with Kotlin value classes since they're implemented as inline classes at compile time and have special JVM representations.
LLM Claude
If you LLM Claude with: "Value classes result it wrong type mismatch error in java class when passed as parameter in spring annotated bean. A plain class works fine. Explain". It says:
When Spring tries to:
Create proxies (CGLIB or JDK proxies)
Inject dependencies
Call methods from Java code
It sees the mangled signatures and underlying primitive types, not the value class wrapper. This causes type mismatches.
Key Takeaway
Value classes are optimized for performance by avoiding object allocation, but this optimization conflicts with Spring's reflection-heavy, proxy-based dependency injection, especially when Java interop is involved. For Spring beans, regular classes are safer unless you carefully manage where value classes are used.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the provided ContractDomainRepository delegation and the updateContract call using nullable and non-nullable Kotlin value classes. Reproduce the IllegalArgumentException and compare the generated or proxied method argument types; done means the nullable value-class parameters invoke successfully without the argument type mismatch.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin, spring
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100