Path: blob/master/src/java.desktop/share/classes/java/beans/XMLDecoder.java
41152 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package java.beans;2526import com.sun.beans.decoder.DocumentHandler;2728import java.io.Closeable;29import java.io.InputStream;30import java.io.IOException;31import java.security.AccessControlContext;32import java.security.AccessController;33import java.security.PrivilegedAction;3435import org.xml.sax.InputSource;36import org.xml.sax.helpers.DefaultHandler;3738/**39* The {@code XMLDecoder} class is used to read XML documents40* created using the {@code XMLEncoder} and is used just like41* the {@code ObjectInputStream}. For example, one can use42* the following fragment to read the first object defined43* in an XML document written by the {@code XMLEncoder}44* class:45* <pre>46* XMLDecoder d = new XMLDecoder(47* new BufferedInputStream(48* new FileInputStream("Test.xml")));49* Object result = d.readObject();50* d.close();51* </pre>52*53*<p>54* For more information you might also want to check out55* <a href="http://www.oracle.com/technetwork/java/persistence3-139471.html">56* Long Term Persistence of JavaBeans Components: XML Schema</a>,57* an article in <em>The Swing Connection.</em>58* @see XMLEncoder59* @see java.io.ObjectInputStream60*61* @since 1.462*63* @author Philip Milne64*/65public class XMLDecoder implements AutoCloseable {66@SuppressWarnings("removal")67private final AccessControlContext acc = AccessController.getContext();68private final DocumentHandler handler = new DocumentHandler();69private final InputSource input;70private Object owner;71private Object[] array;72private int index;7374/**75* Creates a new input stream for reading archives76* created by the {@code XMLEncoder} class.77*78* @param in The underlying stream.79*80* @see XMLEncoder#XMLEncoder(java.io.OutputStream)81*/82public XMLDecoder(InputStream in) {83this(in, null);84}8586/**87* Creates a new input stream for reading archives88* created by the {@code XMLEncoder} class.89*90* @param in The underlying stream.91* @param owner The owner of this stream.92*93*/94public XMLDecoder(InputStream in, Object owner) {95this(in, owner, null);96}9798/**99* Creates a new input stream for reading archives100* created by the {@code XMLEncoder} class.101*102* @param in the underlying stream.103* @param owner the owner of this stream.104* @param exceptionListener the exception handler for the stream;105* if {@code null} the default exception listener will be used.106*/107public XMLDecoder(InputStream in, Object owner, ExceptionListener exceptionListener) {108this(in, owner, exceptionListener, null);109}110111/**112* Creates a new input stream for reading archives113* created by the {@code XMLEncoder} class.114*115* @param in the underlying stream. {@code null} may be passed without116* error, though the resulting XMLDecoder will be useless117* @param owner the owner of this stream. {@code null} is a legal118* value119* @param exceptionListener the exception handler for the stream, or120* {@code null} to use the default121* @param cl the class loader used for instantiating objects.122* {@code null} indicates that the default class loader should123* be used124* @since 1.5125*/126public XMLDecoder(InputStream in, Object owner,127ExceptionListener exceptionListener, ClassLoader cl) {128this(new InputSource(in), owner, exceptionListener, cl);129}130131132/**133* Creates a new decoder to parse XML archives134* created by the {@code XMLEncoder} class.135* If the input source {@code is} is {@code null},136* no exception is thrown and no parsing is performed.137* This behavior is similar to behavior of other constructors138* that use {@code InputStream} as a parameter.139*140* @param is the input source to parse141*142* @since 1.7143*/144public XMLDecoder(InputSource is) {145this(is, null, null, null);146}147148/**149* Creates a new decoder to parse XML archives150* created by the {@code XMLEncoder} class.151*152* @param is the input source to parse153* @param owner the owner of this decoder154* @param el the exception handler for the parser,155* or {@code null} to use the default exception handler156* @param cl the class loader used for instantiating objects,157* or {@code null} to use the default class loader158*159* @since 1.7160*/161private XMLDecoder(InputSource is, Object owner, ExceptionListener el, ClassLoader cl) {162this.input = is;163this.owner = owner;164setExceptionListener(el);165this.handler.setClassLoader(cl);166this.handler.setOwner(this);167}168169/**170* This method closes the input stream associated171* with this stream.172*/173public void close() {174if (parsingComplete()) {175close(this.input.getCharacterStream());176close(this.input.getByteStream());177}178}179180private void close(Closeable in) {181if (in != null) {182try {183in.close();184}185catch (IOException e) {186getExceptionListener().exceptionThrown(e);187}188}189}190191@SuppressWarnings("removal")192private boolean parsingComplete() {193if (this.input == null) {194return false;195}196if (this.array == null) {197if ((this.acc == null) && (null != System.getSecurityManager())) {198throw new SecurityException("AccessControlContext is not set");199}200AccessController.doPrivileged(new PrivilegedAction<Void>() {201public Void run() {202XMLDecoder.this.handler.parse(XMLDecoder.this.input);203return null;204}205}, this.acc);206this.array = this.handler.getObjects();207}208return true;209}210211/**212* Sets the exception handler for this stream to {@code exceptionListener}.213* The exception handler is notified when this stream catches recoverable214* exceptions.215*216* @param exceptionListener The exception handler for this stream;217* if {@code null} the default exception listener will be used.218*219* @see #getExceptionListener220*/221public void setExceptionListener(ExceptionListener exceptionListener) {222if (exceptionListener == null) {223exceptionListener = Statement.defaultExceptionListener;224}225this.handler.setExceptionListener(exceptionListener);226}227228/**229* Gets the exception handler for this stream.230*231* @return The exception handler for this stream.232* Will return the default exception listener if this has not explicitly been set.233*234* @see #setExceptionListener235*/236public ExceptionListener getExceptionListener() {237return this.handler.getExceptionListener();238}239240/**241* Reads the next object from the underlying input stream.242*243* @return the next object read244*245* @throws ArrayIndexOutOfBoundsException if the stream contains no objects246* (or no more objects)247*248* @see XMLEncoder#writeObject249*/250public Object readObject() {251return (parsingComplete())252? this.array[this.index++]253: null;254}255256/**257* Sets the owner of this decoder to {@code owner}.258*259* @param owner The owner of this decoder.260*261* @see #getOwner262*/263public void setOwner(Object owner) {264this.owner = owner;265}266267/**268* Gets the owner of this decoder.269*270* @return The owner of this decoder.271*272* @see #setOwner273*/274public Object getOwner() {275return owner;276}277278/**279* Creates a new handler for SAX parser280* that can be used to parse embedded XML archives281* created by the {@code XMLEncoder} class.282*283* The {@code owner} should be used if parsed XML document contains284* the method call within context of the <java> element.285* The {@code null} value may cause illegal parsing in such case.286* The same problem may occur, if the {@code owner} class287* does not contain expected method to call. See details <a288* href="http://www.oracle.com/technetwork/java/persistence3-139471.html">289* here</a>.290*291* @param owner the owner of the default handler292* that can be used as a value of <java> element293* @param el the exception handler for the parser,294* or {@code null} to use the default exception handler295* @param cl the class loader used for instantiating objects,296* or {@code null} to use the default class loader297* @return an instance of {@code DefaultHandler} for SAX parser298*299* @since 1.7300*/301public static DefaultHandler createHandler(Object owner, ExceptionListener el, ClassLoader cl) {302DocumentHandler handler = new DocumentHandler();303handler.setOwner(owner);304handler.setExceptionListener(el);305handler.setClassLoader(cl);306return handler;307}308}309310311