1 7 package java.beans; 8 9 import java.io.*; 10 import java.util.*; 11 import java.lang.reflect.*; 12 13 186 public class XMLEncoder extends Encoder { 187 188 private static String encoding = "UTF-8"; 189 190 private OutputStream out; 191 private Object owner; 192 private int indentation = 0; 193 private boolean internal = false; 194 private Map valueToExpression; 195 private Map targetToStatementList; 196 private boolean preambleWritten = false; 197 private NameGenerator nameGenerator; 198 199 private class ValueData { 200 public int refs = 0; 201 public boolean marked = false; public String name = null; 203 public Expression exp = null; 204 } 205 206 215 public XMLEncoder(OutputStream out) { 216 this.out = out; 217 valueToExpression = new IdentityHashMap(); 218 targetToStatementList = new IdentityHashMap(); 219 nameGenerator = new NameGenerator (); 220 } 221 222 229 public void setOwner(Object owner) { 230 this.owner = owner; 231 writeExpression(new Expression (this, "getOwner", new Object [0])); 232 } 233 234 241 public Object getOwner() { 242 return owner; 243 } 244 245 252 public void writeObject(Object o) { 253 if (internal) { 254 super.writeObject(o); 255 } 256 else { 257 writeStatement(new Statement (this, "writeObject", new Object []{o})); 258 } 259 } 260 261 private Vector statementList(Object target) { 262 Vector list = (Vector)targetToStatementList.get(target); 263 if (list != null) { 264 return list; 265 } 266 list = new Vector(); 267 targetToStatementList.put(target, list); 268 return list; 269 } 270 271 272 private void mark(Object o, boolean isArgument) { 273 if (o == null || o == this) { 274 return; 275 } 276 ValueData d = getValueData(o); 277 Expression exp = d.exp; 278 if (o.getClass() == String .class && exp == null) { 281 return; 282 } 283 284 if (isArgument) { 286 d.refs++; 287 } 288 if (d.marked) { 289 return; 290 } 291 d.marked = true; 292 Object target = exp.getTarget(); 293 if (!(target instanceof Class )) { 294 statementList(target).add(exp); 295 d.refs++; 298 } 299 mark(exp); 300 } 301 302 private void mark(Statement stm) { 303 Object [] args = stm.getArguments(); 304 for (int i = 0; i < args.length; i++) { 305 Object arg = args[i]; 306 mark(arg, true); 307 } 308 mark(stm.getTarget(), false); 309 } 310 311 312 323 public void writeStatement(Statement oldStm) { 324 boolean internal = this.internal; 326 this.internal = true; 327 try { 328 super.writeStatement(oldStm); 329 337 mark(oldStm); 338 statementList(oldStm.getTarget()).add(oldStm); 339 } 340 catch (Exception e) { 341 getExceptionListener().exceptionThrown(new Exception ("XMLEncoder: discarding statement " + oldStm, e)); 342 } 343 this.internal = internal; 344 } 345 346 347 363 public void writeExpression(Expression oldExp) { 364 boolean internal = this.internal; 365 this.internal = true; 366 Object oldValue = getValue(oldExp); 367 if (get(oldValue) == null || (oldValue instanceof String && !internal)) { 368 getValueData(oldValue).exp = oldExp; 369 super.writeExpression(oldExp); 370 } 371 this.internal = internal; 372 } 373 374 382 public void flush() { 383 if (!preambleWritten) { writeln("<?xml version=" + quote("1.0") + 385 " encoding=" + quote(encoding) + "?>"); 386 writeln("<java version=" + quote(System.getProperty("java.version")) + 387 " class=" + quote(XMLDecoder .class.getName()) + ">"); 388 preambleWritten = true; 389 } 390 indentation++; 391 Vector roots = statementList(this); 392 for(int i = 0; i < roots.size(); i++) { 393 Statement s = (Statement )roots.get(i); 394 if ("writeObject".equals(s.getMethodName())) { 395 outputValue(s.getArguments()[0], this, true); 396 } 397 else { 398 outputStatement(s, this, false); 399 } 400 } 401 indentation--; 402 403 try { 404 out.flush(); 405 } 406 catch (IOException e) { 407 getExceptionListener().exceptionThrown(e); 408 } 409 clear(); 410 } 411 412 void clear() { 413 super.clear(); 414 nameGenerator.clear(); 415 valueToExpression.clear(); 416 targetToStatementList.clear(); 417 } 418 419 420 425 public void close() { 426 flush(); 427 writeln("</java>"); 428 try { 429 out.close(); 430 } 431 catch (IOException e) { 432 getExceptionListener().exceptionThrown(e); 433 } 434 } 435 436 private String quote(String s) { 437 return "\"" + s + "\""; 438 } 439 440 private ValueData getValueData(Object o) { 441 ValueData d = (ValueData)valueToExpression.get(o); 442 if (d == null) { 443 d = new ValueData(); 444 valueToExpression.put(o, d); 445 } 446 return d; 447 } 448 449 private static String quoteCharacters(String s) { 450 StringBuffer result = null; 451 for(int i = 0, max = s.length(), delta = 0; i < max; i++) { 452 char c = s.charAt(i); 453 String replacement = null; 454 455 if (c == '&') { 456 replacement = "&"; 457 } else if (c == '<') { 458 replacement = "<"; 459 } else if (c == '\r') { 460 replacement = " "; 461 } else if (c == '>') { 462 replacement = ">"; 463 } else if (c == '"') { 464 replacement = """; 465 } else if (c == '\'') { 466 replacement = "'"; 467 } 468 469 if (replacement != null) { 470 if (result == null) { 471 result = new StringBuffer (s); 472 } 473 result.replace(i + delta, i + delta + 1, replacement); 474 delta += (replacement.length() - 1); 475 } 476 } 477 if (result == null) { 478 return s; 479 } 480 return result.toString(); 481 } 482 483 private void writeln(String exp) { 484 try { 485 for(int i = 0; i < indentation; i++) { 486 out.write(' '); 487 } 488 out.write(exp.getBytes(encoding)); 489 out.write(" \n".getBytes(encoding)); 490 } 491 catch (IOException e) { 492 getExceptionListener().exceptionThrown(e); 493 } 494 } 495 496 private void outputValue(Object value, Object outer, boolean isArgument) { 497 if (value == null) { 498 writeln("<null/>"); 499 return; 500 } 501 502 if (value instanceof Class ) { 503 writeln("<class>" + ((Class )value).getName() + "</class>"); 504 return; 505 } 506 507 ValueData d = getValueData(value); 508 if (d.exp != null) { 509 Object target = d.exp.getTarget(); 510 String methodName = d.exp.getMethodName(); 511 512 if (target == null || methodName == null) { 513 throw new NullPointerException ((target == null ? "target" : 514 "methodName") + " should not be null"); 515 } 516 517 if (target instanceof Field && methodName.equals("get")) { 518 Field f = (Field)target; 519 writeln("<object class=" + quote(f.getDeclaringClass().getName()) + 520 " field=" + quote(f.getName()) + "/>"); 521 return; 522 } 523 524 Class primitiveType = ReflectionUtils.primitiveTypeFor(value.getClass()); 525 if (primitiveType != null && target == value.getClass() && 526 methodName.equals("new")) { 527 String primitiveTypeName = primitiveType.getName(); 528 if (primitiveType == Character.TYPE) { 530 value = quoteCharacters(((Character )value).toString()); 531 } 532 writeln("<" + primitiveTypeName + ">" + value + "</" + 533 primitiveTypeName + ">"); 534 return; 535 } 536 537 } else if (value instanceof String ) { 538 writeln("<string>" + quoteCharacters((String )value) + "</string>"); 539 return; 540 } 541 542 if (d.name != null) { 543 writeln("<object idref=" + quote(d.name) + "/>"); 544 return; 545 } 546 547 outputStatement(d.exp, outer, isArgument); 548 } 549 550 private void outputStatement(Statement exp, Object outer, boolean isArgument) { 551 Object target = exp.getTarget(); 552 String methodName = exp.getMethodName(); 553 554 if (target == null || methodName == null) { 555 throw new NullPointerException ((target == null ? "target" : 556 "methodName") + " should not be null"); 557 } 558 559 Object [] args = exp.getArguments(); 560 boolean expression = exp.getClass() == Expression .class; 561 Object value = (expression) ? getValue((Expression )exp) : null; 562 563 String tag = (expression && isArgument) ? "object" : "void"; 564 String attributes = ""; 565 ValueData d = getValueData(value); 566 if (expression) { 567 if (d.refs > 1) { 568 String instanceName = nameGenerator.instanceName(value); 569 d.name = instanceName; 570 attributes = attributes + " id=" + quote(instanceName); 571 } 572 } 573 574 if (target == outer) { 576 } 577 else if (target == Array.class && methodName.equals("newInstance")) { 578 tag = "array"; 579 attributes = attributes + " class=" + quote(((Class )args[0]).getName()); 580 attributes = attributes + " length=" + quote(args[1].toString()); 581 args = new Object []{}; 582 } 583 else if (target.getClass() == Class .class) { 584 attributes = attributes + " class=" + quote(((Class )target).getName()); 585 } 586 else { 587 d.refs = 2; 588 outputValue(target, outer, false); 589 outputValue(value, outer, false); 590 return; 591 } 592 593 594 if ((!expression && methodName.equals("set") && args.length == 2 && 596 args[0] instanceof Integer ) || 597 (expression && methodName.equals("get") && args.length == 1 && 598 args[0] instanceof Integer )) { 599 attributes = attributes + " index=" + quote(args[0].toString()); 600 args = (args.length == 1) ? new Object []{} : new Object []{args[1]}; 601 } 602 else if ((!expression && methodName.startsWith("set") && args.length == 1) || 603 (expression && methodName.startsWith("get") && args.length == 0)) { 604 attributes = attributes + " property=" + 605 quote(Introspector.decapitalize(methodName.substring(3))); 606 } 607 else if (!methodName.equals("new") && !methodName.equals("newInstance")) { 608 attributes = attributes + " method=" + quote(methodName); 609 } 610 611 Vector statements = statementList(value); 612 if (args.length == 0 && statements.size() == 0) { 614 writeln("<" + tag + attributes + "/>"); 615 return; 616 } 617 618 writeln("<" + tag + attributes + ">"); 619 indentation++; 620 621 for(int i = 0; i < args.length; i++) { 622 outputValue(args[i], null, true); 623 } 624 625 for(int i = 0; i < statements.size(); i++) { 626 Statement s = (Statement )statements.get(i); 627 outputStatement(s, value, false); 628 } 629 630 indentation--; 631 writeln("</" + tag + ">"); 632 } 633 } 634 | Popular Tags |