diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/TypeUtils.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/TypeUtils.java index 8be4f51d2f86..654763143291 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/TypeUtils.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/TypeUtils.java @@ -385,7 +385,12 @@ private static void updateEmbeddableAccessTypeForMember(Context context, AccessT private static void updateEmbeddableAccessType(Context context, AccessType defaultAccessType, TypeElement embedded) { final String embeddedClassName = embedded.getQualifiedName().toString(); - final AccessTypeInformation accessTypeInfo = context.getAccessTypeInfo(embeddedClassName); + final AccessType forcedAccessType = determineAnnotationSpecifiedAccessType( embedded ); + final AccessTypeInformation accessTypeInfo = + forcedAccessType != null + ? new AccessTypeInformation( embeddedClassName, null, forcedAccessType ) + : context.getAccessTypeInfo( embeddedClassName ); + if ( accessTypeInfo == null ) { final AccessTypeInformation newAccessTypeInfo = new AccessTypeInformation( embeddedClassName, null, defaultAccessType ); diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/embeddable/ForcedAccessTypeTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/embeddable/ForcedAccessTypeTest.java new file mode 100644 index 000000000000..c6c65aced017 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/processor/test/embeddable/ForcedAccessTypeTest.java @@ -0,0 +1,125 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.processor.test.embeddable; + +import jakarta.persistence.Access; +import jakarta.persistence.AccessType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.Transient; +import org.hibernate.processor.test.util.CompilationTest; +import org.hibernate.processor.test.util.TestUtil; +import org.hibernate.processor.test.util.WithClasses; +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import static org.hibernate.processor.test.util.TestUtil.assertAttributeTypeInMetaModelFor; +import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor; + +@CompilationTest +public class ForcedAccessTypeTest { + + @Test + @WithClasses({MyEntity.class, DateAndTime.class, MySuperclass.class}) + public void testCorrectAccessTypeUsedForEmbeddable() { + System.out.println( TestUtil.getMetaModelSourceAsString( MyEntity.class ) ); + assertMetamodelClassGeneratedFor( MyEntity.class ); + + assertMetamodelClassGeneratedFor( MySuperclass.class ); + assertAttributeTypeInMetaModelFor( + MySuperclass.class, + "name", + String.class, + "Missing attribute name of type java.lang.String" + ); + + assertMetamodelClassGeneratedFor( DateAndTime.class ); + assertAttributeTypeInMetaModelFor( + DateAndTime.class, + "localDateTime", + LocalDateTime.class, + "Missing attribute localDateTime of type java.time.LocalDateTime" + ); + assertAttributeTypeInMetaModelFor( + DateAndTime.class, + "offset", + ZoneOffset.class, + "Missing attribute offset of type java.time.ZoneOffset" + ); + } + + @Entity + @Access(AccessType.FIELD) + static class MyEntity extends MySuperclass { + @Id + Long id; + + @Embedded + DateAndTime dateAndTime; + } + + @MappedSuperclass + @Access(AccessType.PROPERTY) + static class MySuperclass { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Embeddable + @Access(AccessType.PROPERTY) + static class DateAndTime { + + @Transient + private OffsetDateTime dateTime; + + public DateAndTime() { + this.dateTime = OffsetDateTime.now(); + } + + public DateAndTime(final OffsetDateTime dateTime) { + this.dateTime = dateTime; + } + + public DateAndTime(final Instant localDateTime, final ZoneOffset offset) { + this.dateTime = localDateTime.atOffset( offset ); + } + + public LocalDateTime getLocalDateTime() { + return dateTime.toLocalDateTime(); + } + + public void setLocalDateTime(final LocalDateTime localDateTime) { + this.dateTime = localDateTime.atOffset( this.dateTime.getOffset() ); + } + + public ZoneOffset getOffset() { + return dateTime.getOffset(); + } + + public void setOffset(final ZoneOffset offset) { + this.dateTime = dateTime.toLocalDateTime().atOffset( offset ); + } + + @Transient + public OffsetDateTime dateTime() { + return dateTime; + } + } + +}