Sync with 3.1.x

* 3.1.x: (61 commits)
  Compensate for changes in JDK 7 Introspector
  Avoid 'type mismatch' errors in ExtendedBeanInfo
  Polish ExtendedBeanInfo and tests
  Infer AnnotationAttributes method return types
  Minor fix in MVC reference doc chapter
  Hibernate 4.1 etc
  TypeDescriptor equals implementation accepts annotations in any order
  "setBasenames" uses varargs now (for programmatic setup; SPR-9106)
  @ActiveProfiles mechanism works with @ImportResource as well (SPR-8992
  polishing
  clarified Resource's "getFilename" method to consistently return null
  substituteNamedParameters detects and unwraps SqlParameterValue object
  Replace spaces with tabs
  Consider security in ClassUtils#getMostSpecificMethod
  Adding null check for username being null.
  Improvements for registering custom SQL exception translators in app c
  SPR-7680 Adding QueryTimeoutException to the DataAccessException hiera
  Minor polish in WebMvcConfigurationSupport
  Detect overridden boolean getters in ExtendedBeanInfo
  Polish ExtendedBeanInfoTests
  ...
This commit is contained in:
Chris Beams
2012-02-13 15:17:30 +01:00
134 changed files with 3552 additions and 1471 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -16,11 +16,12 @@
package org.springframework.beans;
import static org.junit.Assert.*;
import org.junit.Test;
import test.beans.CustomEnum;
import test.beans.GenericBean;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
* @author Chris Beams
@@ -109,4 +110,14 @@ public final class BeanWrapperEnumTests {
assertTrue(gb.getCustomEnumSet().contains(CustomEnum.VALUE_2));
}
@Test
public void testCustomEnumSetWithGetterSetterMismatch() {
GenericBean<?> gb = new GenericBean<Object>();
BeanWrapper bw = new BeanWrapperImpl(gb);
bw.setPropertyValue("customEnumSetMismatch", new String[] {"VALUE_1", "VALUE_2"});
assertEquals(2, gb.getCustomEnumSet().size());
assertTrue(gb.getCustomEnumSet().contains(CustomEnum.VALUE_1));
assertTrue(gb.getCustomEnumSet().contains(CustomEnum.VALUE_2));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -16,13 +16,13 @@
package org.springframework.beans;
import static java.lang.String.format;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.beans.BeanInfo;
@@ -32,9 +32,10 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.ExtendedBeanInfo.PropertyDescriptorComparator;
import org.springframework.core.JdkVersion;
import org.springframework.util.ClassUtils;
import test.beans.TestBean;
@@ -429,11 +430,12 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
// interesting! standard Inspector picks up non-void return types on indexed write methods by default
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
@@ -456,13 +458,12 @@ public class ExtendedBeanInfoTests {
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
// again as above, standard Inspector picks up non-void return types on indexed write methods by default
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foos"), is(true));
// again as above, standard Inspector picks up non-void return types on indexed write methods by default
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
@@ -550,17 +551,17 @@ public class ExtendedBeanInfoTests {
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(true));
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
assertThat(hasReadMethodForProperty(ebi, "dateFormat"), is(false));
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(false));
assertThat(hasIndexedReadMethodForProperty(ebi, "dateFormat"), is(false));
assertThat(hasIndexedWriteMethodForProperty(ebi, "dateFormat"), is(true));
}
@@ -663,52 +664,18 @@ public class ExtendedBeanInfoTests {
return false;
}
@Test
public void reproSpr8806_y() throws IntrospectionException, SecurityException, NoSuchMethodException {
Introspector.getBeanInfo(LawLibrary.class);
private boolean trueUntilJdk17() {
return JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_17;
}
@Ignore @Test
public void reproSpr8806_x() throws IntrospectionException, SecurityException, NoSuchMethodException {
BeanInfo info = Introspector.getBeanInfo(LawLibrary.class);
for (PropertyDescriptor d : info.getPropertyDescriptors()) {
if (d.getName().equals("book")) {
Method readMethod = d.getReadMethod();
Method writeMethod = d.getWriteMethod();
System.out.println(format("READ : %s.%s (bridge:%s)",
readMethod.getDeclaringClass().getSimpleName(), readMethod.getName(), readMethod.isBridge()));
System.out.println(format("WRITE: %s.%s (bridge:%s)",
writeMethod.getDeclaringClass().getSimpleName(), writeMethod.getName(), writeMethod.isBridge()));
new PropertyDescriptor("book", readMethod, writeMethod);
}
}
Method readMethod = LawLibrary.class.getMethod("getBook");
Method writeMethod = LawLibrary.class.getMethod("setBook", Book.class);
System.out.println(format("read : %s.%s (bridge:%s)",
readMethod.getDeclaringClass().getSimpleName(), readMethod.getName(), readMethod.isBridge()));
System.out.println(format("write: %s.%s (bridge:%s)",
writeMethod.getDeclaringClass().getSimpleName(), writeMethod.getName(), writeMethod.isBridge()));
System.out.println("--------");
for (Method m : LawLibrary.class.getMethods()) {
if (m.getDeclaringClass() == Object.class) continue;
System.out.println(format("%s %s.%s(%s) [bridge:%s]",
m.getReturnType().getSimpleName(), m.getDeclaringClass().getSimpleName(),
m.getName(),
m.getParameterTypes().length == 1 ? m.getParameterTypes()[0].getSimpleName() : "",
m.isBridge()));
}
//new ExtendedBeanInfo(info);
}
@Test
public void reproSpr8806() throws IntrospectionException {
BeanInfo bi = Introspector.getBeanInfo(LawLibrary.class);
new ExtendedBeanInfo(bi); // throws
// does not throw
Introspector.getBeanInfo(LawLibrary.class);
// does not throw after the changes introduced in SPR-8806
new ExtendedBeanInfo(Introspector.getBeanInfo(LawLibrary.class));
}
interface Book { }
@@ -734,4 +701,74 @@ public class ExtendedBeanInfoTests {
class LawLibrary extends Library implements TextBookOperations {
public LawBook getBook() { return null; }
}
@Test
public void cornerSpr8949() throws IntrospectionException {
class A {
@SuppressWarnings("unused")
public boolean isTargetMethod() {
return false;
}
}
class B extends A {
@Override
public boolean isTargetMethod() {
return false;
}
}
BeanInfo bi = Introspector.getBeanInfo(B.class);
/* first, demonstrate the 'problem':
* java.beans.Introspector returns the "wrong" declaring class for overridden read
* methods, which in turn violates expectations in {@link ExtendedBeanInfo} regarding
* method equality. Spring's {@link ClassUtils#getMostSpecificMethod(Method, Class)}
* helps out here, and is now put into use in ExtendedBeanInfo as well
*/
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
if ("targetMethod".equals(pd.getName())) {
Method readMethod = pd.getReadMethod();
assertTrue(readMethod.getDeclaringClass().equals(A.class)); // we expected B!
Method msReadMethod = ClassUtils.getMostSpecificMethod(readMethod, B.class);
assertTrue(msReadMethod.getDeclaringClass().equals(B.class)); // and now we get it.
}
}
// and now demonstrate that we've indeed fixed the problem
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "targetMethod"), is(true));
assertThat(hasWriteMethodForProperty(bi, "targetMethod"), is(false));
assertThat(hasReadMethodForProperty(ebi, "targetMethod"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "targetMethod"), is(false));
}
@Test
public void cornerSpr8937() throws IntrospectionException {
@SuppressWarnings("unused") class A {
public void setAddress(String addr){ }
public void setAddress(int index, String addr) { }
public String getAddress(int index){ return null; }
}
{ // baseline. ExtendedBeanInfo needs to behave exactly like the following
BeanInfo bi = Introspector.getBeanInfo(A.class);
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
}
{
ExtendedBeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -23,7 +23,6 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import static org.junit.Assert.*;
import org.junit.Test;
import test.beans.ITestBean;
import test.beans.IndexedTestBean;
@@ -40,6 +39,8 @@ import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.util.SerializationTestUtils;
import static org.junit.Assert.*;
/**
* Unit tests for {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor}
* processing the JSR-303 {@link javax.inject.Inject} annotation.
@@ -206,8 +207,8 @@ public class InjectAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(
ConstructorsCollectionResourceInjectionBean.class));
bf.registerBeanDefinition("annotatedBean",
new RootBeanDefinition(ConstructorsCollectionResourceInjectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
NestedTestBean ntb1 = new NestedTestBean();
@@ -415,6 +416,74 @@ public class InjectAnnotationBeanPostProcessorTests {
bf.destroySingletons();
}
@Test
public void testObjectFactoryWithTypedListField() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
ObjectFactoryListFieldInjectionBean bean = (ObjectFactoryListFieldInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean"), bean.getTestBean());
bean = (ObjectFactoryListFieldInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
assertSame(bf.getBean("testBean"), bean.getTestBean());
bf.destroySingletons();
}
@Test
public void testObjectFactoryWithTypedListMethod() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryListMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
ObjectFactoryListMethodInjectionBean bean = (ObjectFactoryListMethodInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean"), bean.getTestBean());
bean = (ObjectFactoryListMethodInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
assertSame(bf.getBean("testBean"), bean.getTestBean());
bf.destroySingletons();
}
@Test
public void testObjectFactoryWithTypedMapField() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
ObjectFactoryMapFieldInjectionBean bean = (ObjectFactoryMapFieldInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean"), bean.getTestBean());
bean = (ObjectFactoryMapFieldInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
assertSame(bf.getBean("testBean"), bean.getTestBean());
bf.destroySingletons();
}
@Test
public void testObjectFactoryWithTypedMapMethod() throws Exception {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryMapMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
bf.setSerializationId("test");
ObjectFactoryMapMethodInjectionBean bean = (ObjectFactoryMapMethodInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean"), bean.getTestBean());
bean = (ObjectFactoryMapMethodInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
assertSame(bf.getBean("testBean"), bean.getTestBean());
bf.destroySingletons();
}
/**
* Verifies that a dependency on a {@link org.springframework.beans.factory.FactoryBean} can be autowired via
* {@link org.springframework.beans.factory.annotation.Autowired @Inject}, specifically addressing the JIRA issue
@@ -835,6 +904,66 @@ public class InjectAnnotationBeanPostProcessorTests {
}
public static class ObjectFactoryListFieldInjectionBean implements Serializable {
@Inject
private Provider<List<TestBean>> testBeanFactory;
public void setTestBeanFactory(Provider<List<TestBean>> testBeanFactory) {
this.testBeanFactory = testBeanFactory;
}
public TestBean getTestBean() {
return this.testBeanFactory.get().get(0);
}
}
public static class ObjectFactoryListMethodInjectionBean implements Serializable {
private Provider<List<TestBean>> testBeanFactory;
@Inject
public void setTestBeanFactory(Provider<List<TestBean>> testBeanFactory) {
this.testBeanFactory = testBeanFactory;
}
public TestBean getTestBean() {
return this.testBeanFactory.get().get(0);
}
}
public static class ObjectFactoryMapFieldInjectionBean implements Serializable {
@Inject
private Provider<Map<String, TestBean>> testBeanFactory;
public void setTestBeanFactory(Provider<Map<String, TestBean>> testBeanFactory) {
this.testBeanFactory = testBeanFactory;
}
public TestBean getTestBean() {
return this.testBeanFactory.get().values().iterator().next();
}
}
public static class ObjectFactoryMapMethodInjectionBean implements Serializable {
private Provider<Map<String, TestBean>> testBeanFactory;
@Inject
public void setTestBeanFactory(Provider<Map<String, TestBean>> testBeanFactory) {
this.testBeanFactory = testBeanFactory;
}
public TestBean getTestBean() {
return this.testBeanFactory.get().values().iterator().next();
}
}
/**
* Bean with a dependency on a {@link org.springframework.beans.factory.FactoryBean}.
*/

View File

@@ -0,0 +1,96 @@
/*
* 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.beans.factory.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Map;
import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor}
* forces the predicted type of a FactoryBean, effectively preventing retrieval of the
* bean from calls to #getBeansOfType(FactoryBean.class). The implementation of
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures
* that not only the predicted bean type is considered, but also the original bean
* definition's beanClass.
*
* @author Chris Beams
* @author Oliver Gierke
*/
public class Spr8954Tests {
@Test
public void repro() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
bf.addBeanPostProcessor(new PredictingBPP());
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
@SuppressWarnings("rawtypes")
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
assertThat(1, equalTo(fbBeans.size()));
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
assertThat(1, equalTo(aiBeans.size()));
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
}
static class FooFactoryBean implements FactoryBean<Foo>, AnInterface {
public Foo getObject() throws Exception {
return new Foo();
}
public Class<?> getObjectType() {
return Foo.class;
}
public boolean isSingleton() {
return true;
}
}
interface AnInterface {
}
static class Foo {
}
interface PredictedType {
}
static class PredictingBPP extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
return FactoryBean.class.isAssignableFrom(beanClass) ?
PredictedType.class :
super.predictBeanType(beanClass, beanName);
}
}
}