JndiObjectFactoryBean converts a "defaultObject" value to the expected type if necessary
Issue: SPR-11039
This commit is contained in:
parent
dcc6ef262d
commit
0aedd81ccc
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -25,8 +25,14 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
import org.springframework.aop.framework.ProxyFactory;
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
|
import org.springframework.beans.SimpleTypeConverter;
|
||||||
|
import org.springframework.beans.TypeConverter;
|
||||||
|
import org.springframework.beans.TypeMismatchException;
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,9 +67,10 @@ import org.springframework.util.ClassUtils;
|
||||||
* @see #setCache
|
* @see #setCache
|
||||||
* @see JndiObjectTargetSource
|
* @see JndiObjectTargetSource
|
||||||
*/
|
*/
|
||||||
public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryBean<Object>, BeanClassLoaderAware {
|
public class JndiObjectFactoryBean extends JndiObjectLocator
|
||||||
|
implements FactoryBean<Object>, BeanFactoryAware, BeanClassLoaderAware {
|
||||||
|
|
||||||
private Class[] proxyInterfaces;
|
private Class<?>[] proxyInterfaces;
|
||||||
|
|
||||||
private boolean lookupOnStartup = true;
|
private boolean lookupOnStartup = true;
|
||||||
|
|
||||||
|
@ -73,6 +80,8 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
|
|
||||||
private Object defaultObject;
|
private Object defaultObject;
|
||||||
|
|
||||||
|
private ConfigurableBeanFactory beanFactory;
|
||||||
|
|
||||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||||
|
|
||||||
private Object jndiObject;
|
private Object jndiObject;
|
||||||
|
@ -87,8 +96,8 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
* @see #setLookupOnStartup
|
* @see #setLookupOnStartup
|
||||||
* @see #setCache
|
* @see #setCache
|
||||||
*/
|
*/
|
||||||
public void setProxyInterface(Class proxyInterface) {
|
public void setProxyInterface(Class<?> proxyInterface) {
|
||||||
this.proxyInterfaces = new Class[] {proxyInterface};
|
this.proxyInterfaces = new Class<?>[] {proxyInterface};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,7 +109,7 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
* @see #setLookupOnStartup
|
* @see #setLookupOnStartup
|
||||||
* @see #setCache
|
* @see #setCache
|
||||||
*/
|
*/
|
||||||
public void setProxyInterfaces(Class[] proxyInterfaces) {
|
public void setProxyInterfaces(Class<?>... proxyInterfaces) {
|
||||||
this.proxyInterfaces = proxyInterfaces;
|
this.proxyInterfaces = proxyInterfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,12 +158,25 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
* It is typically used for literal values in scenarios where the JNDI environment
|
* It is typically used for literal values in scenarios where the JNDI environment
|
||||||
* might define specific config settings but those are not required to be present.
|
* might define specific config settings but those are not required to be present.
|
||||||
* <p>Note: This is only supported for lookup on startup.
|
* <p>Note: This is only supported for lookup on startup.
|
||||||
|
* If specified together with {@link #setExpectedType}, the specified value
|
||||||
|
* needs to be either of that type or convertible to it.
|
||||||
* @see #setLookupOnStartup
|
* @see #setLookupOnStartup
|
||||||
|
* @see ConfigurableBeanFactory#getTypeConverter()
|
||||||
|
* @see SimpleTypeConverter
|
||||||
*/
|
*/
|
||||||
public void setDefaultObject(Object defaultObject) {
|
public void setDefaultObject(Object defaultObject) {
|
||||||
this.defaultObject = defaultObject;
|
this.defaultObject = defaultObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) {
|
||||||
|
if (beanFactory instanceof ConfigurableBeanFactory) {
|
||||||
|
// Just optional - for getting a specifically configured TypeConverter if needed.
|
||||||
|
// We'll simply fall back to a SimpleTypeConverter if no specific one available.
|
||||||
|
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
this.beanClassLoader = classLoader;
|
this.beanClassLoader = classLoader;
|
||||||
|
@ -180,9 +202,16 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
else {
|
else {
|
||||||
if (this.defaultObject != null && getExpectedType() != null &&
|
if (this.defaultObject != null && getExpectedType() != null &&
|
||||||
!getExpectedType().isInstance(this.defaultObject)) {
|
!getExpectedType().isInstance(this.defaultObject)) {
|
||||||
throw new IllegalArgumentException("Default object [" + this.defaultObject +
|
TypeConverter converter = (this.beanFactory != null ?
|
||||||
"] of type [" + this.defaultObject.getClass().getName() +
|
this.beanFactory.getTypeConverter() : new SimpleTypeConverter());
|
||||||
"] is not of expected type [" + getExpectedType().getName() + "]");
|
try {
|
||||||
|
this.defaultObject = converter.convertIfNecessary(this.defaultObject, getExpectedType());
|
||||||
|
}
|
||||||
|
catch (TypeMismatchException ex) {
|
||||||
|
throw new IllegalArgumentException("Default object [" + this.defaultObject + "] of type [" +
|
||||||
|
this.defaultObject.getClass().getName() + "] is not of expected type [" +
|
||||||
|
getExpectedType().getName() + "] and cannot be converted either", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Locate specified JNDI object.
|
// Locate specified JNDI object.
|
||||||
this.jndiObject = lookupWithFallback();
|
this.jndiObject = lookupWithFallback();
|
||||||
|
@ -267,7 +296,7 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
* @return the merged interface as Class
|
* @return the merged interface as Class
|
||||||
* @see java.lang.reflect.Proxy#getProxyClass
|
* @see java.lang.reflect.Proxy#getProxyClass
|
||||||
*/
|
*/
|
||||||
protected Class createCompositeInterface(Class[] interfaces) {
|
protected Class<?> createCompositeInterface(Class<?>[] interfaces) {
|
||||||
return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader);
|
return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,13 +323,13 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
|
||||||
proxyFactory.setInterfaces(jof.proxyInterfaces);
|
proxyFactory.setInterfaces(jof.proxyInterfaces);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Class targetClass = targetSource.getTargetClass();
|
Class<?> targetClass = targetSource.getTargetClass();
|
||||||
if (targetClass == null) {
|
if (targetClass == null) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Cannot deactivate 'lookupOnStartup' without specifying a 'proxyInterface' or 'expectedType'");
|
"Cannot deactivate 'lookupOnStartup' without specifying a 'proxyInterface' or 'expectedType'");
|
||||||
}
|
}
|
||||||
Class[] ifcs = ClassUtils.getAllInterfacesForClass(targetClass, jof.beanClassLoader);
|
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(targetClass, jof.beanClassLoader);
|
||||||
for (Class ifc : ifcs) {
|
for (Class<?> ifc : ifcs) {
|
||||||
if (Modifier.isPublic(ifc.getModifiers())) {
|
if (Modifier.isPublic(ifc.getModifiers())) {
|
||||||
proxyFactory.addInterface(ifc);
|
proxyFactory.addInterface(ifc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ import javax.naming.Context;
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.tests.mock.jndi.ExpectedLookupTemplate;
|
import org.springframework.tests.mock.jndi.ExpectedLookupTemplate;
|
||||||
import org.springframework.tests.sample.beans.DerivedTestBean;
|
import org.springframework.tests.sample.beans.DerivedTestBean;
|
||||||
import org.springframework.tests.sample.beans.ITestBean;
|
import org.springframework.tests.sample.beans.ITestBean;
|
||||||
|
@ -142,8 +144,7 @@ public class JndiObjectFactoryBeanTests {
|
||||||
@Test
|
@Test
|
||||||
public void testLookupWithExpectedTypeAndNoMatch() throws Exception {
|
public void testLookupWithExpectedTypeAndNoMatch() throws Exception {
|
||||||
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
||||||
Object o = new Object();
|
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", new Object()));
|
||||||
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", o));
|
|
||||||
jof.setJndiName("foo");
|
jof.setJndiName("foo");
|
||||||
jof.setExpectedType(String.class);
|
jof.setExpectedType(String.class);
|
||||||
try {
|
try {
|
||||||
|
@ -151,15 +152,14 @@ public class JndiObjectFactoryBeanTests {
|
||||||
fail("Should have thrown NamingException");
|
fail("Should have thrown NamingException");
|
||||||
}
|
}
|
||||||
catch (NamingException ex) {
|
catch (NamingException ex) {
|
||||||
assertTrue(ex.getMessage().indexOf("java.lang.String") != -1);
|
assertTrue(ex.getMessage().contains("java.lang.String"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLookupWithDefaultObject() throws Exception {
|
public void testLookupWithDefaultObject() throws Exception {
|
||||||
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
||||||
String s = "";
|
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
|
||||||
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s));
|
|
||||||
jof.setJndiName("myFoo");
|
jof.setJndiName("myFoo");
|
||||||
jof.setExpectedType(String.class);
|
jof.setExpectedType(String.class);
|
||||||
jof.setDefaultObject("myString");
|
jof.setDefaultObject("myString");
|
||||||
|
@ -170,8 +170,7 @@ public class JndiObjectFactoryBeanTests {
|
||||||
@Test
|
@Test
|
||||||
public void testLookupWithDefaultObjectAndExpectedType() throws Exception {
|
public void testLookupWithDefaultObjectAndExpectedType() throws Exception {
|
||||||
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
||||||
String s = "";
|
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
|
||||||
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s));
|
|
||||||
jof.setJndiName("myFoo");
|
jof.setJndiName("myFoo");
|
||||||
jof.setExpectedType(String.class);
|
jof.setExpectedType(String.class);
|
||||||
jof.setDefaultObject("myString");
|
jof.setDefaultObject("myString");
|
||||||
|
@ -179,14 +178,36 @@ public class JndiObjectFactoryBeanTests {
|
||||||
assertEquals("myString", jof.getObject());
|
assertEquals("myString", jof.getObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupWithDefaultObjectAndExpectedTypeConversion() throws Exception {
|
||||||
|
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
||||||
|
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
|
||||||
|
jof.setJndiName("myFoo");
|
||||||
|
jof.setExpectedType(Integer.class);
|
||||||
|
jof.setDefaultObject("5");
|
||||||
|
jof.afterPropertiesSet();
|
||||||
|
assertEquals(new Integer(5), jof.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLookupWithDefaultObjectAndExpectedTypeConversionViaBeanFactory() throws Exception {
|
||||||
|
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
||||||
|
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
|
||||||
|
jof.setJndiName("myFoo");
|
||||||
|
jof.setExpectedType(Integer.class);
|
||||||
|
jof.setDefaultObject("5");
|
||||||
|
jof.setBeanFactory(new DefaultListableBeanFactory());
|
||||||
|
jof.afterPropertiesSet();
|
||||||
|
assertEquals(new Integer(5), jof.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLookupWithDefaultObjectAndExpectedTypeNoMatch() throws Exception {
|
public void testLookupWithDefaultObjectAndExpectedTypeNoMatch() throws Exception {
|
||||||
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
|
||||||
String s = "";
|
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
|
||||||
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s));
|
|
||||||
jof.setJndiName("myFoo");
|
jof.setJndiName("myFoo");
|
||||||
jof.setExpectedType(String.class);
|
jof.setExpectedType(Boolean.class);
|
||||||
jof.setDefaultObject(Boolean.TRUE);
|
jof.setDefaultObject("5");
|
||||||
try {
|
try {
|
||||||
jof.afterPropertiesSet();
|
jof.afterPropertiesSet();
|
||||||
fail("Should have thrown IllegalArgumentException");
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
|
Loading…
Reference in New Issue