From d94a2a7ea95af43f09c1a8d71eb15133af9bf742 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 26 Sep 2024 11:47:37 -0500 Subject: [PATCH] HHH-18545 - Document "characteristics" of settings (cherry picked from commit 4f9035e9f822474efe050b7a57737adecf3bd00a) --- documentation/documentation.gradle | 2 +- .../java/org/hibernate/cfg/Compatibility.java | 23 ++++++ .../java/org/hibernate/cfg/QuerySettings.java | 32 +++++---- .../hibernate/cfg/TransactionSettings.java | 70 +++++++++++-------- .../main/java/org/hibernate/cfg/Unsafe.java | 22 ++++++ .../orm/properties/AsciiDocWriter.java | 6 ++ .../orm/properties/SettingDescriptor.java | 20 +++++- .../orm/properties/SettingWorkingDetails.java | 22 +++++- .../org/hibernate/orm/properties/Utils.java | 37 ++++++++++ .../properties/jdk11/SettingsCollector.java | 28 ++------ .../properties/jdk17/SettingsCollector.java | 29 ++------ 11 files changed, 198 insertions(+), 93 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/Compatibility.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java diff --git a/documentation/documentation.gradle b/documentation/documentation.gradle index 02b5f88298..ad0ee5f00b 100644 --- a/documentation/documentation.gradle +++ b/documentation/documentation.gradle @@ -573,7 +573,7 @@ settingsDocumentation { } transaction { explicitPosition = 6 - summary = "Proxool Connection Pool Settings" + summary = "Transaction Environment Settings" description = "Settings which control how Hibernate interacts with and manages transactions" settingsClassName "org.hibernate.cfg.TransactionSettings" } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Compatibility.java b/hibernate-core/src/main/java/org/hibernate/cfg/Compatibility.java new file mode 100644 index 0000000000..efddfc6293 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Compatibility.java @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.cfg; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; + +/** + * Denotes that a setting is intended to allow applications to upgrade + * versions of Hibernate and maintain backwards compatibility with the + * older version in some specific behavior. Such settings are almost always + * considered temporary and are usually also {@linkplain Deprecated deprecated}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Compatibility { +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/QuerySettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/QuerySettings.java index 08d9aa70d8..cefbf61849 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/QuerySettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/QuerySettings.java @@ -23,6 +23,8 @@ public interface QuerySettings { * databases. By default, integer division in HQL can produce a non-integer * on Oracle, MySQL, or MariaDB. * + * @settingDefault {@code false} + * * @since 6.5 */ String PORTABLE_INTEGER_DIVISION = "hibernate.query.hql.portable_integer_division"; @@ -53,10 +55,10 @@ public interface QuerySettings { /** * When enabled, specifies that named queries be checked during startup. *

- * By default, named queries are checked at startup. - *

* Mainly intended for use in test environments. * + * @settingDefault {@code true} (enabled) - named queries are checked at startup. + * * @see org.hibernate.boot.SessionFactoryBuilder#applyNamedQueryCheckingOnStartup(boolean) */ String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check"; @@ -85,8 +87,8 @@ public interface QuerySettings { * {@link jakarta.persistence.Query#setParameter(jakarta.persistence.Parameter,Object)} * to specify its argument are passed to JDBC using a bind parameter. * - *

- * The default mode is {@link org.hibernate.query.criteria.ValueHandlingMode#BIND}. + * + * @settingDefault {@link org.hibernate.query.criteria.ValueHandlingMode#BIND}. * * @since 6.0.0 * @@ -101,8 +103,8 @@ public interface QuerySettings { * Specifies the default {@linkplain NullPrecedence precedence of null values} in the * HQL {@code ORDER BY} clause, either {@code none}, {@code first}, or {@code last}, * or an instance of {@link NullPrecedence}. - *

- * The default is {@code none}. + * + * @settingDefault {@code none}. * * @see NullPrecedence * @see org.hibernate.boot.SessionFactoryBuilder#applyDefaultNullPrecedence(NullPrecedence) @@ -135,10 +137,10 @@ public interface QuerySettings { String CRITERIA_COPY_TREE = "hibernate.criteria.copy_tree"; /** - * When set to true, indicates that ordinal parameters (represented by the '?' placeholder) in native queries will be ignored. - *

- * By default, this is set to false, i.e. native queries will be checked for ordinal placeholders. - *

+ * When enabled, ordinal parameters (represented by the {@code ?} placeholder) in + * native queries will be ignored. + * + * @settingDefault {@code false} (disabled) - native queries are checked for ordinal placeholders. * * @see SessionFactoryOptions#getNativeJdbcParametersIgnored() */ @@ -152,9 +154,9 @@ public interface QuerySettings { *

* When enabled, this setting specifies that an exception should be thrown for any * query which would result in the limit being applied in-memory. - *

- * By default, the exception is disabled, and the possibility of terrible - * performance is left as a problem for the client to avoid. + * + * @settingDefault {@code false} (disabled) - no exception is thrown and the + * possibility of terrible performance is left as a problem for the client to avoid. * * @since 5.2.13 */ @@ -172,8 +174,8 @@ public interface QuerySettings { *

  • {@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#EXCEPTION "exception"} * specifies that a {@link org.hibernate.HibernateException} should be thrown. * - *

    - * By default, a warning is logged. + * + * @settingDefault {@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#WARNING "warning"} * * @since 5.2.17 * diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java index 94d284499b..6783f87eb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/TransactionSettings.java @@ -6,6 +6,7 @@ */ package org.hibernate.cfg; + import jakarta.persistence.spi.PersistenceUnitInfo; /** @@ -129,36 +130,6 @@ public interface TransactionSettings { */ String ALLOW_JTA_TRANSACTION_ACCESS = "hibernate.jta.allowTransactionAccess"; - /** - * Allows a detached proxy or lazy collection to be fetched even when not - * associated with an open persistence context, by creating a temporary - * persistence context when the proxy or collection is accessed. This - * behavior is not recommended, since it can easily break transaction - * isolation or lead to data aliasing; it is therefore disabled by default. - * - * @settingDefault {@code false} (disabled) - * - * @see org.hibernate.boot.SessionFactoryBuilder#applyLazyInitializationOutsideTransaction(boolean) - */ - String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans"; - - /** - * When enabled, allows update operations outside a transaction. - *

    - * Since version 5.2 Hibernate conforms with the JPA specification and disallows - * flushing any update outside a transaction. - *

    - * Values are {@code true}, which allows flushing outside a transaction, and - * {@code false}, which does not. - *

    - * The default behavior is to disallow update operations outside a transaction. - * - * @see org.hibernate.boot.SessionFactoryBuilder#allowOutOfTransactionUpdateOperations(boolean) - * - * @since 5.2 - */ - String ALLOW_UPDATE_OUTSIDE_TRANSACTION = "hibernate.allow_update_outside_transaction"; - /** * When enabled, specifies that the {@link org.hibernate.Session} should be * closed automatically at the end of each transaction. @@ -178,4 +149,43 @@ public interface TransactionSettings { * @see org.hibernate.boot.SessionFactoryBuilder#applyAutoFlushing(boolean) */ String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion"; + + /** + * Allows a detached proxy or lazy collection to be fetched even when not + * associated with an open persistence context, by creating a temporary + * persistence context when the proxy or collection is accessed. This + * behavior is not recommended, since it can easily break transaction + * isolation or lead to data aliasing; it is therefore disabled by default. + * + * @settingDefault {@code false} (disabled) + * + * @apiNote Generally speaking, all access to transactional data should be done in a transaction. + * + * @see org.hibernate.boot.SessionFactoryBuilder#applyLazyInitializationOutsideTransaction(boolean) + */ + @Unsafe + String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans"; + + /** + * When enabled, allows update operations outside a transaction. + *

    + * Since version 5.2 Hibernate conforms with the JPA specification and disallows + * flushing any update outside a transaction. + *

    + * Values are {@code true}, which allows flushing outside a transaction, and + * {@code false}, which does not. + *

    + * The default behavior is to disallow update operations outside a transaction. + * + * @settingDefault {@code false} (disabled) + * + * @apiNote Generally speaking, all access to transactional data should be done in a transaction. + * Combining this with second-level caching, e.g., will cause problems. + * + * @see org.hibernate.boot.SessionFactoryBuilder#allowOutOfTransactionUpdateOperations(boolean) + * + * @since 5.2 + */ + @Unsafe + String ALLOW_UPDATE_OUTSIDE_TRANSACTION = "hibernate.allow_update_outside_transaction"; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java b/hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java new file mode 100644 index 0000000000..6219e6b9c7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Unsafe.java @@ -0,0 +1,22 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.cfg; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; + +/** + * Denotes that a setting is considered unsafe. Generally these are settings + * added for temporary use during porting of applications. Unsafe settings + * are largely considered unsupported. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Unsafe { +} diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/properties/AsciiDocWriter.java b/local-build-plugins/src/main/java/org/hibernate/orm/properties/AsciiDocWriter.java index ebf99d1182..6f628226b4 100644 --- a/local-build-plugins/src/main/java/org/hibernate/orm/properties/AsciiDocWriter.java +++ b/local-build-plugins/src/main/java/org/hibernate/orm/properties/AsciiDocWriter.java @@ -109,6 +109,12 @@ private static void writeMetadata(SettingDescriptor settingDescriptor, FileWrite if ( lifecycleDetails.isDeprecated() ) { writer.write( "WARNING: *_This setting is considered deprecated_*\n\n" ); } + if ( settingDescriptor.isUnsafe() ) { + writer.write( "WARNING: *_This setting is considered unsafe_*\n\n" ); + } + if ( settingDescriptor.isCompatibility() ) { + writer.write( "INFO: *_This setting manages a certain backwards compatibility_*\n\n" ); + } if ( lifecycleDetails.getSince() != null ) { writer.write( "*_Since:_* _" + lifecycleDetails.getSince() + "_\n\n" ); diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingDescriptor.java b/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingDescriptor.java index 754512bc28..03ed313088 100644 --- a/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingDescriptor.java +++ b/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingDescriptor.java @@ -18,6 +18,8 @@ public class SettingDescriptor { private final String defaultValue; private final String apiNote; private final LifecycleDetails lifecycleDetails; + private final boolean unsafe; + private final boolean compatibility; public SettingDescriptor( String name, @@ -27,6 +29,8 @@ public SettingDescriptor( String comment, String defaultValue, String apiNote, + boolean unsafe, + boolean compatibility, LifecycleDetails lifecycleDetails) { this.name = name; this.settingsClassName = settingsClassName; @@ -35,6 +39,8 @@ public SettingDescriptor( this.publishedJavadocLink = publishedJavadocLink; this.defaultValue = defaultValue; this.apiNote = apiNote; + this.unsafe = unsafe; + this.compatibility = compatibility; this.lifecycleDetails = lifecycleDetails; } @@ -48,7 +54,9 @@ public SettingDescriptor( String apiNote, String since, boolean deprecated, - boolean incubating) { + boolean incubating, + boolean unsafe, + boolean compatibility) { this( name, settingsClassName, @@ -56,6 +64,8 @@ public SettingDescriptor( publishedJavadocLink, comment, defaultValue, apiNote, + unsafe, + compatibility, new LifecycleDetails( since, deprecated, incubating ) ); } @@ -100,6 +110,14 @@ public String getSettingFieldName() { return settingFieldName; } + public boolean isUnsafe() { + return unsafe; + } + + public boolean isCompatibility() { + return compatibility; + } + public LifecycleDetails getLifecycleDetails() { return lifecycleDetails; } diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingWorkingDetails.java b/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingWorkingDetails.java index d6dbd0b277..6fad3071c6 100644 --- a/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingWorkingDetails.java +++ b/local-build-plugins/src/main/java/org/hibernate/orm/properties/SettingWorkingDetails.java @@ -23,6 +23,8 @@ public class SettingWorkingDetails { private String since; private boolean deprecated; private boolean incubating; + private boolean unsafe; + private boolean compatibility; private List relatedSettingNames; public SettingWorkingDetails( @@ -92,6 +94,22 @@ public void setIncubating(boolean incubating) { this.incubating = incubating; } + public boolean isUnsafe() { + return unsafe; + } + + public void setUnsafe(boolean unsafe) { + this.unsafe = unsafe; + } + + public boolean isCompatibility() { + return compatibility; + } + + public void setCompatibility(boolean compatibility) { + this.compatibility = compatibility; + } + public List getRelatedSettingNames() { return relatedSettingNames; } @@ -134,7 +152,9 @@ public SettingDescriptor buildDescriptor(String asciidoc) { apiNote, since, deprecated, - incubating + incubating, + unsafe, + compatibility ); } } diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/properties/Utils.java b/local-build-plugins/src/main/java/org/hibernate/orm/properties/Utils.java index 61a7994b7c..b6e4ce8fcd 100644 --- a/local-build-plugins/src/main/java/org/hibernate/orm/properties/Utils.java +++ b/local-build-plugins/src/main/java/org/hibernate/orm/properties/Utils.java @@ -14,6 +14,8 @@ import java.util.TreeMap; import java.util.TreeSet; +import org.jsoup.nodes.Element; + /** * @author Steve Ebersole */ @@ -39,4 +41,39 @@ public static Map> createResult } ); return map; } + + public static boolean containsHref(Element fieldJavadocElement, String target) { + final String cssQuery = "a[href$=" + target + "]"; + final Element incubatingMarkerElement = fieldJavadocElement.selectFirst( cssQuery ); + return incubatingMarkerElement != null; + + } + + public static boolean interpretIncubation(Element fieldJavadocElement) { + return containsHref( fieldJavadocElement, "Incubating.html" ); + } + + public static boolean interpretUnsafe(Element fieldJavadocElement) { + return containsHref( fieldJavadocElement, "Unsafe.html" ); + } + + public static boolean interpretCompatibility(Element fieldJavadocElement) { + return containsHref( fieldJavadocElement, "Compatibility.html" ); + } + + public static boolean interpretDeprecation(Element fieldJavadocElement) { + // A setting is considered deprecated with either `@Deprecated` + final Element deprecationDiv = fieldJavadocElement.selectFirst( ".deprecationBlock" ); + // presence of this

    indicates the member is deprecated + if ( deprecationDiv != null ) { + return true; + } + + // or `@Remove` + if ( containsHref( fieldJavadocElement, "Remove.html" ) ) { + return true; + } + + return false; + } } diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk11/SettingsCollector.java b/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk11/SettingsCollector.java index 0115a2c06a..9f1e5dc58a 100644 --- a/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk11/SettingsCollector.java +++ b/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk11/SettingsCollector.java @@ -23,6 +23,10 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import static org.hibernate.orm.properties.Utils.interpretCompatibility; +import static org.hibernate.orm.properties.Utils.interpretDeprecation; +import static org.hibernate.orm.properties.Utils.interpretIncubation; +import static org.hibernate.orm.properties.Utils.interpretUnsafe; import static org.hibernate.orm.properties.Utils.packagePrefix; import static org.hibernate.orm.properties.Utils.withoutPackagePrefix; @@ -195,6 +199,8 @@ private static void applyMetadata( settingDetails.setIncubating( interpretIncubation( fieldJavadocElement ) ); settingDetails.setDeprecated( interpretDeprecation( fieldJavadocElement ) ); + settingDetails.setUnsafe( interpretUnsafe( fieldJavadocElement ) ); + settingDetails.setCompatibility( interpretCompatibility( fieldJavadocElement ) ); } private static SettingsDocSection findMatchingDocSection( @@ -245,28 +251,6 @@ private static void processNotes( } } - private static boolean interpretIncubation(Element fieldJavadocElement) { - final Element incubatingMarkerElement = fieldJavadocElement.selectFirst( "[href*=.Incubating.html]" ); - return incubatingMarkerElement != null; - } - - private static boolean interpretDeprecation(Element fieldJavadocElement) { - // A setting is considered deprecated with either `@Deprecated` - final Element deprecationDiv = fieldJavadocElement.selectFirst( ".deprecationBlock" ); - // presence of this
    indicates the member is deprecated - if ( deprecationDiv != null ) { - return true; - } - - // or `@Remove` - final Element removeMarkerElement = fieldJavadocElement.selectFirst( "[href*=.Remove.html]" ); - if ( removeMarkerElement != null ) { - return true; - } - - return false; - } - private static Elements cleanupFieldJavadocElement( Element fieldJavadocElement, String className, diff --git a/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk17/SettingsCollector.java b/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk17/SettingsCollector.java index e5bacf1cd1..b9aea25d99 100644 --- a/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk17/SettingsCollector.java +++ b/local-build-plugins/src/main/java/org/hibernate/orm/properties/jdk17/SettingsCollector.java @@ -24,6 +24,10 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import static org.hibernate.orm.properties.Utils.interpretCompatibility; +import static org.hibernate.orm.properties.Utils.interpretDeprecation; +import static org.hibernate.orm.properties.Utils.interpretIncubation; +import static org.hibernate.orm.properties.Utils.interpretUnsafe; import static org.hibernate.orm.properties.jdk17.JavadocToAsciidocConverter.convertFieldJavadocHtmlToAsciidoc; /** @@ -160,6 +164,8 @@ private static void applyMetadata(SettingWorkingDetails settingDetails, Element ); settingDetails.setIncubating( interpretIncubation( fieldJavadocElement ) ); settingDetails.setDeprecated( interpretDeprecation( fieldJavadocElement ) ); + settingDetails.setUnsafe( interpretUnsafe( fieldJavadocElement ) ); + settingDetails.setCompatibility( interpretCompatibility( fieldJavadocElement ) ); } public static Document loadConstants(File javadocDirectory) { @@ -244,27 +250,4 @@ private static void processNotes( noteConsumer.consumeNote( dtNode.text().trim(), ddNode.text().trim() ); } } - - private static boolean interpretIncubation(Element fieldJavadocElement) { - final Element incubatingMarkerElement = fieldJavadocElement.selectFirst( "[href*=.Incubating.html]" ); - return incubatingMarkerElement != null; - } - - private static boolean interpretDeprecation(Element fieldJavadocElement) { - // A setting is considered deprecated with either `@Deprecated` - final Element deprecationDiv = fieldJavadocElement.selectFirst( ".deprecation-block" ); - // presence of this
    indicates the member is deprecated - if ( deprecationDiv != null ) { - return true; - } - - // or `@Remove` - final Element removeMarkerElement = fieldJavadocElement.selectFirst( "[href*=.Remove.html]" ); - if ( removeMarkerElement != null ) { - return true; - } - - return false; - } - }