| /* XMLEncoder.java | |
| Copyright (C) 2004, 2005 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.beans; | |
| import gnu.java.beans.encoder.ScanEngine; | |
| import java.io.OutputStream; | |
| /** | |
| * This class uses the {@link PersistenceDelegate} and {@link Encoder} | |
| * infrastructure to generate an XML representation of the objects it | |
| * serializes. | |
| * | |
| * @author Robert Schuster (robertschuster@fsfe.org) | |
| * @since 1.4 | |
| */ | |
| public class XMLEncoder extends Encoder | |
| { | |
| Object owner; | |
| Exception exception; | |
| ScanEngine scanEngine; | |
| private int accessCounter = 0; | |
| public XMLEncoder(OutputStream os) | |
| { | |
| scanEngine = new ScanEngine(os); | |
| } | |
| public void close() | |
| { | |
| if (scanEngine != null) | |
| { | |
| scanEngine.close(); | |
| scanEngine = null; | |
| } | |
| } | |
| public void flush() | |
| { | |
| scanEngine.flush(); | |
| } | |
| public void writeExpression(Expression expr) | |
| { | |
| // Implementation note: Why is this method overwritten and nearly exactly | |
| // reimplemented as in Encoder? | |
| // The Encoder class can (and should be) subclassed by users outside of the | |
| // java.beans package. While I have doubts that this is possible from an | |
| // API design point of view I tried to replicate the Encoder's behavior | |
| // in the JDK as exactly as possible. This strictness however made it | |
| // extremely complicated to implement the XMLEncoder's backend. Therefore | |
| // I decided to copy the Encoder's implementation and make all changes | |
| // I needed for a succesfull operation of XMLEncoder. | |
| // | |
| // The same is true for the writeStatement method. | |
| // Silently ignore out of bounds calls. | |
| if (accessCounter <= 0) | |
| return; | |
| scanEngine.writeExpression(expr); | |
| Object target = expr.getTarget(); | |
| Object value = null; | |
| Object newValue = null; | |
| try | |
| { | |
| value = expr.getValue(); | |
| } | |
| catch (Exception e) | |
| { | |
| getExceptionListener().exceptionThrown(e); | |
| return; | |
| } | |
| newValue = get(value); | |
| if (newValue == null) | |
| { | |
| Object newTarget = get(target); | |
| if (newTarget == null) | |
| { | |
| writeObject(target); | |
| newTarget = get(target); | |
| // May happen if exception was thrown. | |
| if (newTarget == null) | |
| { | |
| return; | |
| } | |
| } | |
| Object[] args = expr.getArguments(); | |
| Object[] newArgs = new Object[args.length]; | |
| for (int i = 0; i < args.length; i++) | |
| { | |
| newArgs[i] = get(args[i]); | |
| if (newArgs[i] == null || isImmutableType(args[i].getClass())) | |
| { | |
| writeObject(args[i]); | |
| newArgs[i] = get(args[i]); | |
| } | |
| } | |
| Expression newExpr = new Expression(newTarget, expr.getMethodName(), | |
| newArgs); | |
| // Fakes the result of Class.forName(<primitiveType>) to make it possible | |
| // to hand such a type to the encoding process. | |
| if (value instanceof Class && ((Class) value).isPrimitive()) | |
| newExpr.setValue(value); | |
| // Instantiates the new object. | |
| try | |
| { | |
| newValue = newExpr.getValue(); | |
| putCandidate(value, newValue); | |
| } | |
| catch (Exception e) | |
| { | |
| getExceptionListener().exceptionThrown(e); | |
| // In Statement.writeExpression we had no possibility to flags | |
| // an erroneous state to the ScanEngine without behaving different | |
| // to the JDK. | |
| scanEngine.revoke(); | |
| return; | |
| } | |
| writeObject(value); | |
| } | |
| else if(value.getClass() == String.class || value.getClass() == Class.class) | |
| { | |
| writeObject(value); | |
| } | |
| scanEngine.end(); | |
| } | |
| public void writeStatement(Statement stmt) | |
| { | |
| // In case of questions have a at the implementation note in | |
| // writeExpression. | |
| scanEngine.writeStatement(stmt); | |
| // Silently ignore out of bounds calls. | |
| if (accessCounter <= 0) | |
| return; | |
| Object target = stmt.getTarget(); | |
| Object newTarget = get(target); | |
| if (newTarget == null) | |
| { | |
| writeObject(target); | |
| newTarget = get(target); | |
| } | |
| Object[] args = stmt.getArguments(); | |
| Object[] newArgs = new Object[args.length]; | |
| for (int i = 0; i < args.length; i++) | |
| { | |
| // Here is the difference to the original writeStatement | |
| // method in Encoder. In case that the object is known or | |
| // not an immutable we put it directly into the ScanEngine | |
| // which will then generate an object reference for it. | |
| newArgs[i] = get(args[i]); | |
| if (newArgs[i] == null || isImmutableType(args[i].getClass())) | |
| { | |
| writeObject(args[i]); | |
| newArgs[i] = get(args[i]); | |
| } | |
| else | |
| scanEngine.writeObject(args[i]); | |
| } | |
| Statement newStmt = new Statement(newTarget, stmt.getMethodName(), newArgs); | |
| try | |
| { | |
| newStmt.execute(); | |
| } | |
| catch (Exception e) | |
| { | |
| getExceptionListener().exceptionThrown(e); | |
| // In Statement.writeStatement we had no possibility to flags | |
| // an erroneous state to the ScanEngine without behaving different | |
| // to the JDK. | |
| scanEngine.revoke(); | |
| return; | |
| } | |
| scanEngine.end(); | |
| } | |
| public void writeObject(Object o) | |
| { | |
| accessCounter++; | |
| scanEngine.writeObject(o); | |
| if (get(o) == null); | |
| super.writeObject(o); | |
| accessCounter--; | |
| } | |
| public void setOwner(Object o) | |
| { | |
| owner = o; | |
| } | |
| public Object getOwner() | |
| { | |
| return owner; | |
| } | |
| } |