001package arcommon.xml; 002 003import java.io.IOException; 004import java.io.Serializable; 005import java.lang.reflect.Array; 006import java.lang.reflect.Field; 007import java.lang.reflect.Method; 008import java.text.ParseException; 009import java.util.ArrayList; 010import java.util.Collection; 011import java.util.Date; 012import java.util.HashMap; 013import java.util.List; 014import java.util.Map; 015import java.util.Stack; 016 017import org.xml.sax.Attributes; 018 019import arcommon.ReflectionUtil; 020import arcommon.StringUtil; 021import arcommon.xml.XmlSerializerHelperUtil.SpeciallyHandlingType; 022 023/** 024 * Deserializes XML in a pretty printed human-readable form to an object. 025 * <br> 026 * For XML format see {@link XmlSerializer}.*/ 027public class XmlDeserializer extends AbstractSaxParser { 028 029 private static class StateData { 030 public Object object; 031 public Field field; 032 public boolean fieldIsMissing; 033 public boolean fieldClassIsMissing; 034 public int arrayIndex; 035 @SuppressWarnings("rawtypes") 036 public Collection collection; 037 @SuppressWarnings("rawtypes") 038 public Map map; 039 public Object entryKeyObject; 040 public String entryKeyReference; 041 public boolean entryKeyIsSet; 042 public Object entryValueObject; 043 public String entryValueReference; 044 public boolean entryClassIsMissing; 045 public Type type; 046 public boolean classIsMissing; 047 048 public boolean specialHandling; 049 public Class<?> specialHandlingClass; 050 public ArrayList<Update> specialHandlingUpdates; 051 public ArrayList<SpecialHandlingData> specialHandlingDatas; 052 053 public ArrayList<Update> afterArrayCollectionMapUpdates; 054 055 public void addAfterArrayCollectionMapUpdate(Update update) { 056 if (afterArrayCollectionMapUpdates == null) { 057 afterArrayCollectionMapUpdates = new ArrayList<Update>(); 058 } 059 afterArrayCollectionMapUpdates.add(update); 060 } 061 062 @Override 063 public String toString() { 064 return type + " " + object + " " + field; 065 } 066 } 067 068 private enum Type {OBJECT, ARRAY, COLLECTION, MAP}; 069 070 /*package*/ static class Update { 071 public Type type; 072 public Object object; 073 public Field field; 074 public int arrayIndex; 075 @SuppressWarnings("rawtypes") 076 public Collection collection; 077 @SuppressWarnings("rawtypes") 078 public Map map; 079 public Object keyObject; 080 public String keyReferenceId; 081 public Object value; 082 public String referenceId; 083 084 public boolean specialHandling; 085 public Class<?> specialHandlingClass; 086 public ArrayList<Update> specialHandlingUpdates; 087 public ArrayList<SpecialHandlingData> specialHandlingDatas; 088 089 @Override 090 public String toString() { 091 return type + " " + object + " " + field + " " + referenceId; 092 } 093 } 094 095 /*package*/ static class SpecialHandlingData { 096 public Class<?> clazz; 097 public Object value; 098 public int index; 099 public String referenceId; 100 101 @Override 102 public String toString() { 103 return ReflectionUtil.classToClassNameInJavaSyntax(clazz) + ": " + value; 104 } 105 } 106 107 private Serializable resultObject; 108 private StateData currentData; 109 private Stack<StateData> dataStack; 110 private Map<String, Object> idToObjectMap; 111 private XmlDeserializerMapper xmlDeserializerMapper; 112 113 private List<Update> updates; 114 115 private boolean inSpecialHandlingObject; 116 117 private boolean done; 118 119 private int xmlVersion; 120 121 public XmlDeserializer() { 122 dataStack = new Stack<StateData>(); 123 idToObjectMap = new HashMap<String, Object>(); 124 xmlDeserializerMapper = new XmlDeserializerMapper(this); 125 126 updates = new ArrayList<Update>(); 127 128 inSpecialHandlingObject = false; 129 } 130 131 @Override 132 public void startElement(String qName, Attributes attributes, int childIndex) { 133 try { 134 if (qName.equals(XmlSerializerHelperUtil.TAG_OBJECT)) { 135 handleObjectTag(attributes); 136 } else if (qName.equals(XmlSerializerHelperUtil.TAG_FIELD)) { 137 handleFieldTag(attributes); 138 } else if (qName.equals(XmlSerializerHelperUtil.TAG_ENTRY)) { 139 handleEntryTag(attributes); 140 } else if (qName.equals(XmlSerializerHelperUtil.TAG_SPECIAL_HANDLING)) { 141 handleSpecialHandling(attributes); 142 } else if (qName.equals(XmlSerializerHelperUtil.TAG_DATA)) { 143 handleData(attributes); 144 } else if (qName.equals(XmlSerializerHelperUtil.TAG_NULL_ELEMENT)) { 145 handleNullElement(); 146 } else if (qName.equals(XmlSerializerHelperUtil.TAG_XML_SERIALIZER)) { 147 handleXmlSerializerElement(attributes); 148 } else { 149 throw new RuntimeException("Unknown tag \"" + qName + "\""); 150 } 151 } catch (RuntimeException e) { 152 throw e; 153 } catch (Exception e) { 154 throw new RuntimeException(e); 155 } 156 } 157 158 private void handleObjectTag(Attributes attributes) throws ParseException { 159 if (currentData != null) { 160 dataStack.push(currentData); 161 } 162 163 currentData = new StateData(); 164 165 Object newObject; 166 String className = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_CLASS); 167 if (className == null) { 168 String reference = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_REFERENCE); 169 if (reference == null) { 170 throw new RuntimeException(XmlSerializerHelperUtil.ATTRIBUTE_REFERENCE + " == null"); 171 } 172 StateData parentData = dataStack.get(dataStack.size() - 1); 173 if (parentData == null) { 174 throw new RuntimeException("parentData == null"); 175 } 176 if (parentData.type == null) { 177 throw new RuntimeException("parentData.type == null"); 178 } 179 Update update; 180 switch (parentData.type) { 181 case ARRAY : 182 update = new Update(); 183 update.type = Type.ARRAY; 184 update.object = parentData.object; 185 update.arrayIndex = parentData.arrayIndex++; 186 update.referenceId = reference; 187 parentData.addAfterArrayCollectionMapUpdate(update); 188 break; 189 case COLLECTION : 190 update = new Update(); 191 update.type = Type.COLLECTION; 192 update.collection = parentData.collection; 193 update.referenceId = reference; 194 parentData.addAfterArrayCollectionMapUpdate(update); 195 break; 196 case MAP : 197 if (!parentData.entryKeyIsSet) { 198 parentData.entryKeyIsSet = true; 199 if (parentData.entryKeyReference != null) { 200 throw new RuntimeException("parentData.entryKeyReference != null"); 201 } 202 parentData.entryKeyReference = reference; 203 } else { 204 if (parentData.entryValueReference != null) { 205 throw new RuntimeException("parentData.entryValueReference != null"); 206 } 207 parentData.entryValueReference = reference; 208 } 209 break; 210 default : 211 throw new RuntimeException("Unknown type " + parentData.type); 212 } 213 return ; 214 } 215 216 Class<?> clazz = xmlDeserializerMapper.loadClassWithLogLevel(className); 217 if (clazz == null) { 218 currentData.classIsMissing = true; 219 return ; 220 } 221 222 String xmlSerialVersionUIDString = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_SERIAL_VERSION_UID); 223 if (xmlSerialVersionUIDString != null) { 224 if (!StringUtil.isStringALong(xmlSerialVersionUIDString)) { 225 throw new RuntimeException("xmlSerialVersionUID is not a number for class " + clazz.getName() + ", xmlSerialVersionUID: " + xmlSerialVersionUIDString); 226 } 227 Long codeSerialVersionUID = XmlSerializerHelperUtil.getSerialVersionUID(clazz); 228 Long xmlSerialVersionUID = Long.valueOf(xmlSerialVersionUIDString); 229 if (!codeSerialVersionUID.equals(xmlSerialVersionUID)) { 230 throw new RuntimeException("!codeSerialVersionUID.equals(xmlSerialVersionUID) for class " + clazz.getName() + ", codeSerialVersionUID: " + codeSerialVersionUID + ", xmlSerialVersionUID: " + xmlSerialVersionUID); 231 } 232 } 233 234 boolean isDate = Date.class.isAssignableFrom(clazz); 235 if (clazz != null && (XmlSerializerHelperUtil.isSimpleClass(clazz) || isDate)) { 236 String value = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE); 237 String length = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_LENGTH); 238 newObject = stringValueToSimpleObject(clazz, value, length); 239 } else { 240 if (XmlSerializerHelperUtil.calculateSpeciallyHandlingTypeForHierarchy(clazz) != SpeciallyHandlingType.NONE) { 241 newObject = ReflectionUtil.createInstanceDefaultPrivateConstructor(clazz); 242 } else { 243 if (clazz.isArray()) { 244 String lengthString = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_LENGTH); 245 if (lengthString == null) { 246 throw new RuntimeException("lengthString == null"); 247 } 248 int length = StringUtil.stringToInt(lengthString); 249 newObject = Array.newInstance(clazz.getComponentType(), length); 250 } else { 251 Class<?> superSerializableClazz = XmlSerializerHelperUtil.findSuperSerializableClazz(clazz); 252 if (superSerializableClazz == null) { 253 throw new RuntimeException("Class " + ReflectionUtil.classToClassNameInJavaSyntax(clazz) + " doesn't have a super class that doesn't implementing Serializable"); 254 } 255 Class<?> superNonSerializableClazz = superSerializableClazz.getSuperclass(); 256 newObject = ReflectionUtil.createInstanceUsingParentConstructorOnlyUnsafe(clazz, superNonSerializableClazz); 257 } 258 } 259 } 260 261 if (resultObject == null) { 262 resultObject = (Serializable)newObject; 263 } 264 265 String id = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_ID); 266 if (id != null) { 267 addObjectAndId(id, newObject); 268 } 269 270 currentData.object = newObject; 271 if (currentData.object.getClass().isArray()) { 272 currentData.type = Type.ARRAY; 273 } else { 274 SpeciallyHandlingType speciallyHandlingType = XmlSerializerHelperUtil.calculateSpeciallyHandlingTypeForHierarchy(currentData.object.getClass()); 275 if (speciallyHandlingType == SpeciallyHandlingType.COLLECTION) { 276 currentData.type = Type.COLLECTION; 277 currentData.collection = (Collection<?>)newObject; 278 } else if (speciallyHandlingType == SpeciallyHandlingType.MAP) { 279 currentData.type = Type.MAP; 280 currentData.map = (Map<?, ?>)newObject; 281 } else { 282 currentData.type = Type.OBJECT; 283 } 284 } 285 286 if (dataStack.size() > 0) { 287 StateData parentData = dataStack.get(dataStack.size() - 1); 288 if (parentData.type != null && !parentData.fieldIsMissing && !parentData.fieldClassIsMissing) { 289 if (parentData.field != null) { 290 Update update = new Update(); 291 update.type = Type.OBJECT; 292 update.field = parentData.field; 293 update.object = parentData.object; 294 update.value = newObject; 295 if (parentData.specialHandling) { 296 parentData.specialHandlingUpdates.add(update); 297 } else { 298 updates.add(update); 299 } 300 301 parentData.field = null; 302 } else { 303 Update update; 304 switch (parentData.type) { 305 case OBJECT : 306 if (inSpecialHandlingObject) { 307 int size = parentData.specialHandlingDatas.size(); 308 SpecialHandlingData specialHandlingData = parentData.specialHandlingDatas.get(size - 1); 309 specialHandlingData.value = newObject; 310 } else { 311 throw new RuntimeException("currentType == Type.OBJECT"); 312 } 313 break; 314 case ARRAY : 315 update = new Update(); 316 update.type = Type.ARRAY; 317 update.object = parentData.object; 318 update.arrayIndex = parentData.arrayIndex++; 319 update.value = newObject; 320 parentData.addAfterArrayCollectionMapUpdate(update); 321 break; 322 case COLLECTION : 323 update = new Update(); 324 update.type = Type.COLLECTION; 325 update.collection = parentData.collection; 326 update.value = newObject; 327 parentData.addAfterArrayCollectionMapUpdate(update); 328 break; 329 case MAP : 330 if (!parentData.entryKeyIsSet) { 331 parentData.entryKeyIsSet = true; 332 parentData.entryKeyObject = newObject; 333 } else { 334 if (parentData.entryValueObject != null) { 335 throw new RuntimeException("parentData.entryValueObject != null"); 336 } 337 parentData.entryValueObject = newObject; 338 } 339 break; 340 default : 341 throw new RuntimeException("Unknown type " + parentData.type); 342// break; 343 } 344 } 345 } 346 } 347 } 348 349 private void handleFieldTag(Attributes attributes) throws ParseException { 350 if (currentData.classIsMissing) { 351 return ; 352 } 353 354 Class<?> currentObjectClass = currentData.object.getClass(); 355 356 Class<?> fieldClass = currentObjectClass; 357 String superClass = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_SUPER_CLASS); 358 if (superClass != null) { 359 fieldClass = xmlDeserializerMapper.loadClassWithLogLevel(superClass); 360 if (fieldClass == null) { 361 currentData.fieldClassIsMissing = true; 362 return ; 363 } 364 365 currentData.fieldClassIsMissing = false; 366 } 367 368 String name = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_NAME); 369 String reference = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_REFERENCE); 370 Field field = xmlDeserializerMapper.findField(fieldClass, name); 371 if (reference != null) { 372 if (field != null) { 373 Update update = new Update(); 374 update.type = Type.OBJECT; 375 update.field = field; 376 update.object = currentData.object; 377 update.referenceId = reference; 378 if (currentData.specialHandling) { 379 currentData.specialHandlingUpdates.add(update); 380 } else { 381 updates.add(update); 382 } 383 } 384 } else { 385 String value = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE); 386 String className = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_CLASS); 387 388 Class<?> valueClazz = null; 389 if (className != null) { 390 valueClazz = xmlDeserializerMapper.loadClassWithLogLevel(className); 391 } 392 if (valueClazz == null && value != null && field != null) { 393 valueClazz = field.getType(); // Simple class where the class attribute is missing. It is missing by design on subsequently field occurrences. 394 } 395 if (valueClazz == Date.class && value == null) { 396 valueClazz = null; // HACK 397 } 398 399 if (valueClazz != null && XmlSerializerHelperUtil.isSimpleClass(valueClazz)) { 400 String length = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_LENGTH); 401 Object newFieldValue = stringValueToSimpleObject(valueClazz, value, length); 402 if (field != null) { 403 Update update = new Update(); 404 update.type = Type.OBJECT; 405 update.field = field; 406 update.object = currentData.object; 407 update.value = newFieldValue; 408 if (currentData.specialHandling) { 409 currentData.specialHandlingUpdates.add(update); 410 } else { 411 updates.add(update); 412 } 413 } 414 415 String id = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_ID); 416 if (id != null) { 417 addObjectAndId(id, newFieldValue); 418 } 419 } else { 420 currentData.field = field; 421 currentData.fieldIsMissing = field == null; 422 } 423 } 424 } 425 426 private void handleEntryTag(Attributes attributes) throws ParseException { 427 String key = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_KEY_PREFIX); 428 String className = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_KEY_CLASS); 429 if (key != null || className != null) { 430 Class<?> clazz = xmlDeserializerMapper.loadClassWithLogLevel(className); 431 String length = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_KEY_LENGTH); 432 if (clazz != null) { 433 currentData.entryKeyObject = stringValueToSimpleObject(clazz, key, length); 434 } else { 435 currentData.entryClassIsMissing = true; 436 } 437 438 if (currentData.entryKeyIsSet) { 439 throw new RuntimeException("parentData.entryKeyIsSet"); 440 } 441 currentData.entryKeyIsSet = true; 442 443 String id = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_KEY_ID); 444 if (id != null) { 445 addObjectAndId(id, currentData.entryKeyObject); 446 } 447 } 448 449 String keyReference = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_KEY_REFERENCE); 450 if (keyReference != null) { 451 currentData.entryKeyReference = keyReference; 452 453 if (currentData.entryKeyIsSet) { 454 throw new RuntimeException("parentData.entryKeyIsSet"); 455 } 456 currentData.entryKeyIsSet = true; 457 } 458 459 String keyIsNull = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_KEY_IS_NULL); 460 if (keyIsNull != null) { 461 if (!keyIsNull.equals(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_TRUE)) { 462 throw new RuntimeException(XmlSerializerHelperUtil.ATTRIBUTE_KEY_IS_NULL + " != null && !" + XmlSerializerHelperUtil.ATTRIBUTE_KEY_IS_NULL + ".equals(\"" + XmlSerializerHelperUtil.ATTRIBUTE_VALUE_TRUE + "\") " + keyIsNull); 463 } 464 465 if (currentData.entryKeyIsSet) { 466 throw new RuntimeException("parentData.entryKeyIsSet"); 467 } 468 currentData.entryKeyIsSet = true; 469 } 470 471 String value = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_PREFIX); 472 className = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_CLASS); 473 if (value != null || className != null) { 474 Class<?> clazz = xmlDeserializerMapper.loadClassWithLogLevel(className); 475 String length = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_LENGTH); 476 if (clazz != null) { 477 currentData.entryValueObject = stringValueToSimpleObject(clazz, value, length); 478 } else { 479 currentData.entryClassIsMissing = true; 480 } 481 482 String id = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_ID); 483 if (id != null) { 484 addObjectAndId(id, currentData.entryValueObject); 485 } 486 } 487 488 String valueReference = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_REFERENCE); 489 if (valueReference != null) { 490 currentData.entryValueReference = valueReference; 491 } 492 } 493 494 private void handleSpecialHandling(Attributes attributes) { 495 if (currentData != null) { 496 dataStack.push(currentData); 497 } 498 499 StateData oldCurrentObject = currentData; 500 501 currentData = new StateData(); 502 currentData.object = oldCurrentObject.object; 503 currentData.type = oldCurrentObject.type; 504 currentData.specialHandling = true; 505 currentData.specialHandlingUpdates = new ArrayList<Update>(); 506 currentData.specialHandlingDatas = new ArrayList<SpecialHandlingData>(); 507 508 String className = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_CLASS); 509 currentData.specialHandlingClass = xmlDeserializerMapper.loadClassWithLogLevel(className); 510 } 511 512 private void handleData(Attributes attributes) throws ParseException { 513 SpecialHandlingData specialHandlingData = new SpecialHandlingData(); 514 String className = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_CLASS); 515 516 String dataObjectIsNull = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_DATA_OBJECT_IS_NULL); 517 518 String referenceId = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_REFERENCE); 519 520 if (className != null) { 521 specialHandlingData.clazz = xmlDeserializerMapper.loadClassWithLogLevel(className); 522 String value = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VALUE); 523 String length = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_LENGTH); 524 specialHandlingData.value = stringValueToSimpleObject(specialHandlingData.clazz, value, length); 525 526 String id = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_ID); 527 if (id != null) { 528 addObjectAndId(id, specialHandlingData.value); 529 } 530 } else if (referenceId != null) { 531 specialHandlingData.referenceId = referenceId; 532 } else if (dataObjectIsNull != XmlSerializerHelperUtil.ATTRIBUTE_VALUE_TRUE) { 533 inSpecialHandlingObject = true; 534 } 535 536 currentData.specialHandlingDatas.add(specialHandlingData); 537 } 538 539 private void handleNullElement() { 540 Update update; 541 switch (currentData.type) { 542 case ARRAY : 543 update = new Update(); 544 update.type = Type.ARRAY; 545 update.object = currentData.object; 546 update.arrayIndex = currentData.arrayIndex++; 547 update.value = null; 548 currentData.addAfterArrayCollectionMapUpdate(update); 549 break; 550 case COLLECTION : 551 update = new Update(); 552 update.type = Type.COLLECTION; 553 update.collection = currentData.collection; 554 update.value = null; 555 currentData.addAfterArrayCollectionMapUpdate(update); 556 break; 557 default : 558 throw new RuntimeException("currentData.type != ARRAY && currentData.type != COLLECTION " + currentData.type); 559// break; 560 } 561 } 562 563 private void handleXmlSerializerElement(Attributes attributes) { 564 if (xmlVersion > 0) { 565 throw new RuntimeException("Xml version is already set " + xmlVersion + ". Two XmlSerializer tags?"); 566 } 567 568 String versionString = attributes.getValue(XmlSerializerHelperUtil.ATTRIBUTE_VERSION); 569 if (!StringUtil.isStringAnInt(versionString)) { 570 throw new RuntimeException("Xml version is not a number " + versionString); 571 } 572 573 xmlVersion = StringUtil.stringToInt(versionString); 574 if (xmlVersion == 0 || xmlVersion > XmlSerializerHelperUtil.XML_VERSION_NUMBER) { 575 throw new RuntimeException("Wrong version number " + xmlVersion); 576 } 577 } 578 579 private void addObjectAndId(String id, Object newObject) { 580 if (idToObjectMap.containsKey(id)) { 581 throw new RuntimeException("idToObjectMap.containsKey(id) " + id); 582 } 583 idToObjectMap.put(id, newObject); 584 } 585 586 private Object stringValueToSimpleObject(Class<?> clazz, String value, String lengthString) throws ParseException { 587 Object newFieldValue = null; 588 if (clazz == Long.class || clazz == long.class) { 589 newFieldValue = Long.valueOf(value); 590 } else if (clazz == Integer.class || clazz == int.class) { 591 newFieldValue = Integer.valueOf(value); 592 } else if (clazz == Short.class || clazz == short.class) { 593 newFieldValue = Short.valueOf(value); 594 } else if (clazz == Byte.class || clazz == byte.class) { 595 newFieldValue = Byte.valueOf(value); 596 } else if (clazz == String.class) { 597 newFieldValue = StringUtil.javaConstantDecodeString(value); 598// newFieldValue = XmlUtil.decodeXmlString(newFieldValue); // No need to this here, as it has already been done by the SAX parser 599 } else if (clazz == Character.class || clazz == char.class) { 600 if (value.length() < 1 || value.length() > 6) { 601 throw new RuntimeException("value.length() < 1 || value.length() > 6 for " + clazz + ", value: \"" + value + "\""); 602 } 603 String c = StringUtil.javaConstantDecodeString(value); 604 newFieldValue = c.charAt(0); 605 } else if (clazz == Class.class) { 606 newFieldValue = xmlDeserializerMapper.loadClassWithLogLevel(value); 607 } else if (Date.class.isAssignableFrom(clazz)) { 608 newFieldValue = XmlSerializerHelperUtil.XML_DATE_TIME_FORMAT.parse(value); 609 if (clazz != Date.class) { 610 Date newObject = (Date)ReflectionUtil.createInstanceNoConstructorCall(clazz); 611 newObject.setTime(((Date)newFieldValue).getTime()); 612 newFieldValue = newObject; 613 } 614 } else if (clazz == Boolean.class || clazz == boolean.class) { 615 newFieldValue = Boolean.valueOf(value); 616 } else if (clazz == Double.class || clazz == double.class) { 617 newFieldValue = Double.valueOf(value); 618 } else if (clazz == Float.class || clazz == float.class) { 619 newFieldValue = Float.valueOf(value); 620 } else if (ReflectionUtil.isClassEnum(clazz)) { 621 if (value.equals(XmlSerializerHelperUtil.ENUM_NULL)) { 622 newFieldValue = null; 623 } else { 624 newFieldValue = ReflectionUtil.stringToEnum(clazz, value); 625 } 626 } else if (clazz.isArray()) { 627 if (lengthString == null) { 628 throw new RuntimeException("length == null"); 629 } 630 int length = StringUtil.stringToInt(lengthString); 631 newFieldValue = Array.newInstance(clazz.getComponentType(), length); 632 633 if (length < 0) { 634 throw new RuntimeException("length < 0"); 635 } 636 if (length > 0) { 637 if (value.startsWith("[") && value.endsWith("]")) { 638 value = value.substring(1, value.length() - 1); 639 } 640 641 String[] valuesArray = value.split(","); 642 for (int i = 0; i < valuesArray.length; i++) { 643 String elementValueString = valuesArray[i]; 644 elementValueString = elementValueString.trim(); 645 Object elementValue = stringValueToSimpleObject(clazz.getComponentType(), elementValueString, null); 646 Array.set(newFieldValue, i, elementValue); 647 } 648 } 649 } else { 650 throw new RuntimeException("Unknown simple class " + clazz); 651 } 652 return newFieldValue; 653 } 654 655 @Override 656 public void endElement(String qName, String content, int childTags) { 657 if (qName.equals(XmlSerializerHelperUtil.TAG_XML_SERIALIZER)) { 658 if (!done) { 659 throw new RuntimeException("Not done " + XmlSerializerHelperUtil.TAG_XML_SERIALIZER); 660 } 661 return ; 662 } 663 664 if (done) { 665 throw new RuntimeException("Already done"); 666 } 667 668 if (!currentData.classIsMissing) { 669 if (qName.equals(XmlSerializerHelperUtil.TAG_ENTRY)) { 670 if (currentData.type != Type.MAP) { 671 throw new RuntimeException("currentData.type != Type.MAP"); 672 } 673 if (!currentData.entryClassIsMissing) { 674 Update update = new Update(); 675 update.type = Type.MAP; 676 update.map = currentData.map; 677 update.keyObject = currentData.entryKeyObject; 678 update.keyReferenceId = currentData.entryKeyReference; 679 update.value = currentData.entryValueObject; 680 update.referenceId = currentData.entryValueReference; 681 currentData.addAfterArrayCollectionMapUpdate(update); 682 } 683 684 currentData.entryKeyObject = null; 685 currentData.entryKeyReference = null; 686 currentData.entryKeyIsSet = false; 687 currentData.entryValueObject = null; 688 currentData.entryValueReference = null; 689 currentData.entryClassIsMissing = false; 690 } 691 692 if (qName.equals(XmlSerializerHelperUtil.TAG_SPECIAL_HANDLING)) { 693 Update update = new Update(); 694 update.object = currentData.object; 695 update.specialHandling = true; 696 update.specialHandlingClass = currentData.specialHandlingClass; 697 update.specialHandlingUpdates = currentData.specialHandlingUpdates; 698 update.specialHandlingDatas = currentData.specialHandlingDatas; 699 updates.add(update); 700 } 701 702 if (qName.equals(XmlSerializerHelperUtil.TAG_OBJECT)) { 703 if (currentData.afterArrayCollectionMapUpdates != null) { 704 updates.addAll(currentData.afterArrayCollectionMapUpdates); 705 currentData.afterArrayCollectionMapUpdates = null; 706 } 707 } 708 } 709 710 if (qName.equals(XmlSerializerHelperUtil.TAG_OBJECT) || qName.equals(XmlSerializerHelperUtil.TAG_SPECIAL_HANDLING)) { 711 if (dataStack.size() == 0) { 712 done = true; 713 return ; 714 } 715 716 if (inSpecialHandlingObject) { 717 inSpecialHandlingObject = false; 718 } 719 720 currentData = dataStack.pop(); 721 } 722 } 723 724 @Override 725 public void endOfDocumentReached() { 726 if (!done) { 727 throw new RuntimeException("!done"); 728 } 729 730 executeUpdates(updates); 731 } 732 733 @SuppressWarnings("unchecked") 734 /*package*/ void executeUpdates(List<Update> updatesToExecute) { 735 for (Update update : updatesToExecute) { 736 if (update.specialHandling) { 737 Method method = XmlSerializerHelperUtil.findReadMethod(update.specialHandlingClass); 738 if (method != null) { 739 for (SpecialHandlingData specialHandlingData : update.specialHandlingDatas) { 740 if (specialHandlingData.referenceId != null) { 741 specialHandlingData.value = idToObjectMap.get(specialHandlingData.referenceId); 742 if (specialHandlingData.value == null) { 743 throw new RuntimeException("Data object not found " + specialHandlingData.referenceId); 744 } 745 } 746 } 747 748 XmlObjectInputStream xmlObjectInputStream; 749 try { 750 xmlObjectInputStream = new XmlObjectInputStream(this, update.specialHandlingUpdates, update.specialHandlingDatas); 751 } catch (IOException e) { 752 throw new RuntimeException(e); 753 } 754 ReflectionUtil.invokeMethod(update.object, method, new Object[] {xmlObjectInputStream}); 755 xmlObjectInputStream.checkAllDataRead(); 756 } else { 757 executeUpdates(update.specialHandlingUpdates); 758 } 759 continue; 760 } 761 762 Object value; 763 if (update.referenceId != null) { 764 value = idToObjectMap.get(update.referenceId); 765 if (value == null) { 766 throw new RuntimeException("Object not found " + update.referenceId); 767 } 768 } else { 769 value = update.value; 770 } 771 772 switch (update.type) { 773 case OBJECT : 774 if (value == null || XmlSerializerHelperUtil.isAssignableFrom(update.field.getType(), value.getClass())) { 775 ReflectionUtil.setFieldValue(update.object, update.field, value); 776 } else { 777 switch (XmlDeserializerMapper.fieldTypeMismatchLogLevel) { 778 case ERROR : 779 throw new RuntimeException("Field \"" + update.field.getName() + "\" in class \"" + update.field.getDeclaringClass().getCanonicalName() + "\" can't be assigned the value \"" + value + "\" of class \"" + value.getClass().getCanonicalName() + "\", because the field is of class \"" + update.field.getType().getCanonicalName() + "\"."); 780// break; 781 case WARNING : 782 System.err.println("WARNING: Field \"" + update.field.getName() + "\" in class \"" + update.field.getDeclaringClass().getCanonicalName() + "\" can't be assigned the value \"" + value + "\" of class \"" + value.getClass().getCanonicalName() + "\", because the field is of class \"" + update.field.getType().getCanonicalName() + "\". The field value will not be loaded."); 783 break; 784 case INFO : 785 System.out.println("Info: Field \"" + update.field.getName() + "\" in class \"" + update.field.getDeclaringClass().getCanonicalName() + "\" can't be assigned the value \"" + value + "\" of class \"" + value.getClass().getCanonicalName() + "\", because the field is of class \"" + update.field.getType().getCanonicalName() + "\". The field value will not be loaded."); 786 break; 787 case IGNORE : 788 ; 789 break; 790 default : 791 throw new RuntimeException("Internal error " + XmlDeserializerMapper.fieldTypeMismatchLogLevel); 792// break; 793 } 794 } 795 break; 796 case ARRAY : 797 if (value == null || XmlSerializerHelperUtil.isAssignableFrom(update.object.getClass().getComponentType(), value.getClass())) { 798 Array.set(update.object, update.arrayIndex, value); 799 } else { 800 switch (XmlDeserializerMapper.fieldTypeMismatchLogLevel) { 801 case ERROR : 802 throw new RuntimeException("Array index " + update.arrayIndex + " in class \"" + update.object.getClass().getCanonicalName() + "\" can't be assigned the value \"" + value + "\" of class \"" + value.getClass().getCanonicalName() + "\"."); 803// break; 804 case WARNING : 805 System.err.println("WARNING: Array index " + update.arrayIndex + " in class \"" + update.object.getClass().getCanonicalName() + "\" can't be assigned the value \"" + value + "\" of class \"" + value.getClass().getCanonicalName() + "\". The value will not be loaded."); 806 break; 807 case INFO : 808 System.out.println("Info: Array index " + update.arrayIndex + " in class \"" + update.object.getClass().getCanonicalName() + "\" can't be assigned the value \"" + value + "\" of class \"" + value.getClass().getCanonicalName() + "\". The value will not be loaded."); 809 break; 810 case IGNORE : 811 ; 812 break; 813 default : 814 throw new RuntimeException("Internal error " + XmlDeserializerMapper.fieldTypeMismatchLogLevel); 815// break; 816 } 817 } 818 break; 819 case COLLECTION : 820 update.collection.add(value); 821 break; 822 case MAP : 823 Object key; 824 if (update.keyReferenceId != null) { 825 key = idToObjectMap.get(update.keyReferenceId); 826 if (value == null) { 827 throw new RuntimeException("Object not found " + update.keyReferenceId); 828 } 829 } else { 830 key = update.keyObject; 831 } 832 update.map.put(key, value); 833 break; 834 default : 835 throw new RuntimeException("Unknown type " + update.type); 836 } 837 } 838 } 839 840 public Serializable getResultObject() { 841 return resultObject; 842 } 843}