diff --git a/api/src/main/java/jakarta/persistence/ColumnResult.java b/api/src/main/java/jakarta/persistence/ColumnResult.java index a1d2e95e..17983d3a 100644 --- a/api/src/main/java/jakarta/persistence/ColumnResult.java +++ b/api/src/main/java/jakarta/persistence/ColumnResult.java @@ -16,7 +16,6 @@ package jakarta.persistence; -import java.lang.annotation.Annotation; import java.lang.annotation.Target; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -81,15 +80,4 @@ * @since 2.1 */ Class type() default void.class; - - record Map(String name, Class type) - implements ColumnResult, SqlResultSetMapping.MappingElement { - Map(String name) { - this(name, void.class); - } - @Override - public Class annotationType() { - return ColumnResult.class; - } - } } diff --git a/api/src/main/java/jakarta/persistence/ConstructorResult.java b/api/src/main/java/jakarta/persistence/ConstructorResult.java index a2943148..7620d08d 100644 --- a/api/src/main/java/jakarta/persistence/ConstructorResult.java +++ b/api/src/main/java/jakarta/persistence/ConstructorResult.java @@ -16,7 +16,6 @@ package jakarta.persistence; -import java.lang.annotation.Annotation; import java.lang.annotation.Target; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -88,12 +87,4 @@ * {@linkplain #targetClass target class}, in order. */ ColumnResult[] columns(); - - record Map(Class targetClass, ColumnResult... columns) - implements ConstructorResult, SqlResultSetMapping.MappingElement { - @Override - public Class annotationType() { - return ConstructorResult.class; - } - } } diff --git a/api/src/main/java/jakarta/persistence/EntityManager.java b/api/src/main/java/jakarta/persistence/EntityManager.java index 80b41a19..ea5ac401 100644 --- a/api/src/main/java/jakarta/persistence/EntityManager.java +++ b/api/src/main/java/jakarta/persistence/EntityManager.java @@ -27,6 +27,7 @@ import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.sql.ResultSetMapping; /** * Interface used to interact with the persistence context. @@ -1138,6 +1139,15 @@ void refresh(Object entity, */ Query createNativeQuery(String sqlString, String resultSetMapping); + /** + * Create an instance of {@link TypedQuery} for executing + * a native SQL query. + * @param sqlString a native SQL query string + * @param resultSetMapping the result set mapping + * @return the new query instance + */ + TypedQuery createNativeQuery(String sqlString, ResultSetMapping resultSetMapping); + /** * Create an instance of {@link StoredProcedureQuery} for executing * a stored procedure in the database. diff --git a/api/src/main/java/jakarta/persistence/EntityResult.java b/api/src/main/java/jakarta/persistence/EntityResult.java index a0c1387f..442fdb2f 100644 --- a/api/src/main/java/jakarta/persistence/EntityResult.java +++ b/api/src/main/java/jakarta/persistence/EntityResult.java @@ -17,7 +17,6 @@ package jakarta.persistence; -import java.lang.annotation.Annotation; import java.lang.annotation.Target; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -91,18 +90,4 @@ * the entity instance. */ String discriminatorColumn() default ""; - - record Map(Class entityClass, String discriminatorColumn, FieldResult[] fields, LockModeType lockMode) - implements EntityResult, SqlResultSetMapping.MappingElement { - Map(Class entityClass, FieldResult... fields) { - this(entityClass, "", fields, LockModeType.NONE); - } - Map(Class entityClass, String discriminatorColumn, FieldResult... fields) { - this(entityClass, discriminatorColumn, fields, LockModeType.NONE); - } - @Override - public Class annotationType() { - return EntityResult.class; - } - } } diff --git a/api/src/main/java/jakarta/persistence/FieldResult.java b/api/src/main/java/jakarta/persistence/FieldResult.java index e2da1822..461a8ed0 100644 --- a/api/src/main/java/jakarta/persistence/FieldResult.java +++ b/api/src/main/java/jakarta/persistence/FieldResult.java @@ -17,7 +17,6 @@ package jakarta.persistence; -import java.lang.annotation.Annotation; import java.lang.annotation.Target; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -73,12 +72,4 @@ * the column alias, if applicable. */ String column(); - - record Map(String name, String column) - implements FieldResult { - @Override - public Class annotationType() { - return FieldResult.class; - } - } } diff --git a/api/src/main/java/jakarta/persistence/SqlResultSetMapping.java b/api/src/main/java/jakarta/persistence/SqlResultSetMapping.java index 1fd547dc..3f0760e3 100644 --- a/api/src/main/java/jakarta/persistence/SqlResultSetMapping.java +++ b/api/src/main/java/jakarta/persistence/SqlResultSetMapping.java @@ -17,12 +17,9 @@ package jakarta.persistence; -import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; import java.lang.annotation.Target; import java.lang.annotation.Retention; -import java.lang.reflect.Array; -import java.util.Arrays; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -94,31 +91,6 @@ * Specifies the result set mapping to scalar values. */ ColumnResult[] columns() default {}; - - interface MappingElement {} - - record Map(String name, EntityResult[] entities, ConstructorResult[] classes, ColumnResult[] columns) - implements SqlResultSetMapping { - @SuppressWarnings("unchecked") - private static R[] newArrayInstance(Class type, int length) { - return (R[]) Array.newInstance(type, length); - } - static R[] extract(Class type, MappingElement[] mappingElements) { - return Arrays.stream(mappingElements) - .filter(type::isInstance) - .toArray(length -> newArrayInstance(type, length)); - } - Map(String name, MappingElement... mappings) { - this(name, - extract(EntityResult.class, mappings), - extract(ConstructorResult.class, mappings), - extract(ColumnResult.class, mappings)); - } - @Override - public Class annotationType() { - return SqlResultSetMapping.class; - } - } } diff --git a/api/src/main/java/jakarta/persistence/sql/ColumnMapping.java b/api/src/main/java/jakarta/persistence/sql/ColumnMapping.java new file mode 100644 index 00000000..9fd04b3b --- /dev/null +++ b/api/src/main/java/jakarta/persistence/sql/ColumnMapping.java @@ -0,0 +1,22 @@ +package jakarta.persistence.sql; + +import jakarta.persistence.ColumnResult; + +import java.lang.annotation.Annotation; + +public record ColumnMapping(String name, Class type) + implements ColumnResult, MappingElement { + + public static ColumnMapping map(String name) { + return new ColumnMapping<>(name, Object.class); + } + + public static ColumnMapping map(String name, Class type) { + return new ColumnMapping<>(name, type); + } + + @Override + public Class annotationType() { + return ColumnResult.class; + } +} diff --git a/api/src/main/java/jakarta/persistence/sql/ConstructorMapping.java b/api/src/main/java/jakarta/persistence/sql/ConstructorMapping.java new file mode 100644 index 00000000..708b75d3 --- /dev/null +++ b/api/src/main/java/jakarta/persistence/sql/ConstructorMapping.java @@ -0,0 +1,19 @@ +package jakarta.persistence.sql; + +import jakarta.persistence.ColumnResult; +import jakarta.persistence.ConstructorResult; + +import java.lang.annotation.Annotation; + +public record ConstructorMapping(Class targetClass, ColumnResult[] columns) + implements ConstructorResult, MappingElement { + + public static ConstructorMapping map(Class targetClass, ColumnResult... columns) { + return new ConstructorMapping<>(targetClass, columns); + } + + @Override + public Class annotationType() { + return ConstructorResult.class; + } +} diff --git a/api/src/main/java/jakarta/persistence/sql/EntityMapping.java b/api/src/main/java/jakarta/persistence/sql/EntityMapping.java new file mode 100644 index 00000000..b7577cdc --- /dev/null +++ b/api/src/main/java/jakarta/persistence/sql/EntityMapping.java @@ -0,0 +1,31 @@ +package jakarta.persistence.sql; + +import jakarta.persistence.EntityResult; +import jakarta.persistence.FieldResult; +import jakarta.persistence.LockModeType; + +import java.lang.annotation.Annotation; + +public record EntityMapping(Class entityClass, LockModeType lockMode, String discriminatorColumn, FieldResult[] fields) + implements EntityResult, MappingElement { + + @SafeVarargs + public static EntityMapping map(Class entityClass, FieldMapping... fields) { + return new EntityMapping<>(entityClass, LockModeType.NONE, "", fields); + } + + @SafeVarargs + public static EntityMapping map(Class entityClass, String discriminatorColumn, FieldMapping... fields) { + return new EntityMapping<>(entityClass, LockModeType.NONE, discriminatorColumn, fields); + } + + @SafeVarargs + public static EntityMapping map(Class entityClass, LockModeType lockMode, String discriminatorColumn, FieldMapping... fields) { + return new EntityMapping<>(entityClass, lockMode, discriminatorColumn, fields); + } + + @Override + public Class annotationType() { + return EntityResult.class; + } +} \ No newline at end of file diff --git a/api/src/main/java/jakarta/persistence/sql/FieldMapping.java b/api/src/main/java/jakarta/persistence/sql/FieldMapping.java new file mode 100644 index 00000000..5a6baf95 --- /dev/null +++ b/api/src/main/java/jakarta/persistence/sql/FieldMapping.java @@ -0,0 +1,20 @@ +package jakarta.persistence.sql; + +import jakarta.persistence.FieldResult; +import jakarta.persistence.metamodel.SingularAttribute; + +import java.lang.annotation.Annotation; + +public record FieldMapping(String name, String column) + implements FieldResult { + + public static FieldMapping map(SingularAttribute attribute, String column) { + return new FieldMapping<>(attribute.getName(), column); + } + + @Override + public Class annotationType() { + return FieldResult.class; + } +} + diff --git a/api/src/main/java/jakarta/persistence/sql/MappingElement.java b/api/src/main/java/jakarta/persistence/sql/MappingElement.java new file mode 100644 index 00000000..67daf7fe --- /dev/null +++ b/api/src/main/java/jakarta/persistence/sql/MappingElement.java @@ -0,0 +1,17 @@ +package jakarta.persistence.sql; + +import java.lang.reflect.Array; +import java.util.Arrays; + +public interface MappingElement { + + @SuppressWarnings("unchecked") + private static R[] newArrayInstance(Class type, int length) { + return (R[]) Array.newInstance(type, length); + } + static R[] extract(Class type, MappingElement[] mappingElements) { + return Arrays.stream(mappingElements) + .filter(type::isInstance) + .toArray(length -> newArrayInstance(type, length)); + } +} diff --git a/api/src/main/java/jakarta/persistence/sql/ResultSetMapping.java b/api/src/main/java/jakarta/persistence/sql/ResultSetMapping.java new file mode 100644 index 00000000..667f403f --- /dev/null +++ b/api/src/main/java/jakarta/persistence/sql/ResultSetMapping.java @@ -0,0 +1,48 @@ +package jakarta.persistence.sql; + +import jakarta.persistence.ColumnResult; +import jakarta.persistence.ConstructorResult; +import jakarta.persistence.EntityResult; +import jakarta.persistence.SqlResultSetMapping; + +import java.lang.annotation.Annotation; + +import static jakarta.persistence.sql.MappingElement.extract; + +public record ResultSetMapping(String name, EntityResult[] entities, ConstructorResult[] classes, ColumnResult[] columns) + implements SqlResultSetMapping { + + public static ResultSetMapping create(MappingElement... mappings) { + return new ResultSetMapping<>("", + extract(EntityResult.class, mappings), + extract(ConstructorResult.class, mappings), + extract(ColumnResult.class, mappings)); + } + + public static ResultSetMapping create(EntityMapping entityMapping) { + return new ResultSetMapping<>("", + new EntityResult[]{entityMapping}, + new ConstructorResult[0], + new ColumnResult[0]); + } + + public static ResultSetMapping create(ConstructorMapping constructorMapping) { + return new ResultSetMapping<>("", + new EntityResult[0], + new ConstructorResult[]{constructorMapping}, + new ColumnResult[0]); + } + + public static ResultSetMapping create(ColumnMapping columnResult) { + return new ResultSetMapping<>("", + new EntityResult[0], + new ConstructorResult[0], + new ColumnResult[]{columnResult}); + } + + @Override + public Class annotationType() { + return SqlResultSetMapping.class; + } +} + diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 4243c1fd..7add16f2 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -19,6 +19,7 @@ exports jakarta.persistence.criteria; exports jakarta.persistence.metamodel; exports jakarta.persistence.spi; + exports jakarta.persistence.sql; uses jakarta.persistence.spi.PersistenceProvider; }