Deprecation of Tuplizer Class in Hibernate ORM Version 6

Hello Team,
As per the suggestions and recommendations from the fellow community members, i am in the process of upgrading the Hibernate from version 5.2 to version 6.1 which has been released last week.

I had some code which is referring to EntityMode/[Entity/Component]Tuplizers , i am trying to rewrite it with the new implementation, but it looks like the interface has changed.
I looked for some help on the documents and came across https://in.relation.to/2021/12/08/hibernate-orm-562/ this post which was written for version 5.6.

However when i look at the source code in version 6 hibernate-orm/Tuplizer.java at main · hibernate/hibernate-orm · GitHub and version 5.6 hibernate-orm/Tuplizer.java at 5.6 · hibernate/hibernate-orm · GitHub it looks like the interface functions have changed, some of them are missing.

Can some-one shed some light on how to modify the code with the new implementation?

Thank You in Advance!!

Depends what you are trying to achieve. Please share the purpose of your custom implementation. We have new SPIs to do certain things.

@beikov : We use a tuplizer for persisting an object.
A tuplizer is responsible for:

  • creating the instance of entity which is defined by Instantiator interface.
  • extracting values of a property from the entity which is defined by Getter interface
  • Injecting values for a property into the entity which is defined by Setter interface

Can you please let me know the corresponding SPIs for these functionality?

Thanks!!

Controlling extraction and injection for a property can be done by annotating a property with @AttributeAccessor(strategy = MyPropertyAccessStrategy.class). If you don’t want to annotate your model, you can create a org.hibernate.boot.spi.MetadataContributor and apply these configurations on the properties of the respective PersistenceClass instances.

Changing the way entities are instantiated is not possible anymore.

Why do you need to do this? You really shouldn’t need this functionality.

@beikov : In the earlier version of Hibernate 5.2, we were creating mapping (hbmxml) files and then using it to persist the entity. Earlier we were creating a dynamic map for the entity class using the dom4j mapping. I think now for hbmxml, Hibernate is using JAXB, but was wondering how will these persistence operations etc will change.

If you don’t provide a Java class for the entity mappings, the default is to represent entities as dynamic maps i.e. java.util.Map. If that is all you want/need, then you should only have to drop the tuplizer code and be done.

Hi @beikov, we are in a similar problem… we create rich entities that have services injected, for that we used tuplizer extensions with factories in charge of the Entity instantiation.
What approach would you suggest to achive same behavior using Hibernate 6?

You’d need a custom org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver to be returned in BootstrapContext#getRepresentationStrategySelector if you control the boot process. If you don’t you have to provide a custom org.hibernate.persister.spi.PersisterClassResolver configured via the config property hibernate.persister.resolver.

1 Like

Hi @beikov, thank you for your answers.

Could you please provide more clarification on the first method? Where could I hook my custom ManagedTypeRepresentationResolver?

I control the boot process as follows:

// Some code might be omitted.

@Bean
  public SessionFactory sessionFactory() {
    BootstrapServiceRegistryBuilder bootstrapServiceRegistryBuilder;
    bootstrapServiceRegistryBuilder = new BootstrapServiceRegistryBuilder();

    BootstrapServiceRegistry bootstrapServiceRegistry;
    bootstrapServiceRegistry = bootstrapServiceRegistryBuilder.build();

    StandardServiceRegistryBuilder stdServiceRegistryBuilder =
      new StandardServiceRegistryBuilder(bootstrapServiceRegistry);

    StandardServiceRegistry stdServiceRegistry;
    stdServiceRegistry = stdServiceRegistryBuilder.configure().build();

    MetadataSources metadataSources;
    metadataSources = new MetadataSources(stdServiceRegistry);
    metadataSources.addAnnotatedClass(SomeContent.class);

    Metadata metadata = metadataSources.buildMetadata(stdServiceRegistry);
    SessionFactory sessionFactory = metadata.buildSessionFactory();
    return sessionFactory;
  }

I’m attempting to hook a Spring Bean that is aware of certain (not all) classes needing to be created without invoking a default constructor, but Factories (spring beans), thus enabling Smart Entities.

Thanks in advance!

You’d need to do the same thing that org.hibernate.boot.internal.MetadataImpl#getSessionFactoryBuilder does:

@Bean
public SessionFactory sessionFactory() {
    BootstrapServiceRegistryBuilder bootstrapServiceRegistryBuilder;
    bootstrapServiceRegistryBuilder = new BootstrapServiceRegistryBuilder();

    BootstrapServiceRegistry bootstrapServiceRegistry;
    bootstrapServiceRegistry = bootstrapServiceRegistryBuilder.build();

    StandardServiceRegistryBuilder stdServiceRegistryBuilder =
      new StandardServiceRegistryBuilder(bootstrapServiceRegistry);

    StandardServiceRegistry stdServiceRegistry;
    stdServiceRegistry = stdServiceRegistryBuilder.configure().build();

    MetadataSources metadataSources;
    metadataSources = new MetadataSources(stdServiceRegistry);
    metadataSources.addAnnotatedClass(SomeContent.class);

    Metadata metadata = metadataSources.buildMetadata(stdServiceRegistry);

		final SessionFactoryBuilderService factoryBuilderService = stdServiceRegistry.getService( SessionFactoryBuilderService.class );
		final SessionFactoryBuilderImplementor defaultBuilder = factoryBuilderService.createSessionFactoryBuilder( this, bootstrapContext );

		final ClassLoaderService cls = stdServiceRegistry.getService( ClassLoaderService.class );
		final java.util.Collection<SessionFactoryBuilderFactory> discoveredBuilderFactories = cls.loadJavaServices( SessionFactoryBuilderFactory.class );

		SessionFactoryBuilder builder = null;
		List<String> activeFactoryNames = null;

		for ( SessionFactoryBuilderFactory discoveredBuilderFactory : discoveredBuilderFactories ) {
			final SessionFactoryBuilder returnedBuilder = discoveredBuilderFactory.getSessionFactoryBuilder( this, defaultBuilder );
			if ( returnedBuilder != null ) {
				if ( activeFactoryNames == null ) {
					activeFactoryNames = new ArrayList<>();
				}
				activeFactoryNames.add( discoveredBuilderFactory.getClass().getName() );
				builder = returnedBuilder;
			}
		}

		if ( activeFactoryNames != null && activeFactoryNames.size() > 1 ) {
			throw new HibernateException(
					"Multiple active SessionFactoryBuilderFactory definitions were discovered : " +
							String.join(", ", activeFactoryNames)
			);
		}


		if ( builder != null ) {
			return builder.build();
		}

		return defaultBuilder.build();
	}
1 Like