From 17caac8f1fd53f54270e799a6c754dac9f3a6e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 5 Feb 2019 15:39:46 +0100 Subject: [PATCH 1/4] Add tests for SpringBeanContainer (Hibernate ORM integration) and fix the behavior when requesting named beans (#22260) * Add integration tests for SpringBeanContainer (Hibernate ORM integration) * Autowire bean properties of beans retrieved by name in SpringBeanContainer * Add integration tests for fallback cases in SpringBeanContainer (Hibernate ORM integration) * Fix SpringBeanContainer incorrectly losing the bean name when calling the fallback producer (cherry picked from commit 00855c4f5f4e0f028212268a98a23b3009c3f7d4) --- .../orm/hibernate5/SpringBeanContainer.java | 7 +- ...rySpringBeanContainerIntegrationTests.java | 344 ++++++++++++++++++ .../orm/jpa/hibernate/beans/BeanSource.java | 22 ++ ...iplePrototypesInSpringContextTestBean.java | 20 + .../NoDefinitionInSpringContextTestBean.java | 37 ++ ...inglePrototypeInSpringContextTestBean.java | 20 + .../orm/jpa/hibernate/beans/TestBean.java | 49 +++ ...-hibernate-spring-bean-container-tests.xml | 23 ++ 8 files changed, 517 insertions(+), 5 deletions(-) create mode 100644 spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests.java create mode 100644 spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/BeanSource.java create mode 100644 spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/MultiplePrototypesInSpringContextTestBean.java create mode 100644 spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/NoDefinitionInSpringContextTestBean.java create mode 100644 spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/SinglePrototypeInSpringContextTestBean.java create mode 100644 spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/TestBean.java create mode 100644 spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/inject-hibernate-spring-bean-container-tests.xml diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringBeanContainer.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringBeanContainer.java index 9280d38230..bba1c889ec 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringBeanContainer.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringBeanContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -116,10 +116,6 @@ public final class SpringBeanContainer implements BeanContainer { public ContainedBean getBean( String name, Class beanType, LifecycleOptions lifecycleOptions, BeanInstanceProducer fallbackProducer) { - if (!this.beanFactory.containsBean(name)) { - return getBean(beanType, lifecycleOptions, fallbackProducer); - } - SpringContainedBean bean; if (lifecycleOptions.canUseCachedReferences()) { bean = this.beanCache.get(name); @@ -169,6 +165,7 @@ public final class SpringBeanContainer implements BeanContainer { try { if (lifecycleOptions.useJpaCompliantCreation()) { Object bean = this.beanFactory.autowire(beanType, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); + this.beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false); this.beanFactory.applyBeanPropertyValues(bean, name); bean = this.beanFactory.initializeBean(bean, name); return new SpringContainedBean<>(bean, beanInstance -> this.beanFactory.destroyBean(name, beanInstance)); diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests.java new file mode 100644 index 0000000000..048da832a1 --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests.java @@ -0,0 +1,344 @@ +/* + * Copyright 2002-2019 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.jpa.hibernate; + +import org.hibernate.SessionFactory; +import org.hibernate.resource.beans.container.spi.BeanContainer; +import org.hibernate.resource.beans.container.spi.ContainedBean; +import org.hibernate.resource.beans.spi.BeanInstanceProducer; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; +import org.hibernate.service.ServiceRegistry; + +import org.junit.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.orm.jpa.AbstractEntityManagerFactoryIntegrationTests; +import org.springframework.orm.jpa.hibernate.beans.*; + +import static org.junit.Assert.*; + +/** + * Hibernate-specific SpringBeanContainer integration tests. + * + * @author Yoann Rodiere + */ +public class HibernateNativeEntityManagerFactorySpringBeanContainerIntegrationTests + extends AbstractEntityManagerFactoryIntegrationTests { + + @Autowired + private ApplicationContext applicationContext; + + @Override + protected String[] getConfigLocations() { + return new String[] {"/org/springframework/orm/jpa/hibernate/hibernate-manager-native.xml", + "/org/springframework/orm/jpa/memdb.xml", "/org/springframework/orm/jpa/inject.xml", + "/org/springframework/orm/jpa/hibernate/inject-hibernate-spring-bean-container-tests.xml"}; + } + + private ManagedBeanRegistry getManagedBeanRegistry() { + SessionFactory sessionFactory = entityManagerFactory.unwrap( SessionFactory.class ); + ServiceRegistry serviceRegistry = sessionFactory.getSessionFactoryOptions().getServiceRegistry(); + return serviceRegistry.requireService( ManagedBeanRegistry.class ); + } + + private BeanContainer getBeanContainer() { + return getManagedBeanRegistry().getBeanContainer(); + } + + + @Test + public void testCanRetrieveBeanByTypeWithJpaCompliantOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + + ContainedBean bean = beanContainer.getBean( + SinglePrototypeInSpringContextTestBean.class, + JpaLifecycleOptions.INSTANCE, + IneffectiveBeanInstanceProducer.INSTANCE + ); + + assertNotNull(bean); + SinglePrototypeInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertSame(applicationContext, instance.getApplicationContext()); + } + + @Test + public void testCanRetrieveBeanByNameWithJpaCompliantOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + + ContainedBean bean = beanContainer.getBean( + "multiple-1", MultiplePrototypesInSpringContextTestBean.class, + JpaLifecycleOptions.INSTANCE, + IneffectiveBeanInstanceProducer.INSTANCE + ); + + assertNotNull(bean); + MultiplePrototypesInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals("multiple-1", instance.getName()); + assertSame(applicationContext, instance.getApplicationContext()); + } + + @Test + public void testCanRetrieveBeanByTypeWithNativeOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + + ContainedBean bean = beanContainer.getBean( + SinglePrototypeInSpringContextTestBean.class, + NativeLifecycleOptions.INSTANCE, + IneffectiveBeanInstanceProducer.INSTANCE + ); + + assertNotNull(bean); + SinglePrototypeInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals("single", instance.getName()); + assertSame(applicationContext, instance.getApplicationContext()); + + ContainedBean bean2 = beanContainer.getBean( + SinglePrototypeInSpringContextTestBean.class, + NativeLifecycleOptions.INSTANCE, + IneffectiveBeanInstanceProducer.INSTANCE + ); + + assertNotNull(bean2); + SinglePrototypeInSpringContextTestBean instance2 = bean2.getBeanInstance(); + assertNotNull(instance2); + // Due to the lifecycle options, and because the bean has the "prototype" scope, we should not return the same instance + assertNotSame(instance, instance2); + } + + @Test + public void testCanRetrieveBeanByNameWithNativeOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + + ContainedBean bean = beanContainer.getBean( + "multiple-1", MultiplePrototypesInSpringContextTestBean.class, + NativeLifecycleOptions.INSTANCE, + IneffectiveBeanInstanceProducer.INSTANCE + ); + + assertNotNull(bean); + MultiplePrototypesInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals("multiple-1", instance.getName()); + assertSame(applicationContext, instance.getApplicationContext()); + + ContainedBean bean2 = beanContainer.getBean( + "multiple-1", MultiplePrototypesInSpringContextTestBean.class, + NativeLifecycleOptions.INSTANCE, + IneffectiveBeanInstanceProducer.INSTANCE + ); + + assertNotNull(bean2); + MultiplePrototypesInSpringContextTestBean instance2 = bean2.getBeanInstance(); + assertNotNull(instance2); + // Due to the lifecycle options, and because the bean has the "prototype" scope, we should not return the same instance + assertNotSame(instance, instance2); + } + + @Test + public void testCanRetrieveFallbackBeanByTypeWithJpaCompliantOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + NoDefinitionInSpringContextTestBeanInstanceProducer fallbackProducer = new NoDefinitionInSpringContextTestBeanInstanceProducer(); + + ContainedBean bean = beanContainer.getBean( + NoDefinitionInSpringContextTestBean.class, + JpaLifecycleOptions.INSTANCE, + fallbackProducer + ); + + assertEquals(1, fallbackProducer.currentUnnamedInstantiationCount()); + assertEquals(0, fallbackProducer.currentNamedInstantiationCount()); + + assertNotNull(bean); + NoDefinitionInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals(BeanSource.FALLBACK, instance.getSource()); + assertNull(instance.getApplicationContext()); + } + + @Test + public void testCanRetrieveFallbackBeanByNameWithJpaCompliantOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + NoDefinitionInSpringContextTestBeanInstanceProducer fallbackProducer = new NoDefinitionInSpringContextTestBeanInstanceProducer(); + + ContainedBean bean = beanContainer.getBean( + "some name", NoDefinitionInSpringContextTestBean.class, + JpaLifecycleOptions.INSTANCE, + fallbackProducer + ); + + assertEquals(0, fallbackProducer.currentUnnamedInstantiationCount()); + assertEquals(1, fallbackProducer.currentNamedInstantiationCount()); + + assertNotNull(bean); + NoDefinitionInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals(BeanSource.FALLBACK, instance.getSource()); + assertEquals("some name", instance.getName()); + assertNull(instance.getApplicationContext()); + } + + @Test + public void testCanRetrieveFallbackBeanByTypeWithNativeOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + NoDefinitionInSpringContextTestBeanInstanceProducer fallbackProducer = new NoDefinitionInSpringContextTestBeanInstanceProducer(); + + ContainedBean bean = beanContainer.getBean( + NoDefinitionInSpringContextTestBean.class, + NativeLifecycleOptions.INSTANCE, + fallbackProducer + ); + + assertEquals(1, fallbackProducer.currentUnnamedInstantiationCount()); + assertEquals(0, fallbackProducer.currentNamedInstantiationCount()); + + assertNotNull(bean); + NoDefinitionInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals(BeanSource.FALLBACK, instance.getSource()); + assertNull(instance.getApplicationContext()); + } + + @Test + public void testCanRetrieveFallbackBeanByNameWithNativeOptions() { + BeanContainer beanContainer = getBeanContainer(); + assertNotNull(beanContainer); + NoDefinitionInSpringContextTestBeanInstanceProducer fallbackProducer = new NoDefinitionInSpringContextTestBeanInstanceProducer(); + + ContainedBean bean = beanContainer.getBean( + "some name", NoDefinitionInSpringContextTestBean.class, + NativeLifecycleOptions.INSTANCE, + fallbackProducer + ); + + assertEquals(0, fallbackProducer.currentUnnamedInstantiationCount()); + assertEquals(1, fallbackProducer.currentNamedInstantiationCount()); + + assertNotNull(bean); + NoDefinitionInSpringContextTestBean instance = bean.getBeanInstance(); + assertNotNull(instance); + assertEquals(BeanSource.FALLBACK, instance.getSource()); + assertEquals("some name", instance.getName()); + assertNull(instance.getApplicationContext()); + } + + + /** + * The lifecycle options mandated by the JPA spec and used as a default in Hibernate ORM. + */ + private static class JpaLifecycleOptions implements BeanContainer.LifecycleOptions { + public static final JpaLifecycleOptions INSTANCE = new JpaLifecycleOptions(); + + @Override + public boolean canUseCachedReferences() { + return true; + } + + @Override + public boolean useJpaCompliantCreation() { + return true; + } + } + + /** + * The lifecycle options used by libraries integrating into Hibernate ORM + * and that want a behavior closer to Spring's native behavior, + * such as Hibernate Search. + */ + private static class NativeLifecycleOptions implements BeanContainer.LifecycleOptions { + public static final NativeLifecycleOptions INSTANCE = new NativeLifecycleOptions(); + + @Override + public boolean canUseCachedReferences() { + return false; + } + + @Override + public boolean useJpaCompliantCreation() { + return false; + } + } + + private static class IneffectiveBeanInstanceProducer implements BeanInstanceProducer { + public static final IneffectiveBeanInstanceProducer INSTANCE = new IneffectiveBeanInstanceProducer(); + + @Override + public B produceBeanInstance(Class aClass) { + throw new UnsupportedOperationException("should not be called"); + } + + @Override + public B produceBeanInstance(String s, Class aClass) { + throw new UnsupportedOperationException("should not be called"); + } + } + + private static class NoDefinitionInSpringContextTestBeanInstanceProducer implements BeanInstanceProducer { + private int unnamedInstantiationCount = 0; + private int namedInstantiationCount = 0; + + @Override + public B produceBeanInstance(Class beanType) { + try { + ++unnamedInstantiationCount; + /* + * We only expect to ever be asked to instantiate this class, so we just cut corners here. + * A real-world implementation would obviously be different. + */ + NoDefinitionInSpringContextTestBean instance = new NoDefinitionInSpringContextTestBean(null, BeanSource.FALLBACK); + return beanType.cast( instance ); + } + catch (RuntimeException e) { + throw new AssertionError( "Unexpected error instantiating a bean by type using reflection", e ); + } + } + + @Override + public B produceBeanInstance(String name, Class beanType) { + try { + ++namedInstantiationCount; + /* + * We only expect to ever be asked to instantiate this class, so we just cut corners here. + * A real-world implementation would obviously be different. + */ + NoDefinitionInSpringContextTestBean instance = new NoDefinitionInSpringContextTestBean(name, BeanSource.FALLBACK); + return beanType.cast( instance ); + } + catch (RuntimeException e) { + throw new AssertionError( "Unexpected error instantiating a bean by name using reflection", e ); + } + } + + private int currentUnnamedInstantiationCount() { + return unnamedInstantiationCount; + } + + private int currentNamedInstantiationCount() { + return namedInstantiationCount; + } + } +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/BeanSource.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/BeanSource.java new file mode 100644 index 0000000000..e81fe908fb --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/BeanSource.java @@ -0,0 +1,22 @@ +/* + * Copyright 2002-2019 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.jpa.hibernate.beans; + +public enum BeanSource { + SPRING, + FALLBACK; +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/MultiplePrototypesInSpringContextTestBean.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/MultiplePrototypesInSpringContextTestBean.java new file mode 100644 index 0000000000..b936671aec --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/MultiplePrototypesInSpringContextTestBean.java @@ -0,0 +1,20 @@ +/* + * Copyright 2002-2019 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.jpa.hibernate.beans; + +public class MultiplePrototypesInSpringContextTestBean extends TestBean { +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/NoDefinitionInSpringContextTestBean.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/NoDefinitionInSpringContextTestBean.java new file mode 100644 index 0000000000..d93b5832bd --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/NoDefinitionInSpringContextTestBean.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2019 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.jpa.hibernate.beans; + +public class NoDefinitionInSpringContextTestBean extends TestBean { + + private NoDefinitionInSpringContextTestBean() { + throw new AssertionError( + "Unexpected call to the default constructor." + + " Is Spring trying to instantiate this class by itself, even though it should delegate to the fallback producer?" + ); + } + + /* + * Expect instantiation through a non-default constructor, just to be sure that Spring will fail if it tries to instantiate it, + * and will subsequently delegate to the fallback bean instance producer. + */ + public NoDefinitionInSpringContextTestBean(String name, BeanSource source) { + setName(name); + setSource(source); + } + +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/SinglePrototypeInSpringContextTestBean.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/SinglePrototypeInSpringContextTestBean.java new file mode 100644 index 0000000000..f5ac1ab06b --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/SinglePrototypeInSpringContextTestBean.java @@ -0,0 +1,20 @@ +/* + * Copyright 2002-2019 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.jpa.hibernate.beans; + +public class SinglePrototypeInSpringContextTestBean extends TestBean { +} diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/TestBean.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/TestBean.java new file mode 100644 index 0000000000..5370734bf0 --- /dev/null +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/beans/TestBean.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2019 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.jpa.hibernate.beans; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +public abstract class TestBean { + private BeanSource source; + + private String name; + + @Autowired + private ApplicationContext applicationContext; + + public BeanSource getSource() { + return source; + } + + public void setSource(BeanSource source) { + this.source = source; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ApplicationContext getApplicationContext() { + return applicationContext; + } +} diff --git a/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/inject-hibernate-spring-bean-container-tests.xml b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/inject-hibernate-spring-bean-container-tests.xml new file mode 100644 index 0000000000..3b056bb69b --- /dev/null +++ b/spring-orm/src/test/resources/org/springframework/orm/jpa/hibernate/inject-hibernate-spring-bean-container-tests.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + From ac4525ddf8b280759c0d3ba63d3569dda64a2e3a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 5 Feb 2019 16:02:17 +0100 Subject: [PATCH 2/4] Detect MariaDB as MySQL (for mariadb-java-client 2.4+ compatibility) Closes gh-22344 --- .../java/org/springframework/jdbc/support/JdbcUtils.java | 5 ++++- .../org/springframework/jdbc/support/sql-error-codes.xml | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcUtils.java index f3b8f4e030..a714d975e9 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/JdbcUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -418,6 +418,9 @@ public abstract class JdbcUtils { if (source != null && source.startsWith("DB2")) { name = "DB2"; } + else if ("MariaDB".equals(source)) { + name = "MySQL"; + } else if ("Sybase SQL Server".equals(source) || "Adaptive Server Enterprise".equals(source) || "ASE".equals(source) || diff --git a/spring-jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml b/spring-jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml index 5e3cd6f840..bec81aab96 100644 --- a/spring-jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml +++ b/spring-jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml @@ -186,6 +186,12 @@ + + + MySQL + MariaDB + + 1054,1064,1146 From 643a68f81bbff820301a76ec862cbb91a6735967 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 5 Feb 2019 16:02:50 +0100 Subject: [PATCH 3/4] Detect existing jar URLs from URLClassLoader.getURLs() Closes gh-22346 --- .../io/support/PathMatchingResourcePatternResolver.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java index 60412044a1..712450c67c 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -372,8 +372,9 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol try { for (URL url : ((URLClassLoader) classLoader).getURLs()) { try { - UrlResource jarResource = new UrlResource( - ResourceUtils.JAR_URL_PREFIX + url + ResourceUtils.JAR_URL_SEPARATOR); + UrlResource jarResource = (ResourceUtils.URL_PROTOCOL_JAR.equals(url.getProtocol()) ? + new UrlResource(url) : + new UrlResource(ResourceUtils.JAR_URL_PREFIX + url + ResourceUtils.JAR_URL_SEPARATOR)); if (jarResource.exists()) { result.add(jarResource); } From 9895e44d7309295302859f8ad4328e8ea5d4fcf5 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 5 Feb 2019 16:03:24 +0100 Subject: [PATCH 4/4] Polishing --- .../java/org/springframework/util/MimeTypeUtils.java | 9 ++++----- .../expression/spel/ast/InlineMap.java | 12 ++++++------ .../expression/spel/ast/ValueRef.java | 9 +++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java index d09ee8c4a2..93653c3b18 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java +++ b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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,7 +31,6 @@ import java.util.Random; import java.util.stream.Collectors; import org.springframework.lang.Nullable; -import org.springframework.util.MimeType.SpecificityComparator; /** * Miscellaneous {@link MimeType} utility methods. @@ -52,7 +51,7 @@ public abstract class MimeTypeUtils { /** * Comparator used by {@link #sortBySpecificity(List)}. */ - public static final Comparator SPECIFICITY_COMPARATOR = new SpecificityComparator<>(); + public static final Comparator SPECIFICITY_COMPARATOR = new MimeType.SpecificityComparator<>(); /** * Public constant mime type that includes all media ranges (i.e. "*/*"). @@ -154,10 +153,10 @@ public abstract class MimeTypeUtils { */ public static final String TEXT_XML_VALUE = "text/xml"; + @Nullable private static volatile Random random; - static { ALL = MimeType.valueOf(ALL_VALUE); APPLICATION_JSON = MimeType.valueOf(APPLICATION_JSON_VALUE); @@ -263,6 +262,7 @@ public abstract class MimeTypeUtils { .map(MimeTypeUtils::parseMimeType).collect(Collectors.toList()); } + /** * Tokenize the given comma-separated string of {@code MimeType} objects * into a {@code List}. Unlike simple tokenization by ",", this @@ -318,7 +318,6 @@ public abstract class MimeTypeUtils { return builder.toString(); } - /** * Sorts the given list of {@code MimeType} objects by specificity. *

Given two mime types: diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java index b29d124930..4110add6f7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/InlineMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -47,7 +47,7 @@ public class InlineMap extends SpelNodeImpl { /** - * If all the components of the list are constants, or lists/maps that themselves + * If all the components of the map are constants, or lists/maps that themselves * contain constants, then a constant list can be built to represent this node. * This will speed up later getValue calls and reduce the amount of garbage created. */ @@ -70,14 +70,14 @@ public class InlineMap extends SpelNodeImpl { break; } } - else if (!((c%2)==0 && (child instanceof PropertyOrFieldReference))) { + else if (!(c % 2 == 0 && child instanceof PropertyOrFieldReference)) { isConstant = false; break; } } } if (isConstant) { - Map constantMap = new LinkedHashMap<>(); + Map constantMap = new LinkedHashMap<>(); int childCount = getChildCount(); for (int c = 0; c < childCount; c++) { SpelNode keyChild = getChild(c++); @@ -159,9 +159,9 @@ public class InlineMap extends SpelNodeImpl { @SuppressWarnings("unchecked") @Nullable - public Map getConstantValue() { + public Map getConstantValue() { Assert.state(this.constant != null, "No constant"); - return (Map) this.constant.getValue(); + return (Map) this.constant.getValue(); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ValueRef.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ValueRef.java index 702f0e5c6a..f0c09af997 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/ValueRef.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/ValueRef.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -24,8 +24,8 @@ import org.springframework.lang.Nullable; /** * Represents a reference to a value. With a reference it is possible to get or set the * value. Passing around value references rather than the values themselves can avoid - * incorrect duplication of operand evaluation. For example in 'list[index++]++' without a - * value reference for 'list[index++]' it would be necessary to evaluate list[index++] + * incorrect duplication of operand evaluation. For example in 'list[index++]++' without + * a value reference for 'list[index++]' it would be necessary to evaluate list[index++] * twice (once to get the value, once to determine where the value goes) and that would * double increment index. * @@ -103,7 +103,8 @@ public interface ValueRef { @Override public void setValue(@Nullable Object newValue) { - throw new SpelEvaluationException(this.node.pos, SpelMessage.NOT_ASSIGNABLE, this.node.toStringAST()); + throw new SpelEvaluationException( + this.node.getStartPosition(), SpelMessage.NOT_ASSIGNABLE, this.node.toStringAST()); } @Override