1 /* 2 * Copyright 2002-2010 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.context.expression; 18 19 import java.io.Serializable; 20 import java.security.AccessControlException; 21 import java.security.Permission; 22 import java.util.Properties; 23 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 import static org.junit.Assert.*; 27 import org.junit.Test; 28 29 import org.springframework.beans.TestBean; 30 import org.springframework.beans.factory.ObjectFactory; 31 import org.springframework.beans.factory.annotation.Autowired; 32 import org.springframework.beans.factory.annotation.Qualifier; 33 import org.springframework.beans.factory.annotation.Value; 34 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 35 import org.springframework.beans.factory.config.Scope; 36 import org.springframework.beans.factory.config.TypedStringValue; 37 import org.springframework.beans.factory.support.AutowireCandidateQualifier; 38 import org.springframework.beans.factory.support.DefaultListableBeanFactory; 39 import org.springframework.beans.factory.support.GenericBeanDefinition; 40 import org.springframework.beans.factory.support.RootBeanDefinition; 41 import org.springframework.context.annotation.AnnotationConfigUtils; 42 import org.springframework.context.support.GenericApplicationContext; 43 import org.springframework.util.SerializationTestUtils; 44 import org.springframework.util.StopWatch; 45 46 /** 47 * @author Juergen Hoeller 48 * @since 3.0 49 */ 50 public class ApplicationContextExpressionTests { 51 52 private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); 53 54 @Test genericApplicationContext()55 public void genericApplicationContext() throws Exception { 56 GenericApplicationContext ac = new GenericApplicationContext(); 57 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); 58 59 ac.getBeanFactory().registerScope("myScope", new Scope() { 60 public Object get(String name, ObjectFactory objectFactory) { 61 return objectFactory.getObject(); 62 } 63 public Object remove(String name) { 64 return null; 65 } 66 public void registerDestructionCallback(String name, Runnable callback) { 67 } 68 public Object resolveContextualObject(String key) { 69 if (key.equals("mySpecialAttr")) { 70 return "42"; 71 } 72 else { 73 return null; 74 } 75 } 76 public String getConversationId() { 77 return null; 78 } 79 }); 80 81 PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); 82 Properties placeholders = new Properties(); 83 placeholders.setProperty("code", "123"); 84 ppc.setProperties(placeholders); 85 ac.addBeanFactoryPostProcessor(ppc); 86 87 GenericBeanDefinition bd0 = new GenericBeanDefinition(); 88 bd0.setBeanClass(TestBean.class); 89 bd0.getPropertyValues().add("name", "myName"); 90 bd0.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "original")); 91 ac.registerBeanDefinition("tb0", bd0); 92 93 GenericBeanDefinition bd1 = new GenericBeanDefinition(); 94 bd1.setBeanClass(TestBean.class); 95 bd1.setScope("myScope"); 96 bd1.getConstructorArgumentValues().addGenericArgumentValue("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ"); 97 bd1.getConstructorArgumentValues().addGenericArgumentValue("#{mySpecialAttr}"); 98 ac.registerBeanDefinition("tb1", bd1); 99 100 GenericBeanDefinition bd2 = new GenericBeanDefinition(); 101 bd2.setBeanClass(TestBean.class); 102 bd2.setScope("myScope"); 103 bd2.getPropertyValues().add("name", "{ XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ }"); 104 bd2.getPropertyValues().add("age", "#{mySpecialAttr}"); 105 bd2.getPropertyValues().add("country", "${code} #{systemProperties.country}"); 106 ac.registerBeanDefinition("tb2", bd2); 107 108 GenericBeanDefinition bd3 = new GenericBeanDefinition(); 109 bd3.setBeanClass(ValueTestBean.class); 110 bd3.setScope("myScope"); 111 ac.registerBeanDefinition("tb3", bd3); 112 113 GenericBeanDefinition bd4 = new GenericBeanDefinition(); 114 bd4.setBeanClass(ConstructorValueTestBean.class); 115 bd4.setScope("myScope"); 116 ac.registerBeanDefinition("tb4", bd4); 117 118 GenericBeanDefinition bd5 = new GenericBeanDefinition(); 119 bd5.setBeanClass(MethodValueTestBean.class); 120 bd5.setScope("myScope"); 121 ac.registerBeanDefinition("tb5", bd5); 122 123 GenericBeanDefinition bd6 = new GenericBeanDefinition(); 124 bd6.setBeanClass(PropertyValueTestBean.class); 125 bd6.setScope("myScope"); 126 ac.registerBeanDefinition("tb6", bd6); 127 128 System.getProperties().put("country", "UK"); 129 try { 130 ac.refresh(); 131 132 TestBean tb0 = ac.getBean("tb0", TestBean.class); 133 134 TestBean tb1 = ac.getBean("tb1", TestBean.class); 135 assertEquals("XXXmyNameYYY42ZZZ", tb1.getName()); 136 assertEquals(42, tb1.getAge()); 137 138 TestBean tb2 = ac.getBean("tb2", TestBean.class); 139 assertEquals("{ XXXmyNameYYY42ZZZ }", tb2.getName()); 140 assertEquals(42, tb2.getAge()); 141 assertEquals("123 UK", tb2.getCountry()); 142 143 ValueTestBean tb3 = ac.getBean("tb3", ValueTestBean.class); 144 assertEquals("XXXmyNameYYY42ZZZ", tb3.name); 145 assertEquals(42, tb3.age); 146 assertEquals("123 UK", tb3.country); 147 assertEquals("123 UK", tb3.countryFactory.getObject()); 148 System.getProperties().put("country", "US"); 149 assertEquals("123 UK", tb3.country); 150 assertEquals("123 US", tb3.countryFactory.getObject()); 151 System.getProperties().put("country", "UK"); 152 assertEquals("123 UK", tb3.country); 153 assertEquals("123 UK", tb3.countryFactory.getObject()); 154 assertSame(tb0, tb3.tb); 155 156 tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3); 157 assertEquals("123 UK", tb3.countryFactory.getObject()); 158 159 ConstructorValueTestBean tb4 = ac.getBean("tb4", ConstructorValueTestBean.class); 160 assertEquals("XXXmyNameYYY42ZZZ", tb4.name); 161 assertEquals(42, tb4.age); 162 assertEquals("123 UK", tb4.country); 163 assertSame(tb0, tb4.tb); 164 165 MethodValueTestBean tb5 = ac.getBean("tb5", MethodValueTestBean.class); 166 assertEquals("XXXmyNameYYY42ZZZ", tb5.name); 167 assertEquals(42, tb5.age); 168 assertEquals("123 UK", tb5.country); 169 assertSame(tb0, tb5.tb); 170 171 PropertyValueTestBean tb6 = ac.getBean("tb6", PropertyValueTestBean.class); 172 assertEquals("XXXmyNameYYY42ZZZ", tb6.name); 173 assertEquals(42, tb6.age); 174 assertEquals("123 UK", tb6.country); 175 assertSame(tb0, tb6.tb); 176 } 177 finally { 178 System.getProperties().remove("country"); 179 } 180 } 181 182 @Test prototypeCreationReevaluatesExpressions()183 public void prototypeCreationReevaluatesExpressions() { 184 GenericApplicationContext ac = new GenericApplicationContext(); 185 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); 186 RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class); 187 rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); 188 rbd.getPropertyValues().add("country", "#{systemProperties.country}"); 189 rbd.getPropertyValues().add("country2", new TypedStringValue("#{systemProperties.country}")); 190 ac.registerBeanDefinition("test", rbd); 191 ac.refresh(); 192 193 try { 194 System.getProperties().put("name", "juergen1"); 195 System.getProperties().put("country", "UK1"); 196 PrototypeTestBean tb = (PrototypeTestBean) ac.getBean("test"); 197 assertEquals("juergen1", tb.getName()); 198 assertEquals("UK1", tb.getCountry()); 199 assertEquals("UK1", tb.getCountry2()); 200 201 System.getProperties().put("name", "juergen2"); 202 System.getProperties().put("country", "UK2"); 203 tb = (PrototypeTestBean) ac.getBean("test"); 204 assertEquals("juergen2", tb.getName()); 205 assertEquals("UK2", tb.getCountry()); 206 assertEquals("UK2", tb.getCountry2()); 207 } 208 finally { 209 System.getProperties().remove("name"); 210 System.getProperties().remove("country"); 211 } 212 } 213 214 @Test prototypeCreationIsFastEnough()215 public void prototypeCreationIsFastEnough() { 216 if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { 217 // Skip this test: Trace logging blows the time limit. 218 return; 219 } 220 GenericApplicationContext ac = new GenericApplicationContext(); 221 RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); 222 rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); 223 rbd.getConstructorArgumentValues().addGenericArgumentValue("#{systemProperties.name}"); 224 rbd.getPropertyValues().add("country", "#{systemProperties.country}"); 225 ac.registerBeanDefinition("test", rbd); 226 ac.refresh(); 227 StopWatch sw = new StopWatch(); 228 sw.start("prototype"); 229 System.getProperties().put("name", "juergen"); 230 System.getProperties().put("country", "UK"); 231 try { 232 for (int i = 0; i < 100000; i++) { 233 TestBean tb = (TestBean) ac.getBean("test"); 234 assertEquals("juergen", tb.getName()); 235 assertEquals("UK", tb.getCountry()); 236 } 237 sw.stop(); 238 } 239 finally { 240 System.getProperties().remove("country"); 241 System.getProperties().remove("name"); 242 } 243 assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000); 244 } 245 246 @Test systemPropertiesSecurityManager()247 public void systemPropertiesSecurityManager() { 248 GenericApplicationContext ac = new GenericApplicationContext(); 249 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); 250 251 GenericBeanDefinition bd = new GenericBeanDefinition(); 252 bd.setBeanClass(TestBean.class); 253 bd.getPropertyValues().add("country", "#{systemProperties.country}"); 254 ac.registerBeanDefinition("tb", bd); 255 256 SecurityManager oldSecurityManager = System.getSecurityManager(); 257 try { 258 System.setProperty("country", "NL"); 259 260 SecurityManager securityManager = new SecurityManager() { 261 @Override 262 public void checkPropertiesAccess() { 263 throw new AccessControlException("Not Allowed"); 264 } 265 @Override 266 public void checkPermission(Permission perm) { 267 // allow everything else 268 } 269 }; 270 System.setSecurityManager(securityManager); 271 ac.refresh(); 272 273 TestBean tb = ac.getBean("tb", TestBean.class); 274 assertEquals("NL", tb.getCountry()); 275 276 } 277 finally { 278 System.setSecurityManager(oldSecurityManager); 279 System.getProperties().remove("country"); 280 } 281 } 282 283 @Test stringConcatenationWithDebugLogging()284 public void stringConcatenationWithDebugLogging() { 285 GenericApplicationContext ac = new GenericApplicationContext(); 286 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); 287 288 GenericBeanDefinition bd = new GenericBeanDefinition(); 289 bd.setBeanClass(String.class); 290 bd.getConstructorArgumentValues().addGenericArgumentValue("test-#{ T(java.lang.System).currentTimeMillis() }"); 291 ac.registerBeanDefinition("str", bd); 292 ac.refresh(); 293 294 String str = ac.getBean("str", String.class); 295 assertTrue(str.startsWith("test-")); 296 } 297 298 299 public static class ValueTestBean implements Serializable { 300 301 @Autowired @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") 302 public String name; 303 304 @Autowired @Value("#{mySpecialAttr}") 305 public int age; 306 307 @Value("${code} #{systemProperties.country}") 308 public String country; 309 310 @Value("${code} #{systemProperties.country}") 311 public ObjectFactory<String> countryFactory; 312 313 @Autowired @Qualifier("original") 314 public transient TestBean tb; 315 } 316 317 318 public static class ConstructorValueTestBean { 319 320 public String name; 321 322 public int age; 323 324 public String country; 325 326 public TestBean tb; 327 328 @Autowired ConstructorValueTestBean( @alueR) String name, @Value(R) int age, @Qualifier(R) TestBean tb, @Value(R) String country)329 public ConstructorValueTestBean( 330 @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name, 331 @Value("#{mySpecialAttr}") int age, 332 @Qualifier("original") TestBean tb, 333 @Value("${code} #{systemProperties.country}") String country) { 334 this.name = name; 335 this.age = age; 336 this.country = country; 337 this.tb = tb; 338 } 339 } 340 341 342 public static class MethodValueTestBean { 343 344 public String name; 345 346 public int age; 347 348 public String country; 349 350 public TestBean tb; 351 352 @Autowired configure( @ualifierR) TestBean tb, @Value(R) String name, @Value(R) int age, @Value(R) String country)353 public void configure( 354 @Qualifier("original") TestBean tb, 355 @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name, 356 @Value("#{mySpecialAttr}") int age, 357 @Value("${code} #{systemProperties.country}") String country) { 358 this.name = name; 359 this.age = age; 360 this.country = country; 361 this.tb = tb; 362 } 363 } 364 365 366 public static class PropertyValueTestBean { 367 368 public String name; 369 370 public int age; 371 372 public String country; 373 374 public TestBean tb; 375 376 @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") setName(String name)377 public void setName(String name) { 378 this.name = name; 379 } 380 381 @Value("#{mySpecialAttr}") setAge(int age)382 public void setAge(int age) { 383 this.age = age; 384 } 385 386 @Value("${code} #{systemProperties.country}") setCountry(String country)387 public void setCountry(String country) { 388 this.country = country; 389 } 390 391 @Autowired @Qualifier("original") setTb(TestBean tb)392 public void setTb(TestBean tb) { 393 this.tb = tb; 394 } 395 } 396 397 398 public static class PrototypeTestBean { 399 400 public String name; 401 402 public String country; 403 404 public String country2; 405 406 @Value("#{systemProperties.name}") setName(String name)407 public void setName(String name) { 408 this.name = name; 409 } 410 getName()411 public String getName() { 412 return name; 413 } 414 setCountry(String country)415 public void setCountry(String country) { 416 this.country = country; 417 } 418 getCountry()419 public String getCountry() { 420 return country; 421 } 422 setCountry2(String country2)423 public void setCountry2(String country2) { 424 this.country2 = country2; 425 } 426 getCountry2()427 public String getCountry2() { 428 return country2; 429 } 430 } 431 432 } 433