0

I have multi-module spring project and some classes are like third party must be be mapped as external. So i used xml mapping, example classes:

data class GeoLocationEntity(
    val id: GeoLocationId,
)

data class GeoLocationId(
    val id: String,
    val timestamp: Instant,
)

example mapping:

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class entity-name="GeoLocationEntity" name="com.core.api.GeoLocationEntity"
           table="geo_location" mutable="false">
        <composite-id name="id" class="com.core.api.GeoLocationId" access="field">
            <key-property column="id" name="id"/>
            <key-property column="timestamp" name="timestamp"/>
        </composite-id>
    </class>

</hibernate-mapping>

But this way doesn't work:

org.hibernate.InstantiationException: Unable to locate constructor for embeddable 'com.core.api.GeoLocationId'
    at org.hibernate.metamodel.internal.EmbeddableInstantiatorPojoStandard.instantiate(EmbeddableInstantiatorPojoStandard.java:58)
    at org.hibernate.type.ComponentType.deepCopy(ComponentType.java:483)
    at org.hibernate.event.internal.DefaultMergeEventListener.copyCompositeTypeId(DefaultMergeEventListener.java:246)
    at org.hibernate.event.internal.DefaultMergeEventListener.merge(DefaultMergeEventListener.java:171)
    at org.hibernate.event.internal.DefaultMergeEventListener.doMerge(DefaultMergeEventListener.java:148)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:132)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:86)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:850)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:836)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:319)
    at jdk.proxy3/jdk.proxy3.$Proxy133.merge(Unknown Source)
    at com.example.aop.demo_service.MockRepo.processData_aroundBody2(MockRepo.kt:17)
    at com.example.aop.demo_service.MockRepo$AjcClosure3.run(MockRepo.kt:1)
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:67)
    at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:73)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:71)
    at com.example.aop.demo_service.MockRepo.processData(MockRepo.kt:1)
    at com.example.aop.demo_service.ServiceImpl.processRequest(Service.kt:16)
    at com.example.aop.demo_service.DemoServiceApplicationTests.contextLoadsFail(DemoServiceApplicationTests.kt:27)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

Same classes with annotation mapping works fine. Forcing enhancement class not helping. Is it any way to may it works ?

Update: java records didn't helped too. it's can be used only as DTO So im think there is no way to use external immutable class as Entity

1
  • plz mark answer as "Accepted" :P Commented May 16 at 12:07

1 Answer 1

1

I'm not bit expert in Kotlin and you didn't provide project for run and check but solution could just as simple as create constructors in your data classes. Just it it a try.

Here is what google suggest:

When working with Kotlin and Hibernate, using embedded classes requires careful handling of constructors. Hibernate relies on a no-argument constructor to instantiate entities, but Kotlin's primary constructor syntax can make this challenging. Here's how to address this:

The Issue

Kotlin's primary constructor, while concise, doesn't provide a default no-argument constructor. When Hibernate tries to instantiate an entity or embedded object using reflection, it requires a no-argument constructor, leading to an InstantiationException.

Solutions

  • kotlin-jpa Plugin:

    • The recommended approach is to use the kotlin-jpa compiler plugin.

    • It automatically generates a no-argument constructor for classes annotated with @Entity, @MappedSuperclass, or @Embeddable.

    • To enable it, add the plugin to your Maven or Gradle build configuration.

Sign up to request clarification or add additional context in comments.

1 Comment

Same can be done without kotlin, it's just immutable class. kotlin-jpa enabled in root project, component scan specified to module package. Need an opportunity to make entity from third party class

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.