Hey! I try migrate my project to spring-boot:3.0.2, but part of CrudRepository methods broken. We follow to DDD approach and have embeddedId.

I have received next exception:

org.springframework.dao.InvalidDataAccessApiUsageException: Argument [x.x.x.AttributeId@ae4aa43] of type [x.x.x.AttributeId] did not match parameter type [x.x.x.AttributeValueId (n/a)]
    at app//org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:371)
    at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235)
    at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:550)
    at app//org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at app//org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at app//org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
    at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at app//org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:163)
    at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at app//org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at app//org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:218)
    at app/jdk.proxy3/jdk.proxy3.$Proxy201.**existsById**(Unknown Source)
    at app//x.x.x.AttributeUnitTests.testExistByIdAttribute(AttributeUnitTests.java:100)

when I execute next unit test:

@Test

public void testExistByIdAttribute() {

    var attribute = new Attribute(new AttributeId("ATTR-1"), "title", "description");

    assertNotNull(attribute);

    assertNotNull(attribute.getId());

    assertEquals("title", attribute.getTitle());

    assertEquals("description", attribute.getDescription());
 


    var savedAttribute = getAttributeRepository().save(attribute);


    assertTrue(getAttributeRepository().existsById(attribute.getId()));

}

Details:

Here is definition of EntityObject and AggregateRoot

@MappedSuperclass

@NoArgsConstructor(access = AccessLevel.PROTECTED)

@Getter

@Setter(AccessLevel.PRIVATE)

@ToString

public abstract class EntityObject<ID extends Serializable> implements Identifiable<ID> {


    @EmbeddedId


    private ID id;


    

    public EntityObject(ID id) {
        
        this.id = id;

    }


}

@MappedSuperclass

public abstract class AggregateRoot<ID extends Serializable> extends EntityObject<ID> {


    @Getter

    @Setter(AccessLevel.PROTECTED)

    private long version = 0;



    protected AggregateRoot() {

    }

 

   public AggregateRoot(ID id) {
        super(id);
    }



 
}
Here is classes of emebedded ids
@Getter

@FieldDefaults(makeFinal=false, level=AccessLevel.PRIVATE)

@NoArgsConstructor(force = true, access = AccessLevel.PROTECTED)

@AllArgsConstructor

@Embeddable

@EqualsAndHashCode

public class AttributeId  implements Serializable {

    @Column(name="attribute_id")

    String attributeId;


}

@Getter

@FieldDefaults(makeFinal=false, level=AccessLevel.PRIVATE)

@NoArgsConstructor(force = true, access = AccessLevel.PROTECTED)

@AllArgsConstructor

@Embeddable

@EqualsAndHashCode

public class AttributeValueId  implements Serializable {

    @Column(name="id")

    String attributeValueId;


}
Here is my entities:
@NoArgsConstructor(access = AccessLevel.PROTECTED)

@Getter

@Setter(AccessLevel.PRIVATE)

@Entity

@Table(
name = "attributes")

@EqualsAndHashCode(callSuper = true)

public class Attribute extends AggregateRoot<AttributeId> {

    @NonNull

    @Column(name = "title", nullable = false)

    private String title;


    private String description;





    @Builder
    public Attribute(

            @NonNull AttributeId attributeId,

            @NonNull String title,

            String description

    ) {

        super(attributeId);
 
        this.title = title;

        this.description = description;


    }
}


@NoArgsConstructor(access = AccessLevel.PROTECTED)

@Getter

@Setter(AccessLevel.PRIVATE)

@Entity

@Table(
name = "attribute_values")

@EqualsAndHashCode(callSuper = true)

public class AttributeValue extends AggregateRoot<AttributeValueId> {

    @ManyToOne

    @JoinColumn(name = "attribute_id", nullable = false)
    
@EqualsAndHashCode.Exclude
    
private Attribute attribute;



    @Embedded

    @AttributeOverride(name = "attributeId",

        column = @Column(name="attribute_id", nullable = false, insertable = false, updatable = false)
    
)
    
private AttributeId attributeId;

    @NonNull

    @Column(name = "title", nullable = false)

    private String value;





    @Builder

    public AttributeValue(

            @NonNull AttributeValueId attributeValueId,

            @NonNull Attribute attribute,

            @NonNull String value

    ) {

        super(attributeValueId);
 
        this.attribute = attribute;

        this.value = value;


    }
}
Eventualy here is my repositories:
@Repository

public interface AttributeRepository extends CrudRepository<Attribute, AttributeId> {

    List<Attribute> findAll();
    Page<Attribute> findAll(Pageable pageable);
}

@Repository

public interface AttributeValueRepository extends CrudRepository<AttributeValue, AttributeValueId> {

    List<AttributeValue> findAll();
    Page<AttributeValue> findAll(Pageable pageable);
}
My config:
spring:

  h2:

    console:

      enabled: true


  datasource:

    url: jdbc:h2:mem:attributes

    username: developer

    password: developer

    driverClassName: org.h2.Driver

  jpa:
    database-platform: org.hibernate.dialect.H2Dialect

    show-sql: true

    properties:

      hibernate:
 
       dialect: org.hibernate.dialect.H2Dialect

I suppose what entityManager have incorrect metamodel of Jpa entities. How to fix this using configs or it's bug?

Comment From: wilkinsona

Thanks for the report. I suspect that this is a Spring Data JPA or Hibernate problem but it's hard to tell by piecing together separate code snippets. Can you please provide a complete yet minimal sample that reproduces the problem? I see that you've used Lombok in the snippets above. Unless the problem does not occur without Lombok, please remove it from the sample so that it has as few dependencies as possible.

Comment From: stepanovD

Sure! I prepared sample like you ask. sample.zip

Comment From: stepanovD

Hey, @wilkinsona! Do you have any ideas how to fix this problem?

Comment From: wilkinsona

I haven't had time to look at the sample until now. It includes a lot of moving parts that you hadn't mentioned before, including QueryDSL, lots of web-related config and classes, Actuator, Hypersistence, and so on. Are they all required to reproduce the problem? If not, as with Lombok, they should be removed so that the sample has as few dependencies as possible. Ideally, we want the absolute bare minimum that's required to reproduce the problem.

Comment From: stepanovD

Ok, I removed all secondary dependencies. sample.zip

Comment From: wilkinsona

Thanks. Unfortunately, the sample is still far from minimal.

There's still a significant amount of code that doesn't seem to be relevant to the problem. As I said above, we really want to see the absolute bare minimum that's required to reproduce the problem. We just don't have time to read and understand lots of code when it isn't part of the problem. Often, producing a minimal sample will reveal the cause of the problem and you'll be able to solve it yourself without even having to open an issue and wait for us to find the time to take a look.

You can also try upgrading to the latest version of the dependencies that are most likely to be relevant to the problem. As I said above, this looks like a Hibernate or Spring Data JPA problem. Spring Boot 3.0.2 uses Hibernate 6.1.6.Final and 6.1.7.Final is the latest version. Before closing this issue as we can't justify spending any more time on it, I gave this a try by setting the hibernate.version property:

ext {
    set("hibernate.version", "6.1.7.Final")
}

testExistByIdAttribute now passes so this was a Hibernate bug as suspected. Spring Boot 3.0.3 uses Hibernate 6.1.7.Final by default so you may want to upgrade to 3.0.3 rather than overriding Hibernate's version.

Comment From: stepanovD

Thanks, It start to work when I up version of Spring Boot to 3.0.3