From 7fcb277de962a054916e6a1bafc57b101b815d5b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 18 Feb 2016 16:19:09 +0100 Subject: [PATCH] Consistent behavior for unwrap(null) on JPA and Bean Validation wrappers Includes a fix for Query unwrapping before passing it to addNamedQuery. Issue: SPR-13960 Issue: SPR-13957 --- .../SpringValidatorAdapter.java | 13 +++++----- .../jpa/AbstractEntityManagerFactoryBean.java | 26 +++++++++++++++++-- .../orm/jpa/ExtendedEntityManagerCreator.java | 7 +++-- .../orm/jpa/SharedEntityManagerCreator.java | 11 ++++++-- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java index 060d2214eb..9934c10423 100644 --- a/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java +++ b/spring-context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java @@ -253,13 +253,13 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. @Override public Set> validate(T object, Class... groups) { - Assert.notNull(this.targetValidator, "No target Validator set"); + Assert.state(this.targetValidator != null, "No target Validator set"); return this.targetValidator.validate(object, groups); } @Override public Set> validateProperty(T object, String propertyName, Class... groups) { - Assert.notNull(this.targetValidator, "No target Validator set"); + Assert.state(this.targetValidator != null, "No target Validator set"); return this.targetValidator.validateProperty(object, propertyName, groups); } @@ -267,20 +267,21 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation. public Set> validateValue( Class beanType, String propertyName, Object value, Class... groups) { - Assert.notNull(this.targetValidator, "No target Validator set"); + Assert.state(this.targetValidator != null, "No target Validator set"); return this.targetValidator.validateValue(beanType, propertyName, value, groups); } @Override public BeanDescriptor getConstraintsForClass(Class clazz) { - Assert.notNull(this.targetValidator, "No target Validator set"); + Assert.state(this.targetValidator != null, "No target Validator set"); return this.targetValidator.getConstraintsForClass(clazz); } @Override + @SuppressWarnings("unchecked") public T unwrap(Class type) { - Assert.notNull(this.targetValidator, "No target Validator set"); - return this.targetValidator.unwrap(type); + Assert.state(this.targetValidator != null, "No target Validator set"); + return (type != null ? this.targetValidator.unwrap(type) : (T) this.targetValidator); } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java index a1cb684466..f4401ae298 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java @@ -1,5 +1,5 @@ /* - * 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. @@ -36,6 +36,7 @@ import java.util.concurrent.Future; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceException; +import javax.persistence.Query; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; import javax.sql.DataSource; @@ -439,6 +440,24 @@ public abstract class AbstractEntityManagerFactoryBean implements return ExtendedEntityManagerCreator.createApplicationManagedEntityManager(rawEntityManager, this, true); } + // Look for Query arguments, primarily JPA 2.1's addNamedQuery(String, Query) + if (args != null) { + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (arg instanceof Query && Proxy.isProxyClass(arg.getClass())) { + // Assumably a Spring-generated proxy from SharedEntityManagerCreator: + // since we're passing it back to the native EntityManagerFactory, + // let's unwrap it to the original Query object from the provider. + try { + args[i] = ((Query) arg).unwrap(null); + } + catch (RuntimeException ex) { + // Ignore - simply proceed with given Query object then + } + } + } + } + // Standard delegation to the native factory, just post-processing EntityManager return values Object retVal = method.invoke(getNativeEntityManagerFactory(), args); if (retVal instanceof EntityManager) { @@ -604,7 +623,10 @@ public abstract class AbstractEntityManagerFactoryBean implements else if (method.getName().equals("unwrap")) { // Handle JPA 2.1 unwrap method - could be a proxy match. Class targetClass = (Class) args[0]; - if (targetClass == null || targetClass.isInstance(proxy)) { + if (targetClass == null) { + return this.entityManagerFactoryBean.getNativeEntityManagerFactory(); + } + else if (targetClass.isInstance(proxy)) { return proxy; } } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java index 1faa723508..1575a7d2f0 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 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. @@ -296,7 +296,10 @@ public abstract class ExtendedEntityManagerCreator { else if (method.getName().equals("unwrap")) { // Handle JPA 2.0 unwrap method - could be a proxy match. Class targetClass = (Class) args[0]; - if (targetClass == null || targetClass.isInstance(proxy)) { + if (targetClass == null) { + return this.target; + } + else if (targetClass.isInstance(proxy)) { return proxy; } } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java index da262d026c..a3bac0ce61 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java @@ -232,7 +232,7 @@ public abstract class SharedEntityManagerCreator { else if (method.getName().equals("unwrap")) { // JPA 2.0: handle unwrap method - could be a proxy match. Class targetClass = (Class) args[0]; - if (targetClass == null || targetClass.isInstance(proxy)) { + if (targetClass != null && targetClass.isInstance(proxy)) { return proxy; } } @@ -263,6 +263,10 @@ public abstract class SharedEntityManagerCreator { return target; } else if (method.getName().equals("unwrap")) { + Class targetClass = (Class) args[0]; + if (targetClass == null) { + return (target != null ? target : proxy); + } // We need a transactional target now. if (target == null) { throw new IllegalStateException("No transactional EntityManager available"); @@ -355,7 +359,10 @@ public abstract class SharedEntityManagerCreator { else if (method.getName().equals("unwrap")) { // Handle JPA 2.0 unwrap method - could be a proxy match. Class targetClass = (Class) args[0]; - if (targetClass == null || targetClass.isInstance(proxy)) { + if (targetClass == null) { + return this.target; + } + else if (targetClass.isInstance(proxy)) { return proxy; } }