The two main contracts of Hibernate, org.hibernate.SessionFactory and org.hibernate.Session, are both defined as interfaces which allows for custom implementations to be provided. There are two high-level ways in which custom implementations can be provided to users. The first is to develop a custom bootstrap API specific to the custom implementation. The second way is to integrate with the Hibernate bootstrap API. This guide will cover the second approach.

Implementor contracts

A Hibernate naming convention is that SPI contracts extending API contracts are named with Implementor appended to the API contract name. For SessionFactory and Session that is SessionFactoryImplementor and SessionImplementor respectively. These SPI contracts extra information and functionality needed by internal components as well as other SPI components. Therefore, custom SessionFactory and Session should additionally implement org.hibernate.engine.spi.SessionFactoryImplementor and org.hibernate.engine.spi.SessionImplementor. See all pertinent JavaDocs for discussions of implementation details.

Integration hooks

org.hibernate.boot.SessionFactoryBuilder is part of the Hibernate native bootstrap API where we want to configure the SessionFactory to be built. Third parties can hook into this process by supplying a org.hibernate.boot.spi.SessionFactoryBuilderFactory via the Java ServiceLoader mechanism (see JavaDocs for java.util.ServiceLoader if you are unfamiliar with this service discovery mechanism). As you might guess from their names, a SessionFactoryBuilderFactory is responsible for creating SessionFactoryBuilder instances and a SessionFactoryBuilder is in turn responsible for creating SessionFactory instances.

org.hibernate.boot.spi.SessionFactoryOptions are the options ultimately passed to the SessionFactory being built. They represent the choices applied by the user via the SessionFactoryBuilder contract. Custom integrations can leverage this and the SessionFactoryBuilder to also expose custom option setting.

Example 1. Custom SessionFactoryBuilderFactory with additional option
public class CustomSessionFactoryBuilderFactory
		implements SessionFactoryBuilderFactory {
	@Override
	public SessionFactoryBuilder getSessionFactoryBuilder(
			MetadataImplementor metadata,
			SessionFactoryBuilderImplementor defaultBuilder) {
		return new CustomSessionFactoryBuilder( metadata, defaultBuilder );
	}
}

public class CustomSessionFactoryBuilder
		extends AbstractDelegatingSessionFactoryBuilder {
	private final MetadataImplementor metadata;

    private final boolean customSetting;

	public DelegatingSessionFactoryBuilder(
			MetadataImplementor metadata,
			SessionFactoryBuilderImplementor delegate) {
		super( delegate );
		this.metadata = metadata;

		// initialize customSetting, maybe based on config settings...
		ConfigurationService cfgService = metadata.getMetadataBuildingOptions()
				.getServiceRegistry()
				.getService( ConfigurationService.class );
		this.customSetting = cfgService.getSetting(
				"com.acme.domain.custom_setting",
				StandardConverters.BOOLEAN,
				true
		);
	}

	@Override
	public DelegatingSessionFactoryBuilder unwrap() {
	    return (DelegatingSessionFactoryBuilder) this;
	}

    public CustomSessionFactoryBuilder applyCustomSetting(boolean enabled) {
     	this.customSetting = enabled;
    	return this;
    }

	@Override
	public SessionFactory build() {
	    CustomSessionFactoryOptions options = new CustomSessionFactoryOptions(
	    		getDelegate().buildSessionFactoryOptions(),
	    		customSetting
	    );
	    return new CustomSessionFactory( metadata, options );
	}
}

public class CustomSessionFactoryOptions
		extends AbstractDelegatingSessionFactoryOptions {
    private final boolean customSetting;

	public CustomSessionFactoryOptions(
			SessionFactoryOptions baseOptions,
			boolean customSetting) {
		super( baseOptions );
		this.customSetting = customSetting;
	}

	public boolean getCustomSetting() {
		return customSetting;
	}
}

Users can then build your custom SessionFactory still using the normal Hibernate bootstrap. In fact, accepting defaults for your custom settings/options, their code does not even change. Of course they can also apply selections to your custom settings/options as well:

Example 2. Example usage
Metadata metadata = ...;

// The SessionFactory returned here is concretely
// a CustomSessionFactory
SessionFactory sf = metadata.getSessionFactoryBuilder()
		.unwrap( CustomSessionFactoryBuilder.class )
		.applyCustomSetting( false )
		.buildSessionFactory();