| /* 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; |
| } |
| |
| } |