1 15 package org.apache.hivemind.service.impl; 16 17 import hivemind.test.services.AbstractIntWrapper; 18 import hivemind.test.services.FailService; 19 import hivemind.test.services.SimpleService; 20 21 import java.io.IOException ; 22 import java.io.Serializable ; 23 import java.lang.reflect.Constructor ; 24 import java.lang.reflect.Modifier ; 25 import java.util.List ; 26 import java.util.Map ; 27 import java.util.zip.DataFormatException ; 28 29 import javassist.CtClass; 30 import junit.framework.AssertionFailedError; 31 32 import org.apache.hivemind.ApplicationRuntimeException; 33 import org.apache.hivemind.impl.BaseLocatable; 34 import org.apache.hivemind.service.ClassFab; 35 import org.apache.hivemind.service.MethodFab; 36 import org.apache.hivemind.service.MethodSignature; 37 import org.apache.hivemind.test.HiveMindTestCase; 38 import org.apache.hivemind.util.PropertyUtils; 39 40 46 public class TestClassFab extends HiveMindTestCase 47 { 48 private CtClassSource _source; 49 50 protected void setUp() throws Exception 51 { 52 super.setUp(); 53 54 ClassLoader threadLoader = Thread.currentThread().getContextClassLoader(); 55 56 HiveMindClassPool pool = new HiveMindClassPool(); 57 58 pool.appendClassLoader(threadLoader); 59 60 _source = new CtClassSource(pool); 61 } 62 63 private ClassFab newClassFab(String className, Class superClass) 64 { 65 CtClass ctClass = _source.newClass(className, superClass); 66 67 return new ClassFabImpl(_source, ctClass); 68 } 69 70 public void testCreateBean() throws Exception 71 { 72 ClassFab cf = newClassFab("TargetBean", Object .class); 73 74 cf.addField("_stringValue", String .class); 75 76 MethodSignature setStringValue = new MethodSignature(void.class, "setStringValue", 77 new Class [] 78 { String .class }, null); 79 80 cf.addMethod(Modifier.PUBLIC, setStringValue, "_stringValue = $1;"); 81 82 MethodSignature getStringValue = new MethodSignature(String .class, "getStringValue", null, 83 null); 84 85 cf.addMethod(Modifier.PUBLIC, getStringValue, "return _stringValue;"); 86 87 Class targetClass = cf.createClass(); 88 89 Object targetBean = targetClass.newInstance(); 90 91 PropertyUtils.write(targetBean, "stringValue", "Fred"); 92 93 String actual = (String ) PropertyUtils.read(targetBean, "stringValue"); 94 95 assertEquals("Fred", actual); 96 } 97 98 public void testConstructor() throws Exception 99 { 100 ClassFab cf = newClassFab("ConstructableBean", Object .class); 101 102 cf.addField("_stringValue", String .class); 103 cf.addConstructor(new Class [] 104 { String .class }, null, "{ _stringValue = $1; }"); 105 106 MethodSignature getStringValue = new MethodSignature(String .class, "getStringValue", null, 107 null); 108 109 cf.addMethod(Modifier.PUBLIC, getStringValue, "return _stringValue;"); 110 111 Class targetClass = cf.createClass(); 112 113 try 114 { 115 targetClass.newInstance(); 116 unreachable(); 117 } 118 catch (InstantiationException ex) 119 { 120 } 121 122 Constructor c = targetClass.getConstructors()[0]; 123 124 Object targetBean = c.newInstance(new Object [] 125 { "Buffy" }); 126 127 String actual = (String ) PropertyUtils.read(targetBean, "stringValue"); 128 129 assertEquals("Buffy", actual); 130 } 131 132 public void testConstructorFromBaseClass() throws Exception 133 { 134 ClassFab cf = newClassFab("MyIntHolder", AbstractIntWrapper.class); 135 136 cf.addField("_intValue", int.class); 137 cf.addConstructor(new Class [] 138 { int.class }, null, "{ _intValue = $1; }"); 139 140 cf.addMethod( 141 Modifier.PUBLIC, 142 new MethodSignature(int.class, "getIntValue", null, null), 143 "return _intValue;"); 144 145 Class targetClass = cf.createClass(); 146 Constructor c = targetClass.getConstructors()[0]; 147 148 AbstractIntWrapper targetBean = (AbstractIntWrapper) c.newInstance(new Object [] 149 { new Integer (137) }); 150 151 assertEquals(137, targetBean.getIntValue()); 152 } 153 154 public void testInvalidSuperClass() throws Exception 155 { 156 ClassFab cf = newClassFab("InvalidSuperClass", List .class); 157 158 try 159 { 160 cf.createClass(); 161 unreachable(); 162 } 163 catch (ApplicationRuntimeException ex) 164 { 165 assertExceptionSubstring(ex, "Unable to create class InvalidSuperClass"); 166 } 167 } 168 169 public void testAddInterface() throws Exception 170 { 171 ClassFab cf = newClassFab("SimpleService", Object .class); 172 173 cf.addInterface(SimpleService.class); 174 175 cf.addMethod(Modifier.PUBLIC, new MethodSignature(int.class, "add", new Class [] 176 { int.class, int.class }, null), "return $1 + $2;"); 177 178 Class targetClass = cf.createClass(); 179 180 SimpleService s = (SimpleService) targetClass.newInstance(); 181 182 assertEquals(207, s.add(99, 108)); 183 } 184 185 public void testSubclassFromFinal() throws Exception 186 { 187 ClassFab cf = newClassFab("StringSubclass", String .class); 188 189 try 190 { 191 cf.createClass(); 192 } 193 catch (ApplicationRuntimeException ex) 194 { 195 assertExceptionRegexp( 196 ex, 197 "Unable to create class StringSubclass\\:.*Cannot inherit from final class"); 198 } 199 } 200 201 public void testInPackage() throws Exception 202 { 203 ClassFab cf = newClassFab("org.apache.hivemind.InPackage", Object .class); 204 205 Class c = cf.createClass(); 206 207 Object o = c.newInstance(); 208 209 assertEquals("org.apache.hivemind.InPackage", o.getClass().getName()); 210 } 211 212 public void testBadMethodBody() throws Exception 213 { 214 ClassFab cf = newClassFab("BadMethodBody", Object .class); 215 216 cf.addInterface(Runnable .class); 217 218 try 219 { 220 cf.addMethod( 221 Modifier.PUBLIC, 222 new MethodSignature(void.class, "run", null, null), 223 "fail;"); 224 } 225 catch (ApplicationRuntimeException ex) 226 { 227 assertExceptionSubstring(ex, "Unable to add method void run() to class BadMethodBody:"); 228 } 229 } 230 231 public void testGetMethodFab() throws Exception 232 { 233 ClassFab cf = newClassFab("GetMethodFab", Object .class); 234 235 MethodSignature s = new MethodSignature(void.class, "run", null, null); 236 MethodFab mf = cf.addMethod(Modifier.PUBLIC, s, null); 237 238 assertSame(mf, cf.getMethodFab(s)); 239 240 assertNull(cf.getMethodFab(new MethodSignature(void.class, "skip", null, null))); 241 } 242 243 public void testExtendMethod() throws Exception 244 { 245 ClassFab cf = newClassFab("ExtendMethod", Object .class); 246 247 MethodFab mf = cf.addMethod(Modifier.PUBLIC, new MethodSignature(int.class, "getValue", 248 null, null), "return 1;"); 249 250 mf.extend("return 2 * $_;", false); 251 252 Object bean = cf.createClass().newInstance(); 253 254 assertEquals(new Integer (2), PropertyUtils.read(bean, "value")); 255 } 256 257 public void testExtendMethodAlterReturn() throws Exception 258 { 259 ClassFab cf = newClassFab("ExtendMethodAlterReturn", Object .class); 260 261 MethodFab mf = cf.addMethod(Modifier.PUBLIC, new MethodSignature(int.class, "getValue", 262 null, null), "return 2;"); 263 264 mf.extend("$_ = 3 * $_;", false); 265 266 Object bean = cf.createClass().newInstance(); 267 268 assertEquals(new Integer (6), PropertyUtils.read(bean, "value")); 269 } 270 271 public void testExtendMethodFailure() throws Exception 272 { 273 ClassFab cf = newClassFab("ExtendMethodFailure", Object .class); 274 275 MethodFab mf = cf.addMethod(Modifier.PUBLIC, new MethodSignature(int.class, "getValue", 276 null, null), "return 1;"); 277 278 try 279 { 280 mf.extend("$_ =", true); 281 unreachable(); 282 } 283 catch (ApplicationRuntimeException ex) 284 { 285 assertExceptionSubstring( 286 ex, 287 "Unable to extend method int getValue() of class ExtendMethodFailure:"); 288 } 289 } 290 291 public void testDupeMethodAdd() throws Exception 292 { 293 ClassFab cf = newClassFab("DupeMethodAdd", Object .class); 294 295 cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "foo", null, null), "{}"); 296 297 try 298 { 299 cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "foo", null, null), "{}"); 300 unreachable(); 301 } 302 catch (ApplicationRuntimeException ex) 303 { 304 assertEquals("Attempt to redefine method void foo() of class DupeMethodAdd.", ex 305 .getMessage()); 306 } 307 } 308 309 public void testBadConstructor() throws Exception 310 { 311 ClassFab cf = newClassFab("BadConstructor", Object .class); 312 313 try 314 { 315 cf.addConstructor(null, null, " woops!"); 316 } 317 catch (ApplicationRuntimeException ex) 318 { 319 assertExceptionSubstring(ex, "Unable to add constructor to class BadConstructor"); 320 } 321 322 } 323 324 public void testCatchException() throws Exception 325 { 326 ClassFab cf = newClassFab("Fail", Object .class); 327 328 cf.addInterface(FailService.class); 329 330 MethodFab mf = cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "fail", null, 331 null), "throw new java.lang.RuntimeException(\"Ouch!\");"); 332 333 mf.addCatch(RuntimeException .class, "throw new java.io.IOException($e.getMessage());"); 334 335 Class targetClass = cf.createClass(); 336 337 FailService fs = (FailService) targetClass.newInstance(); 338 339 try 340 { 341 fs.fail(); 342 unreachable(); 343 } 344 catch (IOException ex) 345 { 346 assertEquals("Ouch!", ex.getMessage()); 347 } 348 } 349 350 public void testBadCatch() throws Exception 351 { 352 ClassFab cf = newClassFab("BadCatch", Object .class); 353 354 cf.addInterface(Runnable .class); 355 356 MethodFab mf = cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "run", null, 357 null), "return;"); 358 359 try 360 { 361 mf.addCatch(RuntimeException .class, "woops!"); 362 unreachable(); 363 } 364 catch (ApplicationRuntimeException ex) 365 { 366 assertExceptionSubstring( 367 ex, 368 "Unable to add catch block for exception java.lang.RuntimeException to class BadCatch"); 369 } 370 } 371 372 public void testInvalidField() throws Exception 373 { 374 ClassFab cf = newClassFab("InvalidField", Object .class); 375 376 cf.addField(".", String .class); 377 cf.addField("buffy", int.class); 378 cf.addField("", int.class); 379 380 try 381 { 382 cf.createClass(); 383 unreachable(); 384 } 385 catch (ApplicationRuntimeException ex) 386 { 387 assertExceptionSubstring(ex, "Unable to create class InvalidField"); 388 } 389 390 } 393 394 395 public void testToString() throws Exception 396 { 397 ClassFab cf = newClassFab("FredRunnable", BaseLocatable.class); 398 399 cf.addInterface(Runnable .class); 400 cf.addInterface(Serializable .class); 401 402 cf.addField("_map", Map .class); 403 404 cf.addConstructor(new Class [] 405 { Map .class, Runnable .class }, new Class [] 406 { IllegalArgumentException .class, DataFormatException .class }, "{ _map = $1; }"); 407 408 MethodSignature sig = new MethodSignature(Map .class, "doTheNasty", new Class [] 409 { int.class, String .class }, new Class [] 410 { InstantiationException .class, IllegalAccessException .class }); 411 412 MethodFab mf = cf.addMethod( 413 Modifier.PUBLIC + Modifier.FINAL + Modifier.SYNCHRONIZED, 414 sig, 415 "{ return _map; }"); 416 417 mf.addCatch(NullPointerException .class, "return null;"); 418 mf.extend("_map.clear();", true); 419 420 String toString = cf.toString(); 421 422 contains( 423 toString, 424 "public class FredRunnable extends org.apache.hivemind.impl.BaseLocatable\n" 425 + " implements java.lang.Runnable, java.io.Serializable"); 426 427 contains(toString, "private java.util.Map _map;"); 428 429 contains( 430 toString, 431 "public FredRunnable(java.util.Map $1, java.lang.Runnable $2)\n" 432 + " throws java.lang.IllegalArgumentException, java.util.zip.DataFormatException\n" 433 + "{ _map = $1; }"); 434 435 contains( 436 toString, 437 "public final synchronized java.util.Map doTheNasty(int $1, java.lang.String $2)\n" 438 + " throws java.lang.InstantiationException, java.lang.IllegalAccessException\n" 439 + "{ return _map; }\n" + "catch(java.lang.NullPointerException $e)\n" 440 + "return null;\n" + "finally\n" + "_map.clear();"); 441 442 } 443 444 public void testCanConvert() 445 { 446 final ClassFab cf = newClassFab("BamBam", Object .class); 447 assertTrue( cf.canConvert( String .class ) ); 448 assertFalse(cf.canConvert(CglibBeanInterfaceFactory.createCglibBean().getClass())); 449 assertFalse(cf.canConvert(JavassistBeanInterfaceFactory.createJavassistBean().getClass())); 450 assertFalse(cf.canConvert(JdkBeanInterfaceFactory.createJdkBean().getClass())); 451 } 452 453 454 private void contains(String actual, String expected) 455 { 456 if (actual.indexOf(expected) < 0) 457 throw new AssertionFailedError("Missing substring: " + expected); 458 } 459 460 461 } | Popular Tags |