1 22 package org.jboss.xb.binding.group; 23 24 import java.lang.reflect.Constructor ; 25 import java.lang.reflect.Array ; 26 import java.util.Arrays ; 27 import java.util.Collection ; 28 import java.util.Iterator ; 29 import java.util.Map ; 30 31 import org.jboss.util.Classes; 32 import org.jboss.xb.binding.GenericValueContainer; 33 import org.jboss.xb.binding.JBossXBRuntimeException; 34 import org.jboss.xb.binding.sunday.unmarshalling.AttributeBinding; 35 import org.jboss.xb.binding.sunday.unmarshalling.AttributeHandler; 36 import org.jboss.xb.binding.sunday.unmarshalling.CharactersHandler; 37 import org.jboss.xb.binding.sunday.unmarshalling.ElementBinding; 38 import org.jboss.xb.binding.sunday.unmarshalling.ParticleBinding; 39 import org.jboss.xb.binding.sunday.unmarshalling.ParticleHandler; 40 import org.jboss.xb.binding.sunday.unmarshalling.TermBinding; 41 42 46 public interface ValueListHandler 47 { 48 ValueListHandler IMMUTABLE = new ValueListHandler() 49 { 50 public Object newInstance(ParticleBinding particle, ValueList valueList) 51 { 52 Class cls = valueList.getTargetClass(); 53 Map map = valueList.getNonRequiredValues(); 54 55 Collection values = map.values(); 56 if(values.isEmpty()) 57 { 58 throw new JBossXBRuntimeException("Value list does not contain non-required values."); 59 } 60 61 Constructor ctor = null; 62 Constructor [] ctors = cls.getConstructors(); 63 64 if(ctors == null || ctors.length == 0) 65 { 66 throw new JBossXBRuntimeException("The class has no declared constructors: " + cls); 67 } 68 69 for(int i = 0; i < ctors.length; ++i) 70 { 71 Class [] types = ctors[i].getParameterTypes(); 72 73 if(types == null || types.length == 0) 74 { 75 throw new IllegalStateException ("Found no-arg constructor for immutable " + cls); 76 } 77 78 if(types.length == map.size()) 79 { 80 ctor = ctors[i]; 81 82 int typeInd = 0; 83 Iterator iter = values.iterator(); 84 while(iter.hasNext()) 85 { 86 Class type = types[typeInd++]; 87 if(type.isPrimitive()) 88 { 89 type = Classes.getPrimitiveWrapper(type); 90 } 91 92 if(!type.isAssignableFrom(iter.next().getClass())) 93 { 94 ctor = null; 95 break; 96 } 97 } 98 99 if(ctor != null) 100 { 101 break; 102 } 103 } 104 } 105 106 if(ctor == null) 107 { 108 StringBuffer buf = new StringBuffer (); 109 buf.append("There is no ctor in ") 110 .append(cls) 111 .append(" that would take the following arguments:\n"); 112 int cnt = 0; 113 for(Iterator i = values.iterator(); i.hasNext();) 114 { 115 Object o = i.next(); 116 buf.append(' ').append(++cnt).append(") ").append(o.getClass()).append(": ").append(o).append('\n'); 117 } 118 throw new IllegalStateException (buf.toString()); 119 } 120 121 try 122 { 123 return ctor.newInstance(values.toArray()); 124 } 125 catch(Exception e) 126 { 127 throw new IllegalStateException ("Failed to create immutable instance of " + 128 cls + 129 " using arguments: " 130 + values + ": " + e.getMessage() 131 ); 132 } 133 } 134 }; 135 136 ValueListHandler NON_DEFAULT_CTOR = new ValueListHandler() 137 { 138 public Object newInstance(ParticleBinding particle, ValueList valueList) 139 { 140 Class cls = valueList.getTargetClass(); 141 int size = valueList.size(); 142 143 if(size == 0) 144 { 145 try 146 { 147 return newInstance(cls.getConstructor(null), null); 148 } 149 catch(NoSuchMethodException e) 150 { 151 throw new JBossXBRuntimeException( 152 "Value list does not contain non-required values and there is no no-arg ctor in " + cls 153 ); 154 } 155 } 156 157 Constructor ctor = matchBestCtor(cls, valueList); 158 159 if(ctor == null) 160 { 161 StringBuffer buf = new StringBuffer (); 162 buf.append("Failed to find no-arg ctor or best-match ctor in ") 163 .append(cls) 164 .append(", property values:\n"); 165 int cnt = 0; 166 for(int i = 0; i < size; ++i) 167 { 168 Object o = valueList.getValue(i).value; 169 buf.append(' ').append(++cnt).append(") ").append(o).append('\n'); 170 } 171 throw new JBossXBRuntimeException(buf.toString()); 172 } 173 174 Object o; 175 int argsTotal = ctor.getParameterTypes().length; 176 if(argsTotal == size) 177 { 178 Object [] args = getArgs(ctor, valueList); 179 o = newInstance(ctor, args); 180 } 181 else 182 { 183 Object [] args = getArgs(ctor, valueList); 184 o = newInstance(ctor, args); 185 186 int i = argsTotal; 187 while(i < size) 188 { 189 ValueList.NonRequiredValue valueEntry = valueList.getValue(i++); 190 Object binding = valueEntry.binding; 191 if(binding instanceof ParticleBinding) 192 { 193 Object handler = valueEntry.handler; 194 ParticleBinding childParticle = (ParticleBinding)binding; 195 if(handler instanceof ParticleHandler) 196 { 197 ParticleHandler pHandler = (ParticleHandler)handler; 198 if(childParticle.isRepeatable()) 199 { 200 TermBinding term = childParticle.getTerm(); 201 if(!(o instanceof GenericValueContainer) && 202 term.getAddMethodMetaData() == null && 203 term.getMapEntryMetaData() == null && 204 term.getPutMethodMetaData() == null) 205 { 206 pHandler.setParent(o, valueEntry.value, valueEntry.qName, childParticle, particle); 207 } 208 else 209 { 210 Collection col = (Collection )valueEntry.value; 211 for(Iterator iter = col.iterator(); iter.hasNext();) 212 { 213 pHandler.setParent(o, iter.next(), valueEntry.qName, childParticle, particle); 214 } 215 } 216 } 217 else 218 { 219 pHandler.setParent(o, valueEntry.value, valueEntry.qName, childParticle, particle); 220 } 221 } 222 else 223 { 224 ((CharactersHandler)handler).setValue(valueEntry.qName, 225 (ElementBinding)childParticle.getTerm(), 226 o, 227 valueEntry.value 228 ); 229 } 230 } 231 else if(binding instanceof AttributeBinding) 232 { 233 AttributeBinding attr = (AttributeBinding)binding; 234 AttributeHandler handler = attr.getHandler(); 235 if(handler != null) 236 { 237 handler.attribute(valueEntry.qName, attr.getQName(), attr, o, valueEntry.value); 238 } 239 else 240 { 241 throw new JBossXBRuntimeException("Attribute binding present but has no handler: element=" + 242 valueEntry.qName + 243 ", attrinute=" + 244 attr.getQName() 245 ); 246 } 247 } 248 else 249 { 250 throw new JBossXBRuntimeException("Unexpected binding type: " + binding); 251 } 252 } 253 } 254 255 return o; 256 } 257 258 private Constructor matchBestCtor(Class cls, ValueList valueList) 259 { 260 Constructor bestMatch = null; 261 int bestMatchArgsTotal = 0; 262 Constructor [] ctors = cls.getConstructors(); 263 int size = valueList.size(); 264 265 for(int i = 0; i < ctors.length; ++i) 266 { 267 Constructor ctor = ctors[i]; 268 Class [] types = ctor.getParameterTypes(); 269 270 if((types == null || types.length == 0) && bestMatch == null) 271 { 272 bestMatch = ctor; 273 continue; 274 } 275 276 if(bestMatchArgsTotal <= types.length) 277 { 278 int typeInd = 0; 279 for(int valueInd = 0; typeInd < types.length && valueInd < size; ++typeInd, ++valueInd) 280 { 281 Class type = types[typeInd]; 282 if(type.isPrimitive()) 283 { 284 type = Classes.getPrimitiveWrapper(type); 285 } 286 287 ValueList.NonRequiredValue valueEntry = valueList.getValue(valueInd); 288 Object value = valueEntry.value; 289 if(value != null && 290 !(type.isAssignableFrom(value.getClass()) || 291 valueEntry.binding instanceof ParticleBinding && 295 ((ParticleBinding)valueEntry.binding).isRepeatable() && 296 type.isArray() 297 )) 298 { 299 break; 300 } 301 302 if(bestMatchArgsTotal == types.length && 303 !bestMatch.getParameterTypes()[typeInd].isAssignableFrom(type)) 304 { 305 break; 306 } 307 } 308 309 if(typeInd == types.length) 310 { 311 bestMatch = ctor; 312 bestMatchArgsTotal = types.length; 313 } 314 } 315 } 316 return bestMatch; 317 } 318 319 private Object newInstance(Constructor bestMatch, Object [] args) 320 { 321 try 322 { 323 return bestMatch.newInstance(args); 324 } 325 catch(Exception e) 326 { 327 throw new JBossXBRuntimeException("Failed to create an instance of " + 328 bestMatch.getDeclaringClass() + 329 " using the following ctor arguments " + 330 Arrays.asList(args), e 331 ); 332 } 333 } 334 335 private Object [] getArgs(Constructor ctor, ValueList valueList) 336 { 337 Class [] types = ctor.getParameterTypes(); 338 Object [] args = new Object [types.length]; 339 for(int i = 0; i < types.length; ++i) 340 { 341 ValueList.NonRequiredValue valueEntry = valueList.getValue(i); 342 Object arg = valueEntry.value; 343 if(valueEntry.value != null && !types[i].isAssignableFrom(arg.getClass())) 344 { 345 if(types[i].isArray() && Collection .class.isAssignableFrom(arg.getClass())) 348 { 349 Collection col = (Collection )arg; 350 arg = Array.newInstance(types[i].getComponentType(), col.size()); 351 int arrInd = 0; 352 for(Iterator iter = col.iterator(); iter.hasNext();) 353 { 354 Array.set(arg, arrInd++, iter.next()); 355 } 356 } 357 } 358 args[i] = arg; 359 } 360 return args; 361 } 362 }; 363 364 class FACTORY 365 { 366 372 public static ValueListHandler lazy(final Object parent) 373 { 374 return new ValueListHandler() 375 { 376 private final ValueList parentValueList = parent instanceof ValueList ? (ValueList)parent : null; 377 378 public Object newInstance(ParticleBinding particle, ValueList valueList) 379 { 380 for(int i = 0; i < valueList.size(); ++i) 381 { 382 ValueList.NonRequiredValue valueEntry = valueList.getValue(i); 383 Object binding = valueEntry.binding; 384 if(binding instanceof ParticleBinding) 385 { 386 Object handler = valueEntry.handler; 387 ParticleBinding childParticle = (ParticleBinding)binding; 388 if(handler instanceof ParticleHandler) 389 { 390 ParticleHandler pHandler = (ParticleHandler)handler; 391 if(childParticle.isRepeatable()) 392 { 393 if(parentValueList != null) 394 { 395 parentValueList.addTermValue(valueEntry.qName, childParticle, pHandler, valueEntry.value, null); 396 } 397 else 398 { 399 Collection col = (Collection ) valueEntry.value; 400 pHandler.setParent(parent, col, valueEntry.qName, childParticle, valueEntry.parentParticle); 402 403 409 } 410 } 411 else 412 { 413 if(parentValueList != null) 414 { 415 parentValueList.addTermValue(valueEntry.qName, childParticle, pHandler, valueEntry.value, valueEntry.parentParticle); 416 } 417 else 418 { 419 pHandler.setParent(parent, valueEntry.value, valueEntry.qName, childParticle, valueEntry.parentParticle); 420 } 421 } 422 } 423 else 424 { 425 CharactersHandler cHandler = (CharactersHandler)handler; 426 if(parentValueList != null) 427 { 428 parentValueList.addTextValue(valueEntry.qName, childParticle, cHandler, valueEntry.value); 429 } 430 else 431 { 432 cHandler.setValue(valueEntry.qName, (ElementBinding) childParticle.getTerm(), parent, valueEntry.value); 433 } 434 } 435 } 436 else if(binding instanceof AttributeBinding) 437 { 438 AttributeBinding attr = (AttributeBinding)binding; 439 AttributeHandler handler = attr.getHandler(); 440 if(handler != null) 441 { 442 if(parentValueList != null) 443 { 444 parentValueList.setAttributeValue(attr.getQName(), attr, valueEntry.value); 445 } 446 else 447 { 448 handler.attribute(valueEntry.qName, attr.getQName(), attr, parent, valueEntry.value); 449 } 450 } 451 else 452 { 453 throw new JBossXBRuntimeException("Attribute binding present but has no handler: element=" + 454 valueEntry.qName + 455 ", attrinute=" + 456 attr.getQName() 457 ); 458 } 459 } 460 else 461 { 462 throw new JBossXBRuntimeException("Unexpected binding type: " + binding); 463 } 464 } 465 466 return parent; 467 } 468 }; 469 } 470 471 public static ValueListHandler child() 472 { 473 return new ValueListHandler() 474 { 475 public Object newInstance(ParticleBinding particle, ValueList valueList) 476 { 477 if(valueList.size() > 1) 478 { 479 String msg = "Expected only one child for " + particle.getTerm() + " but got:"; 480 for(int i = 0; i < valueList.size(); ++i) 481 { 482 ValueList.NonRequiredValue valueEntry = valueList.getValue(0); 483 msg += " " + valueEntry.value + ";"; 484 } 485 throw new JBossXBRuntimeException(msg); 486 } 487 488 ValueList.NonRequiredValue valueEntry = valueList.getValue(0); 489 return valueEntry.value; 490 } 491 }; 492 } 493 }; 494 495 Object newInstance(ParticleBinding particle, ValueList valueList); 496 } 497 | Popular Tags |