Reflectively invoke getIdentifier method (for compatibility with Hibernate 6)

Closes gh-28855
This commit is contained in:
Juergen Hoeller 2022-08-11 00:55:33 +02:00
parent 38c9e7f629
commit 293e296d59
8 changed files with 51 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -82,7 +82,7 @@ public class ObjectOptimisticLockingFailureException extends OptimisticLockingFa
* @param cause the source exception
*/
public ObjectOptimisticLockingFailureException(
Class<?> persistentClass, Object identifier, String msg, @Nullable Throwable cause) {
Class<?> persistentClass, @Nullable Object identifier, String msg, @Nullable Throwable cause) {
super(msg, cause);
this.persistentClass = persistentClass;
@ -123,7 +123,7 @@ public class ObjectOptimisticLockingFailureException extends OptimisticLockingFa
* @param cause the source exception
*/
public ObjectOptimisticLockingFailureException(
String persistentClassName, Object identifier, String msg, @Nullable Throwable cause) {
String persistentClassName, @Nullable Object identifier, String msg, @Nullable Throwable cause) {
super(msg, cause);
this.persistentClass = persistentClassName;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -69,7 +69,7 @@ public class ObjectRetrievalFailureException extends DataRetrievalFailureExcepti
* @param cause the source exception
*/
public ObjectRetrievalFailureException(
Class<?> persistentClass, Object identifier, String msg, @Nullable Throwable cause) {
Class<?> persistentClass, @Nullable Object identifier, String msg, @Nullable Throwable cause) {
super(msg, cause);
this.persistentClass = persistentClass;
@ -97,7 +97,7 @@ public class ObjectRetrievalFailureException extends DataRetrievalFailureExcepti
* @param cause the source exception
*/
public ObjectRetrievalFailureException(
String persistentClassName, Object identifier, String msg, @Nullable Throwable cause) {
String persistentClassName, @Nullable Object identifier, String msg, @Nullable Throwable cause) {
super(msg, cause);
this.persistentClass = persistentClassName;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,13 @@
package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.springframework.lang.Nullable;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.util.ReflectionUtils;
/**
* Hibernate-specific subclass of ObjectRetrievalFailureException.
@ -33,11 +36,24 @@ import org.springframework.orm.ObjectRetrievalFailureException;
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
super(ex.getEntityName(), getIdentifier(ex), ex.getMessage(), ex);
}
public HibernateObjectRetrievalFailureException(WrongClassException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
super(ex.getEntityName(), getIdentifier(ex), ex.getMessage(), ex);
}
@Nullable
static Object getIdentifier(HibernateException hibEx) {
try {
// getIdentifier declares Serializable return value on 5.x but Object on 6.x
// -> not binary compatible, let's invoke it reflectively for the time being
return ReflectionUtils.invokeMethod(hibEx.getClass().getMethod("getIdentifier"), hibEx);
}
catch (NoSuchMethodException ex) {
return null;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -35,7 +35,7 @@ import org.springframework.orm.ObjectOptimisticLockingFailureException;
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex);
super(ex.getEntityName(), HibernateObjectRetrievalFailureException.getIdentifier(ex), ex.getMessage(), ex);
}
public HibernateOptimisticLockingFailureException(StaleStateException ex) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -57,7 +57,7 @@ import org.springframework.lang.Nullable;
* way to set up a shared Hibernate SessionFactory in a Spring application context; the
* SessionFactory can then be passed to data access objects via dependency injection.
*
* <p>Compatible with Hibernate 5.5/5.6, as of Spring 6.0.
* <p>Compatible with Hibernate ORM 5.5/5.6, as of Spring Framework 6.0.
* This Hibernate-specific {@code LocalSessionFactoryBean} can be an immediate alternative
* to {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean} for
* common JPA purposes: The Hibernate {@code SessionFactory} will natively expose the JPA

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -78,7 +78,7 @@ import org.springframework.util.ClassUtils;
* Typically combined with {@link HibernateTransactionManager} for declarative
* transactions against the {@code SessionFactory} and its JDBC {@code DataSource}.
*
* <p>Compatible with Hibernate 5.5/5.6, as of Spring 6.0.
* <p>Compatible with Hibernate ORM 5.5/5.6, as of Spring Framework 6.0.
* This Hibernate-specific factory builder can also be a convenient way to set up
* a JPA {@code EntityManagerFactory} since the Hibernate {@code SessionFactory}
* natively exposes the JPA {@code EntityManagerFactory} interface as well now.

View File

@ -70,10 +70,11 @@ import org.springframework.transaction.InvalidIsolationLevelException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.ResourceTransactionDefinition;
import org.springframework.util.ReflectionUtils;
/**
* {@link org.springframework.orm.jpa.JpaDialect} implementation for
* Hibernate EntityManager.
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Hibernate.
* Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1.
*
* @author Juergen Hoeller
* @author Costin Leau
@ -295,13 +296,13 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof UnresolvableObjectException hibEx) {
return new ObjectRetrievalFailureException(hibEx.getEntityName(), hibEx.getIdentifier(), ex.getMessage(), ex);
return new ObjectRetrievalFailureException(hibEx.getEntityName(), getIdentifier(hibEx), ex.getMessage(), ex);
}
if (ex instanceof WrongClassException hibEx) {
return new ObjectRetrievalFailureException(hibEx.getEntityName(), hibEx.getIdentifier(), ex.getMessage(), ex);
return new ObjectRetrievalFailureException(hibEx.getEntityName(), getIdentifier(hibEx), ex.getMessage(), ex);
}
if (ex instanceof StaleObjectStateException hibEx) {
return new ObjectOptimisticLockingFailureException(hibEx.getEntityName(), hibEx.getIdentifier(), ex);
return new ObjectOptimisticLockingFailureException(hibEx.getEntityName(), getIdentifier(hibEx), ex.getMessage(), ex);
}
if (ex instanceof StaleStateException) {
return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex);
@ -324,6 +325,18 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
return entityManager.unwrap(SessionImplementor.class);
}
@Nullable
protected Object getIdentifier(HibernateException hibEx) {
try {
// getIdentifier declares Serializable return value on 5.x but Object on 6.x
// -> not binary compatible, let's invoke it reflectively for the time being
return ReflectionUtils.invokeMethod(hibEx.getClass().getMethod("getIdentifier"), hibEx);
}
catch (NoSuchMethodException ex) {
return null;
}
}
private static class SessionTransactionData {

View File

@ -43,8 +43,8 @@ import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate
* EntityManager.
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate.
* Compatible with Hibernate ORM 5.5/5.6 as well as 6.0/6.1.
*
* <p>Exposes Hibernate's persistence provider and Hibernate's Session as extended
* EntityManager interface, and adapts {@link AbstractJpaVendorAdapter}'s common