Skip to content

Commit 0aedd81

Browse files
committed
JndiObjectFactoryBean converts a "defaultObject" value to the expected type if necessary
Issue: SPR-11039
1 parent dcc6ef2 commit 0aedd81

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

spring-context/src/main/java/org/springframework/jndi/JndiObjectFactoryBean.java

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,8 +25,14 @@
2525
import org.aopalliance.intercept.MethodInvocation;
2626

2727
import org.springframework.aop.framework.ProxyFactory;
28+
import org.springframework.beans.SimpleTypeConverter;
29+
import org.springframework.beans.TypeConverter;
30+
import org.springframework.beans.TypeMismatchException;
2831
import org.springframework.beans.factory.BeanClassLoaderAware;
32+
import org.springframework.beans.factory.BeanFactory;
33+
import org.springframework.beans.factory.BeanFactoryAware;
2934
import org.springframework.beans.factory.FactoryBean;
35+
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
3036
import org.springframework.util.ClassUtils;
3137

3238
/**
@@ -61,9 +67,10 @@
6167
* @see #setCache
6268
* @see JndiObjectTargetSource
6369
*/
64-
public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryBean<Object>, BeanClassLoaderAware {
70+
public class JndiObjectFactoryBean extends JndiObjectLocator
71+
implements FactoryBean<Object>, BeanFactoryAware, BeanClassLoaderAware {
6572

66-
private Class[] proxyInterfaces;
73+
private Class<?>[] proxyInterfaces;
6774

6875
private boolean lookupOnStartup = true;
6976

@@ -73,6 +80,8 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
7380

7481
private Object defaultObject;
7582

83+
private ConfigurableBeanFactory beanFactory;
84+
7685
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
7786

7887
private Object jndiObject;
@@ -87,8 +96,8 @@ public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryB
8796
* @see #setLookupOnStartup
8897
* @see #setCache
8998
*/
90-
public void setProxyInterface(Class proxyInterface) {
91-
this.proxyInterfaces = new Class[] {proxyInterface};
99+
public void setProxyInterface(Class<?> proxyInterface) {
100+
this.proxyInterfaces = new Class<?>[] {proxyInterface};
92101
}
93102

94103
/**
@@ -100,7 +109,7 @@ public void setProxyInterface(Class proxyInterface) {
100109
* @see #setLookupOnStartup
101110
* @see #setCache
102111
*/
103-
public void setProxyInterfaces(Class[] proxyInterfaces) {
112+
public void setProxyInterfaces(Class<?>... proxyInterfaces) {
104113
this.proxyInterfaces = proxyInterfaces;
105114
}
106115

@@ -149,12 +158,25 @@ public void setExposeAccessContext(boolean exposeAccessContext) {
149158
* It is typically used for literal values in scenarios where the JNDI environment
150159
* might define specific config settings but those are not required to be present.
151160
* <p>Note: This is only supported for lookup on startup.
161+
* If specified together with {@link #setExpectedType}, the specified value
162+
* needs to be either of that type or convertible to it.
152163
* @see #setLookupOnStartup
164+
* @see ConfigurableBeanFactory#getTypeConverter()
165+
* @see SimpleTypeConverter
153166
*/
154167
public void setDefaultObject(Object defaultObject) {
155168
this.defaultObject = defaultObject;
156169
}
157170

171+
@Override
172+
public void setBeanFactory(BeanFactory beanFactory) {
173+
if (beanFactory instanceof ConfigurableBeanFactory) {
174+
// Just optional - for getting a specifically configured TypeConverter if needed.
175+
// We'll simply fall back to a SimpleTypeConverter if no specific one available.
176+
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
177+
}
178+
}
179+
158180
@Override
159181
public void setBeanClassLoader(ClassLoader classLoader) {
160182
this.beanClassLoader = classLoader;
@@ -180,9 +202,16 @@ public void afterPropertiesSet() throws IllegalArgumentException, NamingExceptio
180202
else {
181203
if (this.defaultObject != null && getExpectedType() != null &&
182204
!getExpectedType().isInstance(this.defaultObject)) {
183-
throw new IllegalArgumentException("Default object [" + this.defaultObject +
184-
"] of type [" + this.defaultObject.getClass().getName() +
185-
"] is not of expected type [" + getExpectedType().getName() + "]");
205+
TypeConverter converter = (this.beanFactory != null ?
206+
this.beanFactory.getTypeConverter() : new SimpleTypeConverter());
207+
try {
208+
this.defaultObject = converter.convertIfNecessary(this.defaultObject, getExpectedType());
209+
}
210+
catch (TypeMismatchException ex) {
211+
throw new IllegalArgumentException("Default object [" + this.defaultObject + "] of type [" +
212+
this.defaultObject.getClass().getName() + "] is not of expected type [" +
213+
getExpectedType().getName() + "] and cannot be converted either", ex);
214+
}
186215
}
187216
// Locate specified JNDI object.
188217
this.jndiObject = lookupWithFallback();
@@ -267,7 +296,7 @@ public boolean isSingleton() {
267296
* @return the merged interface as Class
268297
* @see java.lang.reflect.Proxy#getProxyClass
269298
*/
270-
protected Class createCompositeInterface(Class[] interfaces) {
299+
protected Class<?> createCompositeInterface(Class<?>[] interfaces) {
271300
return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader);
272301
}
273302

@@ -294,13 +323,13 @@ private static Object createJndiObjectProxy(JndiObjectFactoryBean jof) throws Na
294323
proxyFactory.setInterfaces(jof.proxyInterfaces);
295324
}
296325
else {
297-
Class targetClass = targetSource.getTargetClass();
326+
Class<?> targetClass = targetSource.getTargetClass();
298327
if (targetClass == null) {
299328
throw new IllegalStateException(
300329
"Cannot deactivate 'lookupOnStartup' without specifying a 'proxyInterface' or 'expectedType'");
301330
}
302-
Class[] ifcs = ClassUtils.getAllInterfacesForClass(targetClass, jof.beanClassLoader);
303-
for (Class ifc : ifcs) {
331+
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(targetClass, jof.beanClassLoader);
332+
for (Class<?> ifc : ifcs) {
304333
if (Modifier.isPublic(ifc.getModifiers())) {
305334
proxyFactory.addInterface(ifc);
306335
}

spring-context/src/test/java/org/springframework/jndi/JndiObjectFactoryBeanTests.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import javax.naming.NamingException;
2121

2222
import org.junit.Test;
23+
24+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2325
import org.springframework.tests.mock.jndi.ExpectedLookupTemplate;
2426
import org.springframework.tests.sample.beans.DerivedTestBean;
2527
import org.springframework.tests.sample.beans.ITestBean;
@@ -142,24 +144,22 @@ public void testLookupWithExpectedTypeAndMatch() throws Exception {
142144
@Test
143145
public void testLookupWithExpectedTypeAndNoMatch() throws Exception {
144146
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
145-
Object o = new Object();
146-
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", o));
147+
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", new Object()));
147148
jof.setJndiName("foo");
148149
jof.setExpectedType(String.class);
149150
try {
150151
jof.afterPropertiesSet();
151152
fail("Should have thrown NamingException");
152153
}
153154
catch (NamingException ex) {
154-
assertTrue(ex.getMessage().indexOf("java.lang.String") != -1);
155+
assertTrue(ex.getMessage().contains("java.lang.String"));
155156
}
156157
}
157158

158159
@Test
159160
public void testLookupWithDefaultObject() throws Exception {
160161
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
161-
String s = "";
162-
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s));
162+
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
163163
jof.setJndiName("myFoo");
164164
jof.setExpectedType(String.class);
165165
jof.setDefaultObject("myString");
@@ -170,23 +170,44 @@ public void testLookupWithDefaultObject() throws Exception {
170170
@Test
171171
public void testLookupWithDefaultObjectAndExpectedType() throws Exception {
172172
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
173-
String s = "";
174-
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s));
173+
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
175174
jof.setJndiName("myFoo");
176175
jof.setExpectedType(String.class);
177176
jof.setDefaultObject("myString");
178177
jof.afterPropertiesSet();
179178
assertEquals("myString", jof.getObject());
180179
}
181180

181+
@Test
182+
public void testLookupWithDefaultObjectAndExpectedTypeConversion() throws Exception {
183+
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
184+
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
185+
jof.setJndiName("myFoo");
186+
jof.setExpectedType(Integer.class);
187+
jof.setDefaultObject("5");
188+
jof.afterPropertiesSet();
189+
assertEquals(new Integer(5), jof.getObject());
190+
}
191+
192+
@Test
193+
public void testLookupWithDefaultObjectAndExpectedTypeConversionViaBeanFactory() throws Exception {
194+
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
195+
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
196+
jof.setJndiName("myFoo");
197+
jof.setExpectedType(Integer.class);
198+
jof.setDefaultObject("5");
199+
jof.setBeanFactory(new DefaultListableBeanFactory());
200+
jof.afterPropertiesSet();
201+
assertEquals(new Integer(5), jof.getObject());
202+
}
203+
182204
@Test
183205
public void testLookupWithDefaultObjectAndExpectedTypeNoMatch() throws Exception {
184206
JndiObjectFactoryBean jof = new JndiObjectFactoryBean();
185-
String s = "";
186-
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", s));
207+
jof.setJndiTemplate(new ExpectedLookupTemplate("foo", ""));
187208
jof.setJndiName("myFoo");
188-
jof.setExpectedType(String.class);
189-
jof.setDefaultObject(Boolean.TRUE);
209+
jof.setExpectedType(Boolean.class);
210+
jof.setDefaultObject("5");
190211
try {
191212
jof.afterPropertiesSet();
192213
fail("Should have thrown IllegalArgumentException");

0 commit comments

Comments
 (0)