HHH-18545 - Document "characteristics" of settings

This commit is contained in:
Steve Ebersole 2024-09-26 11:47:37 -05:00
parent d4ef44db00
commit 4f9035e9f8
11 changed files with 205 additions and 96 deletions

View File

@ -573,7 +573,7 @@ settingsDocumentation {
} }
transaction { transaction {
explicitPosition = 6 explicitPosition = 6
summary = "Proxool Connection Pool Settings" summary = "Transaction Environment Settings"
description = "Settings which control how Hibernate interacts with and manages transactions" description = "Settings which control how Hibernate interacts with and manages transactions"
settingsClassName "org.hibernate.cfg.TransactionSettings" settingsClassName "org.hibernate.cfg.TransactionSettings"
} }

View File

@ -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 {
}

View File

@ -18,7 +18,8 @@ import jakarta.persistence.criteria.CriteriaUpdate;
public interface QuerySettings { public interface QuerySettings {
/** /**
* Boolean setting to control if the use of tech preview JSON functions in HQL is enabled. * Boolean setting to control if the use of tech preview JSON functions in HQL is enabled.
* By default, this is {@code false} i.e. disabled since the functions are still incubating. *
* @settingDefault {@code false} (disabled) since the functions are still incubating.
* *
* @since 7.0 * @since 7.0
*/ */
@ -27,7 +28,8 @@ public interface QuerySettings {
/** /**
* Boolean setting to control if the use of tech preview XML functions in HQL is enabled. * Boolean setting to control if the use of tech preview XML functions in HQL is enabled.
* By default, this is {@code false} i.e. disabled since the functions are still incubating. *
* @settingDefault {@code false} (disabled) since the functions are still incubating.
* *
* @since 7.0 * @since 7.0
*/ */
@ -39,6 +41,8 @@ public interface QuerySettings {
* databases. By default, integer division in HQL can produce a non-integer * databases. By default, integer division in HQL can produce a non-integer
* on Oracle, MySQL, or MariaDB. * on Oracle, MySQL, or MariaDB.
* *
* @settingDefault {@code false}
*
* @since 6.5 * @since 6.5
*/ */
String PORTABLE_INTEGER_DIVISION = "hibernate.query.hql.portable_integer_division"; String PORTABLE_INTEGER_DIVISION = "hibernate.query.hql.portable_integer_division";
@ -70,10 +74,10 @@ public interface QuerySettings {
/** /**
* When enabled, specifies that named queries be checked during startup. * When enabled, specifies that named queries be checked during startup.
* <p> * <p>
* By default, named queries are checked at startup.
* <p>
* Mainly intended for use in test environments. * Mainly intended for use in test environments.
* *
* @settingDefault {@code true} (enabled) - named queries are checked at startup.
*
* @see org.hibernate.boot.SessionFactoryBuilder#applyNamedQueryCheckingOnStartup(boolean) * @see org.hibernate.boot.SessionFactoryBuilder#applyNamedQueryCheckingOnStartup(boolean)
*/ */
String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check"; String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check";
@ -102,8 +106,8 @@ public interface QuerySettings {
* {@link jakarta.persistence.Query#setParameter(jakarta.persistence.Parameter,Object)} * {@link jakarta.persistence.Query#setParameter(jakarta.persistence.Parameter,Object)}
* to specify its argument are passed to JDBC using a bind parameter. * to specify its argument are passed to JDBC using a bind parameter.
* </ul> * </ul>
* <p> *
* The default mode is {@link org.hibernate.query.criteria.ValueHandlingMode#BIND}. * @settingDefault {@link org.hibernate.query.criteria.ValueHandlingMode#BIND}.
* *
* @since 6.0.0 * @since 6.0.0
* *
@ -119,8 +123,8 @@ public interface QuerySettings {
* of null values} sorted via the HQL {@code ORDER BY} clause, either {@code none}, * of null values} sorted via the HQL {@code ORDER BY} clause, either {@code none},
* {@code first}, or {@code last}, or an instance of the enumeration * {@code first}, or {@code last}, or an instance of the enumeration
* {@link jakarta.persistence.criteria.Nulls}. * {@link jakarta.persistence.criteria.Nulls}.
* <p> *
* The default is {@code none}. * @settingDefault {@code none}.
* *
* @see jakarta.persistence.criteria.Nulls * @see jakarta.persistence.criteria.Nulls
* @see org.hibernate.boot.SessionFactoryBuilder#applyDefaultNullPrecedence(jakarta.persistence.criteria.Nulls) * @see org.hibernate.boot.SessionFactoryBuilder#applyDefaultNullPrecedence(jakarta.persistence.criteria.Nulls)
@ -155,8 +159,8 @@ public interface QuerySettings {
/** /**
* When enabled, ordinal parameters (represented by the {@code ?} placeholder) in * When enabled, ordinal parameters (represented by the {@code ?} placeholder) in
* native queries will be ignored. * native queries will be ignored.
* <p> *
* By default, native queries are checked for ordinal placeholders. * @settingDefault {@code false} (disabled) - native queries are checked for ordinal placeholders.
* *
* @see SessionFactoryOptions#getNativeJdbcParametersIgnored() * @see SessionFactoryOptions#getNativeJdbcParametersIgnored()
*/ */
@ -167,12 +171,14 @@ public interface QuerySettings {
* {@link java.sql.Time}, and {@link java.sql.Timestamp} instead of the * {@link java.sql.Time}, and {@link java.sql.Timestamp} instead of the
* datetime types from {@link java.time}, recovering the behavior of * datetime types from {@link java.time}, recovering the behavior of
* native queries in Hibernate 6 and earlier. * native queries in Hibernate 6 and earlier.
* <p> *
* By default, native queries return {@link java.time.LocalDate}, * @settingDefault {@code false} (disabled) - native queries return
* {@link java.time.LocalTime}, and {@link java.time.LocalDateTime}. * {@link java.time.LocalDate}, {@link java.time.LocalTime}, and
* {@link java.time.LocalDateTime}.
* *
* @since 7.0 * @since 7.0
*/ */
@Compatibility
String NATIVE_PREFER_JDBC_DATETIME_TYPES = "hibernate.query.native.prefer_jdbc_datetime_types"; String NATIVE_PREFER_JDBC_DATETIME_TYPES = "hibernate.query.native.prefer_jdbc_datetime_types";
/** /**
@ -183,9 +189,9 @@ public interface QuerySettings {
* <p> * <p>
* When enabled, this setting specifies that an exception should be thrown for any * When enabled, this setting specifies that an exception should be thrown for any
* query which would result in the limit being applied in-memory. * query which would result in the limit being applied in-memory.
* <p> *
* By default, the exception is <em>disabled</em>, and the possibility of terrible * @settingDefault {@code false} (disabled) - no exception is thrown and the
* performance is left as a problem for the client to avoid. * possibility of terrible performance is left as a problem for the client to avoid.
* *
* @since 5.2.13 * @since 5.2.13
*/ */
@ -203,8 +209,8 @@ public interface QuerySettings {
* <li>{@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#EXCEPTION "exception"} * <li>{@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#EXCEPTION "exception"}
* specifies that a {@link org.hibernate.HibernateException} should be thrown. * specifies that a {@link org.hibernate.HibernateException} should be thrown.
* </ul> * </ul>
* <p> *
* By default, a warning is logged. * @settingDefault {@link org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode#WARNING "warning"}
* *
* @since 5.2.17 * @since 5.2.17
* *

View File

@ -4,6 +4,7 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import jakarta.persistence.spi.PersistenceUnitInfo; import jakarta.persistence.spi.PersistenceUnitInfo;
/** /**
@ -127,36 +128,6 @@ public interface TransactionSettings {
*/ */
String ALLOW_JTA_TRANSACTION_ACCESS = "hibernate.jta.allowTransactionAccess"; 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.
* <p>
* Since version 5.2 Hibernate conforms with the JPA specification and disallows
* flushing any update outside a transaction.
* <p>
* Values are {@code true}, which allows flushing outside a transaction, and
* {@code false}, which does not.
* <p>
* 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 * When enabled, specifies that the {@link org.hibernate.Session} should be
* closed automatically at the end of each transaction. * closed automatically at the end of each transaction.
@ -176,4 +147,43 @@ public interface TransactionSettings {
* @see org.hibernate.boot.SessionFactoryBuilder#applyAutoFlushing(boolean) * @see org.hibernate.boot.SessionFactoryBuilder#applyAutoFlushing(boolean)
*/ */
String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion"; 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.
* <p>
* Since version 5.2 Hibernate conforms with the JPA specification and disallows
* flushing any update outside a transaction.
* <p>
* Values are {@code true}, which allows flushing outside a transaction, and
* {@code false}, which does not.
* <p>
* 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";
} }

View File

@ -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 {
}

View File

@ -109,6 +109,12 @@ public class AsciiDocWriter {
if ( lifecycleDetails.isDeprecated() ) { if ( lifecycleDetails.isDeprecated() ) {
writer.write( "WARNING: *_This setting is considered deprecated_*\n\n" ); 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 ) { if ( lifecycleDetails.getSince() != null ) {
writer.write( "*_Since:_* _" + lifecycleDetails.getSince() + "_\n\n" ); writer.write( "*_Since:_* _" + lifecycleDetails.getSince() + "_\n\n" );

View File

@ -18,6 +18,8 @@ public class SettingDescriptor {
private final String defaultValue; private final String defaultValue;
private final String apiNote; private final String apiNote;
private final LifecycleDetails lifecycleDetails; private final LifecycleDetails lifecycleDetails;
private final boolean unsafe;
private final boolean compatibility;
public SettingDescriptor( public SettingDescriptor(
String name, String name,
@ -27,6 +29,8 @@ public class SettingDescriptor {
String comment, String comment,
String defaultValue, String defaultValue,
String apiNote, String apiNote,
boolean unsafe,
boolean compatibility,
LifecycleDetails lifecycleDetails) { LifecycleDetails lifecycleDetails) {
this.name = name; this.name = name;
this.settingsClassName = settingsClassName; this.settingsClassName = settingsClassName;
@ -35,6 +39,8 @@ public class SettingDescriptor {
this.publishedJavadocLink = publishedJavadocLink; this.publishedJavadocLink = publishedJavadocLink;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
this.apiNote = apiNote; this.apiNote = apiNote;
this.unsafe = unsafe;
this.compatibility = compatibility;
this.lifecycleDetails = lifecycleDetails; this.lifecycleDetails = lifecycleDetails;
} }
@ -48,7 +54,9 @@ public class SettingDescriptor {
String apiNote, String apiNote,
String since, String since,
boolean deprecated, boolean deprecated,
boolean incubating) { boolean incubating,
boolean unsafe,
boolean compatibility) {
this( this(
name, name,
settingsClassName, settingsClassName,
@ -56,6 +64,8 @@ public class SettingDescriptor {
publishedJavadocLink, comment, publishedJavadocLink, comment,
defaultValue, defaultValue,
apiNote, apiNote,
unsafe,
compatibility,
new LifecycleDetails( since, deprecated, incubating ) new LifecycleDetails( since, deprecated, incubating )
); );
} }
@ -100,6 +110,14 @@ public class SettingDescriptor {
return settingFieldName; return settingFieldName;
} }
public boolean isUnsafe() {
return unsafe;
}
public boolean isCompatibility() {
return compatibility;
}
public LifecycleDetails getLifecycleDetails() { public LifecycleDetails getLifecycleDetails() {
return lifecycleDetails; return lifecycleDetails;
} }

View File

@ -23,6 +23,8 @@ public class SettingWorkingDetails {
private String since; private String since;
private boolean deprecated; private boolean deprecated;
private boolean incubating; private boolean incubating;
private boolean unsafe;
private boolean compatibility;
private List<String> relatedSettingNames; private List<String> relatedSettingNames;
public SettingWorkingDetails( public SettingWorkingDetails(
@ -92,6 +94,22 @@ public class SettingWorkingDetails {
this.incubating = 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<String> getRelatedSettingNames() { public List<String> getRelatedSettingNames() {
return relatedSettingNames; return relatedSettingNames;
} }
@ -134,7 +152,9 @@ public class SettingWorkingDetails {
apiNote, apiNote,
since, since,
deprecated, deprecated,
incubating incubating,
unsafe,
compatibility
); );
} }
} }

View File

@ -14,6 +14,8 @@ import java.util.SortedSet;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import org.jsoup.nodes.Element;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -39,4 +41,39 @@ public class Utils {
} ); } );
return map; 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 <div/> indicates the member is deprecated
if ( deprecationDiv != null ) {
return true;
}
// or `@Remove`
if ( containsHref( fieldJavadocElement, "Remove.html" ) ) {
return true;
}
return false;
}
} }

View File

@ -23,6 +23,10 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; 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.packagePrefix;
import static org.hibernate.orm.properties.Utils.withoutPackagePrefix; import static org.hibernate.orm.properties.Utils.withoutPackagePrefix;
@ -195,6 +199,8 @@ public class SettingsCollector {
settingDetails.setIncubating( interpretIncubation( fieldJavadocElement ) ); settingDetails.setIncubating( interpretIncubation( fieldJavadocElement ) );
settingDetails.setDeprecated( interpretDeprecation( fieldJavadocElement ) ); settingDetails.setDeprecated( interpretDeprecation( fieldJavadocElement ) );
settingDetails.setUnsafe( interpretUnsafe( fieldJavadocElement ) );
settingDetails.setCompatibility( interpretCompatibility( fieldJavadocElement ) );
} }
private static SettingsDocSection findMatchingDocSection( private static SettingsDocSection findMatchingDocSection(
@ -245,28 +251,6 @@ public class SettingsCollector {
} }
} }
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 <div/> 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( private static Elements cleanupFieldJavadocElement(
Element fieldJavadocElement, Element fieldJavadocElement,
String className, String className,

View File

@ -24,6 +24,10 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; 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; import static org.hibernate.orm.properties.jdk17.JavadocToAsciidocConverter.convertFieldJavadocHtmlToAsciidoc;
/** /**
@ -160,6 +164,8 @@ public class SettingsCollector {
); );
settingDetails.setIncubating( interpretIncubation( fieldJavadocElement ) ); settingDetails.setIncubating( interpretIncubation( fieldJavadocElement ) );
settingDetails.setDeprecated( interpretDeprecation( fieldJavadocElement ) ); settingDetails.setDeprecated( interpretDeprecation( fieldJavadocElement ) );
settingDetails.setUnsafe( interpretUnsafe( fieldJavadocElement ) );
settingDetails.setCompatibility( interpretCompatibility( fieldJavadocElement ) );
} }
public static Document loadConstants(File javadocDirectory) { public static Document loadConstants(File javadocDirectory) {
@ -244,27 +250,4 @@ public class SettingsCollector {
noteConsumer.consumeNote( dtNode.text().trim(), ddNode.text().trim() ); 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 <div/> 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;
}
} }