提交 54004e0d 编写于 作者: J Juergen Hoeller

Upgrade to JPA 2.1+ and Bean Validation 1.1+; remove native support for Hibernate 3.6 and 4.x

Issue: SPR-13481
Issue: SPR-13827
上级 69ec437f
......@@ -24,11 +24,13 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.validation.Configuration;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
import javax.validation.TraversableResolver;
import javax.validation.Validation;
import javax.validation.ValidationProviderResolver;
......@@ -66,14 +68,8 @@ import org.springframework.util.ReflectionUtils;
* you will almost always use the default Validator anyway. This can also be injected directly
* into any target dependency of type {@link org.springframework.validation.Validator}!
*
* <p><b>As of Spring 4.0, this class supports Bean Validation 1.0 and 1.1, with special support
* for Hibernate Validator 4.3 and 5.x</b> (see {@link #setValidationMessageSource}).
*
* <p>Note that Bean Validation 1.1's {@code #forExecutables} method isn't supported: We do not
* expect that method to be called by application code; consider {@link MethodValidationInterceptor}
* instead. If you really need programmatic {@code #forExecutables} access, inject this class as
* a {@link ValidatorFactory} and call {@link #getValidator()} on it, then {@code #forExecutables}
* on the returned native {@link Validator} reference instead of directly on this class.
* <p><b>As of Spring 5.0, this class requires Bean Validation 1.1, with special support
* for Hibernate Validator 5.x</b> (see {@link #setValidationMessageSource}).
*
* <p>This class is also being used by Spring's MVC configuration namespace, in case of the
* {@code javax.validation} API being present but no explicit Validator having been configured.
......@@ -88,10 +84,6 @@ import org.springframework.util.ReflectionUtils;
public class LocalValidatorFactoryBean extends SpringValidatorAdapter
implements ValidatorFactory, ApplicationContextAware, InitializingBean, DisposableBean {
// Bean Validation 1.1 close() method available?
private static final Method closeMethod = ClassUtils.getMethodIfAvailable(ValidatorFactory.class, "close");
@SuppressWarnings("rawtypes")
private Class providerClass;
......@@ -305,55 +297,23 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
}
private void configureParameterNameProviderIfPossible(Configuration<?> configuration) {
try {
Class<?> parameterNameProviderClass =
ClassUtils.forName("javax.validation.ParameterNameProvider", getClass().getClassLoader());
Method parameterNameProviderMethod =
Configuration.class.getMethod("parameterNameProvider", parameterNameProviderClass);
final Object defaultProvider = ReflectionUtils.invokeMethod(
Configuration.class.getMethod("getDefaultParameterNameProvider"), configuration);
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
Object parameterNameProvider = Proxy.newProxyInstance(getClass().getClassLoader(),
new Class<?>[] {parameterNameProviderClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getParameterNames")) {
String[] result = null;
if (args[0] instanceof Constructor) {
result = discoverer.getParameterNames((Constructor<?>) args[0]);
}
else if (args[0] instanceof Method) {
result = discoverer.getParameterNames((Method) args[0]);
}
if (result != null) {
return Arrays.asList(result);
}
else {
try {
return method.invoke(defaultProvider, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
else {
// toString, equals, hashCode
try {
return method.invoke(this, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
});
ReflectionUtils.invokeMethod(parameterNameProviderMethod, configuration, parameterNameProvider);
}
catch (Exception ex) {
// Bean Validation 1.1 API not available - simply not applying the ParameterNameDiscoverer
}
// TODO: inner class
final ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
final ParameterNameProvider defaultProvider = configuration.getDefaultParameterNameProvider();
configuration.parameterNameProvider(new ParameterNameProvider() {
@Override
public List<String> getParameterNames(Constructor<?> constructor) {
String[] paramNames = discoverer.getParameterNames(constructor);
return (paramNames != null ? Arrays.asList(paramNames) :
defaultProvider.getParameterNames(constructor));
}
@Override
public List<String> getParameterNames(Method method) {
String[] paramNames = discoverer.getParameterNames(method);
return (paramNames != null ? Arrays.asList(paramNames) :
defaultProvider.getParameterNames(method));
}
});
}
/**
......@@ -397,9 +357,14 @@ public class LocalValidatorFactoryBean extends SpringValidatorAdapter
return this.validatorFactory.getConstraintValidatorFactory();
}
@Override
public ParameterNameProvider getParameterNameProvider() {
return this.validatorFactory.getParameterNameProvider();
}
public void close() {
if (closeMethod != null && this.validatorFactory != null) {
ReflectionUtils.invokeMethod(closeMethod, this.validatorFactory);
if (this.validatorFactory != null) {
this.validatorFactory.close();
}
}
......
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
......@@ -26,7 +26,6 @@ import javax.validation.ValidatorFactory;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.validator.HibernateValidator;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.AnnotationUtils;
......@@ -48,9 +47,8 @@ import org.springframework.validation.annotation.Validated;
* at the type level of the containing target class, applying to all public service methods
* of that class. By default, JSR-303 will validate against its default group only.
*
* <p>As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider
* (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator
* 4.3. The actual provider will be autodetected and automatically adapted.
* <p>As of Spring 5.0, this functionality requires a Bean Validation 1.1 provider
* (such as Hibernate Validator 5.x).
*
* @author Juergen Hoeller
* @since 3.1
......@@ -88,8 +86,7 @@ public class MethodValidationInterceptor implements MethodInterceptor {
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
*/
public MethodValidationInterceptor() {
this(forExecutablesMethod != null ? Validation.buildDefaultValidatorFactory() :
HibernateValidatorDelegate.buildValidatorFactory());
this(Validation.buildDefaultValidatorFactory());
}
/**
......@@ -114,43 +111,36 @@ public class MethodValidationInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?>[] groups = determineValidationGroups(invocation);
if (forExecutablesMethod != null) {
// Standard Bean Validation 1.1 API
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
Method methodToValidate = invocation.getMethod();
Set<ConstraintViolation<?>> result;
try {
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
catch (IllegalArgumentException ex) {
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
// Let's try to find the bridged method on the implementation class...
methodToValidate = BridgeMethodResolver.findBridgedMethod(
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
Object returnValue = invocation.proceed();
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
return returnValue;
// Standard Bean Validation 1.1 API
Object execVal = ReflectionUtils.invokeMethod(forExecutablesMethod, this.validator);
Method methodToValidate = invocation.getMethod();
Set<ConstraintViolation<?>> result;
try {
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
catch (IllegalArgumentException ex) {
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
// Let's try to find the bridged method on the implementation class...
methodToValidate = BridgeMethodResolver.findBridgedMethod(
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateParametersMethod,
execVal, invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
else {
// Hibernate Validator 4.3's native API
return HibernateValidatorDelegate.invokeWithinValidation(invocation, this.validator, groups);
Object returnValue = invocation.proceed();
result = (Set<ConstraintViolation<?>>) ReflectionUtils.invokeMethod(validateReturnValueMethod,
execVal, invocation.getThis(), methodToValidate, returnValue, groups);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
return returnValue;
}
/**
......@@ -168,36 +158,4 @@ public class MethodValidationInterceptor implements MethodInterceptor {
return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
}
/**
* Inner class to avoid a hard-coded Hibernate Validator 4.3 dependency.
*/
private static class HibernateValidatorDelegate {
public static ValidatorFactory buildValidatorFactory() {
return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory();
}
@SuppressWarnings("deprecation")
public static Object invokeWithinValidation(MethodInvocation invocation, Validator validator, Class<?>[] groups)
throws Throwable {
org.hibernate.validator.method.MethodValidator methodValidator =
validator.unwrap(org.hibernate.validator.method.MethodValidator.class);
Set<org.hibernate.validator.method.MethodConstraintViolation<Object>> result =
methodValidator.validateAllParameters(
invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups);
if (!result.isEmpty()) {
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
}
Object returnValue = invocation.proceed();
result = methodValidator.validateReturnValue(
invocation.getThis(), invocation.getMethod(), returnValue, groups);
if (!result.isEmpty()) {
throw new org.hibernate.validator.method.MethodConstraintViolationException(result);
}
return returnValue;
}
}
}
......@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.validation.ConstraintViolation;
import javax.validation.executable.ExecutableValidator;
import javax.validation.metadata.BeanDescriptor;
import javax.validation.metadata.ConstraintDescriptor;
......@@ -299,6 +300,11 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator);
}
@Override
public ExecutableValidator forExecutables() {
return this.targetValidator.forExecutables();
}
/**
* Wrapper for a String attribute which can be resolved via a {@code MessageSource},
......
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
......@@ -31,10 +31,9 @@ import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
* Tested against Hibernate Validator 5.x.
*
* @author Juergen Hoeller
* @since 3.0
*/
public class BeanValidationPostProcessorTests {
......@@ -52,6 +51,7 @@ public class BeanValidationPostProcessorTests {
assertTrue(ex.getRootCause().getMessage().contains("testBean"));
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
}
ac.close();
}
@Test
......@@ -63,6 +63,7 @@ public class BeanValidationPostProcessorTests {
bd.getPropertyValues().add("testBean", new TestBean());
ac.registerBeanDefinition("bean", bd);
ac.refresh();
ac.close();
}
@Test
......@@ -74,6 +75,7 @@ public class BeanValidationPostProcessorTests {
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
ac.refresh();
ac.close();
}
@Test
......@@ -92,6 +94,7 @@ public class BeanValidationPostProcessorTests {
assertTrue(ex.getRootCause().getMessage().contains("stringValue"));
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
}
ac.close();
}
@Test
......@@ -103,6 +106,7 @@ public class BeanValidationPostProcessorTests {
bd.getPropertyValues().add("stringValue", "ss");
ac.registerBeanDefinition("bean", bd);
ac.refresh();
ac.close();
}
......
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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,11 +35,11 @@ import org.springframework.validation.annotation.Validated;
import static org.junit.Assert.*;
/**
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
* Tests against Hibernate Validator 5.x.
*
* @author Juergen Hoeller
* @since 3.1
*/
@SuppressWarnings("rawtypes")
public class MethodValidationTests {
@Test
......@@ -65,6 +65,7 @@ public class MethodValidationTests {
}
@SuppressWarnings("unchecked")
private void doTestProxyValidation(MyValidInterface proxy) {
assertNotNull(proxy.myValidMethod("value", 5));
try {
......
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
......@@ -38,6 +38,10 @@ import javax.validation.constraints.NotNull;
import org.hibernate.validator.HibernateValidator;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
......@@ -47,10 +51,9 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Tested against Hibernate Validator 4.3, as of Spring 4.0.
* Tests against Hibernate Validator 5.x.
*
* @author Juergen Hoeller
* @since 3.0
*/
public class ValidatorFactoryTests {
......@@ -58,6 +61,7 @@ public class ValidatorFactoryTests {
public void testSimpleValidation() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
assertEquals(2, result.size());
......@@ -78,6 +82,7 @@ public class ValidatorFactoryTests {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setProviderClass(HibernateValidator.class);
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
Set<ConstraintViolation<ValidPerson>> result = validator.validate(person);
assertEquals(2, result.size());
......@@ -112,6 +117,7 @@ public class ValidatorFactoryTests {
public void testSpringValidationFieldType() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
person.setName("Phil");
person.getAddress().setStreet("Phil's Street");
......@@ -126,6 +132,7 @@ public class ValidatorFactoryTests {
public void testSpringValidation() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
validator.validate(person, result);
......@@ -153,6 +160,7 @@ public class ValidatorFactoryTests {
public void testSpringValidationWithClassLevel() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
person.setName("Juergen");
person.getAddress().setStreet("Juergen's Street");
......@@ -166,10 +174,32 @@ public class ValidatorFactoryTests {
assertTrue(errorCodes.contains("NameAddressValid"));
}
@Test
public void testSpringValidationWithAutowiredValidator() throws Exception {
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(
LocalValidatorFactoryBean.class);
LocalValidatorFactoryBean validator = ctx.getBean(LocalValidatorFactoryBean.class);
ValidPerson person = new ValidPerson();
person.expectsAutowiredValidator = true;
person.setName("Juergen");
person.getAddress().setStreet("Juergen's Street");
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
validator.validate(person, result);
assertEquals(1, result.getErrorCount());
ObjectError globalError = result.getGlobalError();
List<String> errorCodes = Arrays.asList(globalError.getCodes());
assertEquals(2, errorCodes.size());
assertTrue(errorCodes.contains("NameAddressValid.person"));
assertTrue(errorCodes.contains("NameAddressValid"));
ctx.close();
}
@Test
public void testSpringValidationWithErrorInListElement() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
person.getAddressList().add(new ValidAddress());
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
......@@ -187,6 +217,7 @@ public class ValidatorFactoryTests {
public void testSpringValidationWithErrorInSetElement() throws Exception {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet();
ValidPerson person = new ValidPerson();
person.getAddressSet().add(new ValidAddress());
BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person");
......@@ -240,6 +271,8 @@ public class ValidatorFactoryTests {
@Valid
private Set<ValidAddress> addressSet = new LinkedHashSet<ValidAddress>();
public boolean expectsAutowiredValidator = false;
public String getName() {
return name;
}
......@@ -304,16 +337,22 @@ public class ValidatorFactoryTests {
public static class NameAddressValidator implements ConstraintValidator<NameAddressValid, ValidPerson> {
@Autowired
private Environment environment;
@Override
public void initialize(NameAddressValid constraintAnnotation) {
}
@Override
public boolean isValid(ValidPerson value, ConstraintValidatorContext context) {
if (value.expectsAutowiredValidator) {
assertNotNull(this.environment);
}
boolean valid = (value.name == null || !value.address.street.contains(value.name));
if (!valid && "Phil".equals(value.name)) {
context.buildConstraintViolationWithTemplate(
context.getDefaultConstraintMessageTemplate()).addNode("address").addConstraintViolation().disableDefaultConstraintViolation();
context.getDefaultConstraintMessageTemplate()).addPropertyNode("address").addConstraintViolation().disableDefaultConstraintViolation();
}
return valid;
}
......@@ -378,7 +417,7 @@ public class ValidatorFactoryTests {
public boolean isValid(InnerBean bean, ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
if (bean.getValue() == null) {
context.buildConstraintViolationWithTemplate("NULL"). addNode("value").addConstraintViolation();
context.buildConstraintViolationWithTemplate("NULL").addPropertyNode("value").addConstraintViolation();
return false;
}
return true;
......
/*
* Copyright 2002-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import org.hibernate.TransactionException;
import org.hibernate.service.Service;
import org.springframework.transaction.jta.UserTransactionAdapter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Implementation of Hibernate 4's JtaPlatform SPI (which has a different package
* location in Hibernate 4.0-4.2 vs 4.3), exposing passed-in {@link TransactionManager},
* {@link UserTransaction} and {@link TransactionSynchronizationRegistry} references.
*
* @author Juergen Hoeller
* @since 3.1.2
*/
@SuppressWarnings({"serial", "unchecked"})
class ConfigurableJtaPlatform implements InvocationHandler {
static final Class<? extends Service> jtaPlatformClass;
static {
Class<?> jpClass;
try {
// Try Hibernate 4.0-4.2 JtaPlatform variant
jpClass = ClassUtils.forName("org.hibernate.service.jta.platform.spi.JtaPlatform",
ConfigurableJtaPlatform.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
try {
// Try Hibernate 4.3 JtaPlatform variant
jpClass = ClassUtils.forName("org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform",
ConfigurableJtaPlatform.class.getClassLoader());
}
catch (ClassNotFoundException ex2) {
throw new IllegalStateException("Neither Hibernate 4.0-4.2 nor 4.3 variant of JtaPlatform found");
}
}
jtaPlatformClass = (Class<? extends Service>) jpClass;
}
static String getJtaPlatformBasePackage() {
String className = jtaPlatformClass.getName();
return className.substring(0, className.length() - "spi.JtaPlatform".length());
}
private final TransactionManager transactionManager;
private final UserTransaction userTransaction;
private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
/**
* Create a new ConfigurableJtaPlatform instance with the given
* JTA TransactionManager and optionally a given UserTransaction.
* @param tm the JTA TransactionManager reference (required)
* @param ut the JTA UserTransaction reference (optional)
* @param tsr the JTA 1.1 TransactionSynchronizationRegistry (optional)
*/
public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut, TransactionSynchronizationRegistry tsr) {
Assert.notNull(tm, "TransactionManager reference must not be null");
this.transactionManager = tm;
this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
this.transactionSynchronizationRegistry = tsr;
}
public TransactionManager retrieveTransactionManager() {
return this.transactionManager;
}
public UserTransaction retrieveUserTransaction() {
return this.userTransaction;
}
public Object getTransactionIdentifier(Transaction transaction) {
return transaction;
}
public boolean canRegisterSynchronization() {
try {
return (this.transactionManager.getStatus() == Status.STATUS_ACTIVE);
}
catch (SystemException ex) {
throw new TransactionException("Could not determine JTA transaction status", ex);
}
}
public void registerSynchronization(Synchronization synchronization) {
if (this.transactionSynchronizationRegistry != null) {
this.transactionSynchronizationRegistry.registerInterposedSynchronization(synchronization);
}
else {
try {
this.transactionManager.getTransaction().registerSynchronization(synchronization);
}
catch (Exception ex) {
throw new TransactionException("Could not access JTA Transaction to register synchronization", ex);
}
}
}
public int getCurrentStatus() throws SystemException {
return this.transactionManager.getStatus();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(this, args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to delegate to corresponding implementation method", ex);
}
}
/**
* Obtain a proxy that implements the current Hibernate version's JtaPlatform interface
* in the right package location, delegating all invocations to the same-named methods
* on this ConfigurableJtaPlatform class itself.
*/
public Object getJtaPlatformProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] {jtaPlatformClass}, this);
}
}
/*
* Copyright 2002-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.HibernateException;
import org.hibernate.Session;
/**
* Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
* execution methods, often as anonymous classes within a method implementation.
* A typical implementation will call {@code Session.load/find/update} to perform
* some operations on persistent objects.
*
* @author Juergen Hoeller
* @since 4.0.1
* @see HibernateTemplate
* @see HibernateTransactionManager
*/
public interface HibernateCallback<T> {
/**
* Gets called by {@code HibernateTemplate.execute} with an active
* Hibernate {@code Session}. Does not need to care about activating
* or closing the {@code Session}, or handling transactions.
* <p>Allows for returning a result object created within the callback,
* i.e. a domain object or a collection of domain objects.
* A thrown custom RuntimeException is treated as an application exception:
* It gets propagated to the caller of the template.
* @param session active Hibernate session
* @return a result object, or {@code null} if none
* @throws HibernateException if thrown by the Hibernate API
* @see HibernateTemplate#execute
*/
T doInHibernate(Session session) throws HibernateException;
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.HibernateException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
/**
* {@link PersistenceExceptionTranslator} capable of translating {@link HibernateException}
* instances to Spring's {@link DataAccessException} hierarchy.
*
* <p>Extended by {@link LocalSessionFactoryBean}, so there is no need to declare this
* translator in addition to a {@code LocalSessionFactoryBean}.
*
* <p>When configuring the container with {@code @Configuration} classes, a {@code @Bean}
* of this type must be registered manually.
*
* @author Juergen Hoeller
* @since 3.1
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
* @see SessionFactoryUtils#convertHibernateAccessException(HibernateException)
*/
public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
if (ex instanceof HibernateException) {
return convertHibernateAccessException((HibernateException) ex);
}
return null;
}
/**
* Convert the given HibernateException to an appropriate exception from the
* {@code org.springframework.dao} hierarchy.
* @param ex HibernateException that occured
* @return a corresponding DataAccessException
* @see SessionFactoryUtils#convertHibernateAccessException
*/
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
return SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import java.sql.SQLException;
import org.hibernate.JDBCException;
import org.springframework.dao.UncategorizedDataAccessException;
/**
* Hibernate-specific subclass of UncategorizedDataAccessException,
* for JDBC exceptions that Hibernate wrapped.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
@SuppressWarnings("serial")
public class HibernateJdbcException extends UncategorizedDataAccessException {
public HibernateJdbcException(JDBCException ex) {
super("JDBC exception on Hibernate data access: SQLException for SQL [" + ex.getSQL() + "]; SQL state [" +
ex.getSQLState() + "]; error code [" + ex.getErrorCode() + "]; " + ex.getMessage(), ex);
}
/**
* Return the underlying SQLException.
*/
public SQLException getSQLException() {
return ((JDBCException) getCause()).getSQLException();
}
/**
* Return the SQL that led to the problem.
*/
public String getSql() {
return ((JDBCException) getCause()).getSQL();
}
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.springframework.orm.ObjectRetrievalFailureException;
/**
* Hibernate-specific subclass of ObjectRetrievalFailureException.
* Converts Hibernate's UnresolvableObjectException and WrongClassException.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
@SuppressWarnings("serial")
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
}
public HibernateObjectRetrievalFailureException(WrongClassException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
}
}
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
/**
* Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
* Converts Hibernate's StaleObjectStateException, StaleStateException
* and OptimisticEntityLockException.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
@SuppressWarnings("serial")
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex);
}
public HibernateOptimisticLockingFailureException(StaleStateException ex) {
super(ex.getMessage(), ex);
}
public HibernateOptimisticLockingFailureException(OptimisticEntityLockException ex) {
super(ex.getMessage(), ex);
}
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.QueryException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Hibernate-specific subclass of InvalidDataAccessResourceUsageException,
* thrown on invalid HQL query syntax.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
@SuppressWarnings("serial")
public class HibernateQueryException extends InvalidDataAccessResourceUsageException {
public HibernateQueryException(QueryException ex) {
super(ex.getMessage(), ex);
}
/**
* Return the HQL query string that was invalid.
*/
public String getQueryString() {
return ((QueryException) getCause()).getQueryString();
}
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.HibernateException;
import org.springframework.dao.UncategorizedDataAccessException;
/**
* Hibernate-specific subclass of UncategorizedDataAccessException,
* for Hibernate system errors that do not match any concrete
* {@code org.springframework.dao} exceptions.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
@SuppressWarnings("serial")
public class HibernateSystemException extends UncategorizedDataAccessException {
/**
* Create a new HibernateSystemException,
* wrapping an arbitrary HibernateException.
* @param cause the HibernateException thrown
*/
public HibernateSystemException(HibernateException cause) {
super(cause != null ? cause.getMessage() : null, cause);
}
}
/*
* Copyright 2002-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.Interceptor;
import org.hibernate.SessionFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.filter.TypeFilter;
/**
* {@link org.springframework.beans.factory.FactoryBean} that creates a Hibernate
* {@link org.hibernate.SessionFactory}. This is the usual way to set up a shared
* Hibernate SessionFactory in a Spring application context; the SessionFactory can
* then be passed to Hibernate-based data access objects via dependency injection.
*
* <p><b>This variant of LocalSessionFactoryBean requires Hibernate 4.0 or higher.</b>
* As of Spring 4.0, it is compatible with (the quite refactored) Hibernate 4.3 as well.
* We recommend using the latest Hibernate 4.2.x or 4.3.x version, depending on whether
* you need to remain JPA 2.0 compatible at runtime (Hibernate 4.2) or can upgrade to
* JPA 2.1 (Hibernate 4.3).
*
* <p>This class is similar in role to the same-named class in the {@code orm.hibernate3}
* package. However, in practice, it is closer to {@code AnnotationSessionFactoryBean}
* since its core purpose is to bootstrap a {@code SessionFactory} from package scanning.
*
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
* sure to either specify the {@link #setJtaTransactionManager "jtaTransactionManager"}
* bean property or to set the "hibernate.transaction.factory_class" property to
* {@link org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory}.
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
*
* @author Juergen Hoeller
* @since 3.1
* @see #setDataSource
* @see #setPackagesToScan
* @see LocalSessionFactoryBuilder
*/
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
implements FactoryBean<SessionFactory>, ResourceLoaderAware, InitializingBean, DisposableBean {
private DataSource dataSource;
private Resource[] configLocations;
private String[] mappingResources;
private Resource[] mappingLocations;
private Resource[] cacheableMappingLocations;
private Resource[] mappingJarLocations;
private Resource[] mappingDirectoryLocations;
private Interceptor entityInterceptor;
@SuppressWarnings("deprecation")
private org.hibernate.cfg.NamingStrategy namingStrategy;
private Object jtaTransactionManager;
private Object multiTenantConnectionProvider;
private Object currentTenantIdentifierResolver;
private RegionFactory cacheRegionFactory;
private TypeFilter[] entityTypeFilters;
private Properties hibernateProperties;
private Class<?>[] annotatedClasses;
private String[] annotatedPackages;
private String[] packagesToScan;
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private Configuration configuration;
private SessionFactory sessionFactory;
/**
* Set the DataSource to be used by the SessionFactory.
* If set, this will override corresponding settings in Hibernate properties.
* <p>If this is set, the Hibernate settings should not define
* a connection provider to avoid meaningless double configuration.
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Set the location of a single Hibernate XML config file, for example as
* classpath resource "classpath:hibernate.cfg.xml".
* <p>Note: Can be omitted when all necessary properties and mapping
* resources are specified locally via this bean.
* @see org.hibernate.cfg.Configuration#configure(java.net.URL)
*/
public void setConfigLocation(Resource configLocation) {
this.configLocations = new Resource[] {configLocation};
}
/**
* Set the locations of multiple Hibernate XML config files, for example as
* classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
* <p>Note: Can be omitted when all necessary properties and mapping
* resources are specified locally via this bean.
* @see org.hibernate.cfg.Configuration#configure(java.net.URL)
*/
public void setConfigLocations(Resource... configLocations) {
this.configLocations = configLocations;
}
/**
* Set Hibernate mapping resources to be found in the class path,
* like "example.hbm.xml" or "mypackage/example.hbm.xml".
* Analogous to mapping entries in a Hibernate XML config file.
* Alternative to the more generic setMappingLocations method.
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see #setMappingLocations
* @see org.hibernate.cfg.Configuration#addResource
*/
public void setMappingResources(String... mappingResources) {
this.mappingResources = mappingResources;
}
/**
* Set locations of Hibernate mapping files, for example as classpath
* resource "classpath:example.hbm.xml". Supports any resource location
* via Spring's resource abstraction, for example relative paths like
* "WEB-INF/mappings/example.hbm.xml" when running in an application context.
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see org.hibernate.cfg.Configuration#addInputStream
*/
public void setMappingLocations(Resource... mappingLocations) {
this.mappingLocations = mappingLocations;
}
/**
* Set locations of cacheable Hibernate mapping files, for example as web app
* resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
* via Spring's resource abstraction, as long as the resource can be resolved
* in the file system.
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File)
*/
public void setCacheableMappingLocations(Resource... cacheableMappingLocations) {
this.cacheableMappingLocations = cacheableMappingLocations;
}
/**
* Set locations of jar files that contain Hibernate mapping resources,
* like "WEB-INF/lib/example.hbm.jar".
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see org.hibernate.cfg.Configuration#addJar(java.io.File)
*/
public void setMappingJarLocations(Resource... mappingJarLocations) {
this.mappingJarLocations = mappingJarLocations;
}
/**
* Set locations of directories that contain Hibernate mapping resources,
* like "WEB-INF/mappings".
* <p>Can be used to add to mappings from a Hibernate XML config file,
* or to specify all mappings locally.
* @see org.hibernate.cfg.Configuration#addDirectory(java.io.File)
*/
public void setMappingDirectoryLocations(Resource... mappingDirectoryLocations) {
this.mappingDirectoryLocations = mappingDirectoryLocations;
}
/**
* Set a Hibernate entity interceptor that allows to inspect and change
* property values before writing to and reading from the database.
* Will get applied to any new Session created by this factory.
* @see org.hibernate.cfg.Configuration#setInterceptor
*/
public void setEntityInterceptor(Interceptor entityInterceptor) {
this.entityInterceptor = entityInterceptor;
}
/**
* Set a Hibernate NamingStrategy for the SessionFactory, determining the
* physical column and table names given the info in the mapping document.
* @see org.hibernate.cfg.Configuration#setNamingStrategy
*/
@SuppressWarnings("deprecation")
public void setNamingStrategy(org.hibernate.cfg.NamingStrategy namingStrategy) {
this.namingStrategy = namingStrategy;
}
/**
* Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
* or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
* if any. Implicitly sets up {@code JtaPlatform} and {@code CMTTransactionStrategy}.
* @see LocalSessionFactoryBuilder#setJtaTransactionManager
*/
public void setJtaTransactionManager(Object jtaTransactionManager) {
this.jtaTransactionManager = jtaTransactionManager;
}
/**
* Set a Hibernate 4.1/4.2/4.3 {@code MultiTenantConnectionProvider} to be passed
* on to the SessionFactory: as an instance, a Class, or a String class name.
* <p>Note that the package location of the {@code MultiTenantConnectionProvider}
* interface changed between Hibernate 4.2 and 4.3. This method accepts both variants.
* @since 4.0
* @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider
*/
public void setMultiTenantConnectionProvider(Object multiTenantConnectionProvider) {
this.multiTenantConnectionProvider = multiTenantConnectionProvider;
}
/**
* Set a Hibernate 4.1/4.2/4.3 {@code CurrentTenantIdentifierResolver} to be passed
* on to the SessionFactory: as an instance, a Class, or a String class name.
* @since 4.0
* @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver
*/
public void setCurrentTenantIdentifierResolver(Object currentTenantIdentifierResolver) {
this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
}
/**
* Set the Hibernate RegionFactory to use for the SessionFactory.
* Allows for using a Spring-managed RegionFactory instance.
* <p>Note: If this is set, the Hibernate settings should not define a
* cache provider to avoid meaningless double configuration.
* @since 4.0
* @see org.hibernate.cache.spi.RegionFactory
* @see LocalSessionFactoryBuilder#setCacheRegionFactory
*/
public void setCacheRegionFactory(RegionFactory cacheRegionFactory) {
this.cacheRegionFactory = cacheRegionFactory;
}
/**
* Specify custom type filters for Spring-based scanning for entity classes.
* <p>Default is to search all specified packages for classes annotated with
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
* or {@code @javax.persistence.MappedSuperclass}.
* @since 4.1
* @see #setPackagesToScan
*/
public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
this.entityTypeFilters = entityTypeFilters;
}
/**
* Set Hibernate properties, such as "hibernate.dialect".
* <p>Note: Do not specify a transaction provider here when using
* Spring-driven transactions. It is also advisable to omit connection
* provider settings and use a Spring-set DataSource instead.
* @see #setDataSource
*/
public void setHibernateProperties(Properties hibernateProperties) {
this.hibernateProperties = hibernateProperties;
}
/**
* Return the Hibernate properties, if any. Mainly available for
* configuration through property paths that specify individual keys.
*/
public Properties getHibernateProperties() {
if (this.hibernateProperties == null) {
this.hibernateProperties = new Properties();
}
return this.hibernateProperties;
}
/**
* Specify annotated entity classes to register with this Hibernate SessionFactory.
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
*/
public void setAnnotatedClasses(Class<?>... annotatedClasses) {
this.annotatedClasses = annotatedClasses;
}
/**
* Specify the names of annotated packages, for which package-level
* annotation metadata will be read.
* @see org.hibernate.cfg.Configuration#addPackage(String)
*/
public void setAnnotatedPackages(String... annotatedPackages) {
this.annotatedPackages = annotatedPackages;
}
/**
* Specify packages to search for autodetection of your entity classes in the
* classpath. This is analogous to Spring's component-scan feature
* ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
*/
public void setPackagesToScan(String... packagesToScan) {
this.packagesToScan = packagesToScan;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
@Override
public void afterPropertiesSet() throws IOException {
LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver);
if (this.configLocations != null) {
for (Resource resource : this.configLocations) {
// Load Hibernate configuration from given location.
sfb.configure(resource.getURL());
}
}
if (this.mappingResources != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (String mapping : this.mappingResources) {
Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader());
sfb.addInputStream(mr.getInputStream());
}
}
if (this.mappingLocations != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (Resource resource : this.mappingLocations) {
sfb.addInputStream(resource.getInputStream());
}
}
if (this.cacheableMappingLocations != null) {
// Register given cacheable Hibernate mapping definitions, read from the file system.
for (Resource resource : this.cacheableMappingLocations) {
sfb.addCacheableFile(resource.getFile());
}
}
if (this.mappingJarLocations != null) {
// Register given Hibernate mapping definitions, contained in jar files.
for (Resource resource : this.mappingJarLocations) {
sfb.addJar(resource.getFile());
}
}
if (this.mappingDirectoryLocations != null) {
// Register all Hibernate mapping definitions in the given directories.
for (Resource resource : this.mappingDirectoryLocations) {
File file = resource.getFile();
if (!file.isDirectory()) {
throw new IllegalArgumentException(
"Mapping directory location [" + resource + "] does not denote a directory");
}
sfb.addDirectory(file);
}
}
if (this.entityInterceptor != null) {
sfb.setInterceptor(this.entityInterceptor);
}
if (this.namingStrategy != null) {
sfb.setNamingStrategy(this.namingStrategy);
}
if (this.jtaTransactionManager != null) {
sfb.setJtaTransactionManager(this.jtaTransactionManager);
}
if (this.multiTenantConnectionProvider != null) {
sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider);
}
if (this.currentTenantIdentifierResolver != null) {
sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver);
}
if (this.cacheRegionFactory != null) {
sfb.setCacheRegionFactory(this.cacheRegionFactory);
}
if (this.entityTypeFilters != null) {
sfb.setEntityTypeFilters(this.entityTypeFilters);
}
if (this.hibernateProperties != null) {
sfb.addProperties(this.hibernateProperties);
}
if (this.annotatedClasses != null) {
sfb.addAnnotatedClasses(this.annotatedClasses);
}
if (this.annotatedPackages != null) {
sfb.addPackages(this.annotatedPackages);
}
if (this.packagesToScan != null) {
sfb.scanPackages(this.packagesToScan);
}
// Build SessionFactory instance.
this.configuration = sfb;
this.sessionFactory = buildSessionFactory(sfb);
}
/**
* Subclasses can override this method to perform custom initialization
* of the SessionFactory instance, creating it via the given Configuration
* object that got prepared by this LocalSessionFactoryBean.
* <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
* A custom implementation could prepare the instance in a specific way (e.g. applying
* a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
* @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
* @return the SessionFactory instance
* @see LocalSessionFactoryBuilder#buildSessionFactory
*/
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
return sfb.buildSessionFactory();
}
/**
* Return the Hibernate Configuration object used to build the SessionFactory.
* Allows for access to configuration metadata stored there (rarely needed).
* @throws IllegalStateException if the Configuration object has not been initialized yet
*/
public final Configuration getConfiguration() {
if (this.configuration == null) {
throw new IllegalStateException("Configuration not initialized yet");
}
return this.configuration;
}
@Override
public SessionFactory getObject() {
return this.sessionFactory;
}
@Override
public Class<?> getObjectType() {
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void destroy() {
this.sessionFactory.close();
}
}
/*
* Copyright 2002-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import javax.persistence.AttributeConverter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Settings;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.hibernate.service.ServiceRegistry;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A Spring-provided extension of the standard Hibernate {@link Configuration} class,
* adding {@link SpringSessionContext} as a default and providing convenient ways
* to specify a DataSource and an application class loader.
*
* <p>This is designed for programmatic use, e.g. in {@code @Bean} factory methods.
* Consider using {@link LocalSessionFactoryBean} for XML bean definition files.
*
* <p><b>Requires Hibernate 4.0 or higher.</b> As of Spring 4.0, it is compatible with
* (the quite refactored) Hibernate 4.3 as well. We recommend using the latest
* Hibernate 4.2.x or 4.3.x version, depending on whether you need to remain JPA 2.0
* compatible at runtime (Hibernate 4.2) or can upgrade to JPA 2.1 (Hibernate 4.3).
*
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
* sure to either use the {@link #setJtaTransactionManager} method or to set the
* "hibernate.transaction.factory_class" property to {@link CMTTransactionFactory}.
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
*
* @author Juergen Hoeller
* @since 3.1
* @see LocalSessionFactoryBean
*/
@SuppressWarnings("serial")
public class LocalSessionFactoryBuilder extends Configuration {
private static final String RESOURCE_PATTERN = "/**/*.class";
private static final String PACKAGE_INFO_SUFFIX = ".package-info";
private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {
new AnnotationTypeFilter(Entity.class, false),
new AnnotationTypeFilter(Embeddable.class, false),
new AnnotationTypeFilter(MappedSuperclass.class, false)};
private static TypeFilter converterTypeFilter;
static {
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>)
ClassUtils.forName("javax.persistence.Converter", LocalSessionFactoryBuilder.class.getClassLoader());
converterTypeFilter = new AnnotationTypeFilter(converterAnnotation, false);
}
catch (ClassNotFoundException ex) {
// JPA 2.1 API not available - Hibernate <4.3
}
}
private final ResourcePatternResolver resourcePatternResolver;
private RegionFactory cacheRegionFactory;
private TypeFilter[] entityTypeFilters = DEFAULT_ENTITY_TYPE_FILTERS;
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
*/
public LocalSessionFactoryBuilder(DataSource dataSource) {
this(dataSource, new PathMatchingResourcePatternResolver());
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
* @param classLoader the ClassLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
* @param resourceLoader the ResourceLoader to load application classes from
*/
@SuppressWarnings("deprecation") // to be able to build against Hibernate 4.3
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
if (dataSource != null) {
getProperties().put(Environment.DATASOURCE, dataSource);
}
// APP_CLASSLOADER is deprecated as of Hibernate 4.3 but we need to remain compatible with 4.0+
getProperties().put(AvailableSettings.APP_CLASSLOADER, resourceLoader.getClassLoader());
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
/**
* Set the Spring {@link JtaTransactionManager} or the JTA {@link TransactionManager}
* to be used with Hibernate, if any. Allows for using a Spring-managed transaction
* manager for Hibernate 4's session and cache synchronization, with the
* "hibernate.transaction.jta.platform" automatically set to it. Also sets
* "hibernate.transaction.factory_class" to {@link CMTTransactionFactory},
* instructing Hibernate to interact with externally managed transactions.
* <p>A passed-in Spring {@link JtaTransactionManager} needs to contain a JTA
* {@link TransactionManager} reference to be usable here, except for the WebSphere
* case where we'll automatically set {@code WebSphereExtendedJtaPlatform} accordingly.
* <p>Note: If this is set, the Hibernate settings should not contain a JTA platform
* setting to avoid meaningless double configuration.
*/
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
if (jtaTransactionManager instanceof JtaTransactionManager) {
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
if (webspherePresent) {
getProperties().put(AvailableSettings.JTA_PLATFORM,
ConfigurableJtaPlatform.getJtaPlatformBasePackage() + "internal.WebSphereExtendedJtaPlatform");
}
else {
JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
if (jtaTm.getTransactionManager() == null) {
throw new IllegalArgumentException(
"Can only apply JtaTransactionManager which has a TransactionManager reference set");
}
getProperties().put(AvailableSettings.JTA_PLATFORM,
new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction(),
jtaTm.getTransactionSynchronizationRegistry()).getJtaPlatformProxy());
}
}
else if (jtaTransactionManager instanceof TransactionManager) {
getProperties().put(AvailableSettings.JTA_PLATFORM,
new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null, null).getJtaPlatformProxy());
}
else {
throw new IllegalArgumentException(
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
}
getProperties().put(AvailableSettings.TRANSACTION_STRATEGY, new CMTTransactionFactory());
return this;
}
/**
* Set a Hibernate 4.1/4.2/4.3 {@code MultiTenantConnectionProvider} to be passed
* on to the SessionFactory: as an instance, a Class, or a String class name.
* <p>Note that the package location of the {@code MultiTenantConnectionProvider}
* interface changed between Hibernate 4.2 and 4.3. This method accepts both variants.
* @since 4.0
* @see AvailableSettings#MULTI_TENANT_CONNECTION_PROVIDER
*/
public LocalSessionFactoryBuilder setMultiTenantConnectionProvider(Object multiTenantConnectionProvider) {
getProperties().put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
return this;
}
/**
* Set a Hibernate 4.1/4.2/4.3 {@code CurrentTenantIdentifierResolver} to be passed
* on to the SessionFactory: as an instance, a Class, or a String class name.
* @since 4.0
* @see AvailableSettings#MULTI_TENANT_IDENTIFIER_RESOLVER
*/
public LocalSessionFactoryBuilder setCurrentTenantIdentifierResolver(Object currentTenantIdentifierResolver) {
getProperties().put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
return this;
}
/**
* Set the Hibernate RegionFactory to use for the SessionFactory.
* Allows for using a Spring-managed RegionFactory instance.
* <p>Note: If this is set, the Hibernate settings should not define a
* cache provider to avoid meaningless double configuration.
* @since 4.0
* @see org.hibernate.cache.spi.RegionFactory
*/
public LocalSessionFactoryBuilder setCacheRegionFactory(RegionFactory cacheRegionFactory) {
this.cacheRegionFactory = cacheRegionFactory;
return this;
}
/**
* Specify custom type filters for Spring-based scanning for entity classes.
* <p>Default is to search all specified packages for classes annotated with
* {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
* or {@code @javax.persistence.MappedSuperclass}.
* @since 4.1
* @see #scanPackages
*/
public LocalSessionFactoryBuilder setEntityTypeFilters(TypeFilter... entityTypeFilters) {
this.entityTypeFilters = entityTypeFilters;
return this;
}
/**
* Add the given annotated classes in a batch.
* @see #addAnnotatedClass
* @see #scanPackages
*/
public LocalSessionFactoryBuilder addAnnotatedClasses(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
addAnnotatedClass(annotatedClass);
}
return this;
}
/**
* Add the given annotated packages in a batch.
* @see #addPackage
* @see #scanPackages
*/
public LocalSessionFactoryBuilder addPackages(String... annotatedPackages) {
for (String annotatedPackage : annotatedPackages) {
addPackage(annotatedPackage);
}
return this;
}
/**
* Perform Spring-based scanning for entity classes, registering them
* as annotated classes with this {@code Configuration}.
* @param packagesToScan one or more Java package names
* @throws HibernateException if scanning fails for any reason
*/
public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException {
Set<String> entityClassNames = new TreeSet<String>();
Set<String> converterClassNames = new TreeSet<String>();
Set<String> packageNames = new TreeSet<String>();
try {
for (String pkg : packagesToScan) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
if (matchesEntityTypeFilter(reader, readerFactory)) {
entityClassNames.add(className);
}
else if (converterTypeFilter != null && converterTypeFilter.match(reader, readerFactory)) {
converterClassNames.add(className);
}
else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
}
}
}
}
}
catch (IOException ex) {
throw new MappingException("Failed to scan classpath for unlisted classes", ex);
}
try {
ClassLoader cl = this.resourcePatternResolver.getClassLoader();
for (String className : entityClassNames) {
addAnnotatedClass(cl.loadClass(className));
}
for (String className : converterClassNames) {
ConverterRegistrationDelegate.registerConverter(this, cl.loadClass(className));
}
for (String packageName : packageNames) {
addPackage(packageName);
}
}
catch (ClassNotFoundException ex) {
throw new MappingException("Failed to load annotated classes from classpath", ex);
}
return this;
}
/**
* Check whether any of the configured entity type filters matches
* the current class descriptor contained in the metadata reader.
*/
private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
if (this.entityTypeFilters != null) {
for (TypeFilter filter : this.entityTypeFilters) {
if (filter.match(reader, readerFactory)) {
return true;
}
}
}
return false;
}
// Overridden methods from Hibernate's Configuration class
@Override
public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
Settings settings = super.buildSettings(props, serviceRegistry);
if (this.cacheRegionFactory != null) {
try {
Method setRegionFactory = Settings.class.getDeclaredMethod("setRegionFactory", RegionFactory.class);
setRegionFactory.setAccessible(true);
setRegionFactory.invoke(settings, this.cacheRegionFactory);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to invoke Hibernate's setRegionFactory method", ex);
}
}
return settings;
}
/**
* Build the {@code SessionFactory}.
*/
@Override
@SuppressWarnings("deprecation")
public SessionFactory buildSessionFactory() throws HibernateException {
ClassLoader appClassLoader = (ClassLoader) getProperties().get(AvailableSettings.APP_CLASSLOADER);
Thread currentThread = Thread.currentThread();
ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
boolean overrideClassLoader =
(appClassLoader != null && !appClassLoader.equals(threadContextClassLoader));
if (overrideClassLoader) {
currentThread.setContextClassLoader(appClassLoader);
}
try {
return super.buildSessionFactory();
}
finally {
if (overrideClassLoader) {
currentThread.setContextClassLoader(threadContextClassLoader);
}
}
}
/**
* Inner class to avoid hard dependency on JPA 2.1 / Hibernate 4.3.
*/
private static class ConverterRegistrationDelegate {
@SuppressWarnings("unchecked")
public static void registerConverter(Configuration config, Class<?> converterClass) {
config.addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) converterClass);
}
}
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
* HibernateTransactionManager binds instances of this class to the thread,
* for a given SessionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Juergen Hoeller
* @since 3.1
* @see HibernateTransactionManager
* @see SessionFactoryUtils
*/
public class SessionHolder extends ResourceHolderSupport {
private Session session;
private Transaction transaction;
private FlushMode previousFlushMode;
public SessionHolder(Session session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
public Session getSession() {
return this.session;
}
public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}
public Transaction getTransaction() {
return this.transaction;
}
public void setPreviousFlushMode(FlushMode previousFlushMode) {
this.previousFlushMode = previousFlushMode;
}
public FlushMode getPreviousFlushMode() {
return this.previousFlushMode;
}
@Override
public void clear() {
super.clear();
this.transaction = null;
this.previousFlushMode = null;
}
}
/*
* Copyright 2002-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
/**
* Simple synchronization adapter that propagates a {@code flush()} call
* to the underlying Hibernate Session. Used in combination with JTA.
*
* @author Juergen Hoeller
* @since 3.1
*/
public class SpringFlushSynchronization extends TransactionSynchronizationAdapter {
private final Session session;
public SpringFlushSynchronization(Session session) {
this.session = session;
}
@Override
public void flush() {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
this.session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
@Override
public boolean equals(Object obj) {
return (obj instanceof SpringFlushSynchronization &&
this.session == ((SpringFlushSynchronization) obj).session);
}
@Override
public int hashCode() {
return this.session.hashCode();
}
}
/*
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.orm.hibernate4;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.internal.JTASessionContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Spring-specific subclass of Hibernate's JTASessionContext,
* setting {@code FlushMode.MANUAL} for read-only transactions.
*
* @author Juergen Hoeller
* @since 3.1
*/
@SuppressWarnings("serial")
public class SpringJtaSessionContext extends JTASessionContext {
public SpringJtaSessionContext(SessionFactoryImplementor factory) {
super(factory);
}
@Override
protected Session buildOrObtainSession() {
Session session = super.buildOrObtainSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
return session;
}
}
/**
* Classes supporting the {@code org.springframework.orm.hibernate4} package.
*/
package org.springframework.orm.hibernate4.support;
/**
* Support package for the Hibernate 3 Annotation add-on,
* which supports JPA-compliant Java 5+ annotations for mappings.
*/
package org.springframework.orm.hibernate3.annotation;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册