dev@fi.java.net

Re: JAXB and of base64 data and FI

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 29 Jul 2005 17:19:33 +0200

I forgot to mention this code requires the latest FI jar [1] [2].

Paul.

[1] https://fi.dev.java.net/servlets/ProjectDocumentList
[2 Sun internal link]
http://kohsuke.sfbay/hudson/job/fi/lastBuild/artifact/fi/FastInfoset/dist/FastInfoset.jar

Paul Sandoz wrote:
> Hi,
>
> I have a working version of FI integrated with support for base64 data.
> Attached are the files i modified.
>
> For testing purposes i hacked the Marhsaller/UnmarshallerImpl classes to
> check for specific instances of FI related classes. It is working for a
> simple schema containing base64 data.
>
> The implementations are currently very specific to the Base64Data class
> and will not scale very well when supporting a number of different data
> types. We will need a better way to supports types (single instances and
> in certain cases arrays of) for both serializing and parsing in the future
>
> The FastInfosetConnector class is currently FI StAX specific. In the
> future it does not have to be. I can see how to optimize specifically
> for JAXB e.g. to avoid buffering until the end of the element, and not
> to decode stuff like comments and PI which can be just skipped.
>
> The FI marshalling is explicitly StAX specific the moment and inherits a
> lot from the XMLStreamWriterOutput. Again this does not have to be the
> case in the future. I have a prototype for a FastInfosetXmlOutput (which
> does not support the serializing of non bound data at the moment) and
> this could be instantiated from the same method that instantiates a
> UTF-8 and EXC14N serializer given a certain property on the context.
>
>
> The serializing side of things should be quite stable as most code is
> rused. The parsing side may be less so because it is new code. I am not
> sure how best we can test both the parser and serializer. Can existing
> JAXB tests be used with FI?
>
> Paul.
>
>
> ------------------------------------------------------------------------
>
> /*
> * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
> * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
> */
> package com.sun.xml.bind.v2.runtime;
>
> import java.io.BufferedOutputStream;
> import java.io.BufferedWriter;
> import java.io.ByteArrayOutputStream;
> import java.io.FileOutputStream;
> import java.io.IOException;
> import java.io.OutputStream;
> import java.io.OutputStreamWriter;
> import java.io.UnsupportedEncodingException;
> import java.io.Writer;
>
> import javax.xml.bind.DatatypeConverter;
> import javax.xml.bind.JAXBException;
> import javax.xml.bind.MarshalException;
> import javax.xml.bind.PropertyException;
> import javax.xml.bind.ValidationEvent;
> import javax.xml.bind.ValidationEventHandler;
> import javax.xml.bind.annotation.adapters.XmlAdapter;
> import javax.xml.bind.attachment.AttachmentMarshaller;
> import javax.xml.bind.helpers.AbstractMarshallerImpl;
> import javax.xml.stream.XMLEventWriter;
> import javax.xml.stream.XMLStreamException;
> import javax.xml.stream.XMLStreamWriter;
> import javax.xml.transform.Result;
> import javax.xml.transform.dom.DOMResult;
> import javax.xml.transform.sax.SAXResult;
> import javax.xml.transform.stream.StreamResult;
> import javax.xml.validation.Schema;
> import javax.xml.validation.ValidatorHandler;
>
> import com.sun.xml.bind.DatatypeConverterImpl;
> import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
> import com.sun.xml.bind.marshaller.DataWriter;
> import com.sun.xml.bind.marshaller.DumbEscapeHandler;
> import com.sun.xml.bind.marshaller.Messages;
> import com.sun.xml.bind.marshaller.MinimumEscapeHandler;
> import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
> import com.sun.xml.bind.marshaller.NioEscapeHandler;
> import com.sun.xml.bind.marshaller.SAX2DOMEx;
> import com.sun.xml.bind.marshaller.XMLWriter;
> import com.sun.xml.bind.v2.AssociationMap;
> import com.sun.xml.bind.v2.FatalAdapter;
> import com.sun.xml.bind.v2.runtime.output.C14nXmlOutput;
> import com.sun.xml.bind.v2.runtime.output.Encoded;
> import com.sun.xml.bind.v2.runtime.output.FastInfosetStreamWriterOutput;
> import com.sun.xml.bind.v2.runtime.output.ForkXmlOutput;
> import com.sun.xml.bind.v2.runtime.output.IndentingUTF8XmlOutput;
> import com.sun.xml.bind.v2.runtime.output.SAXOutput;
> import com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput;
> import com.sun.xml.bind.v2.runtime.output.XMLEventWriterOutput;
> import com.sun.xml.bind.v2.runtime.output.XMLStreamWriterOutput;
> import com.sun.xml.bind.v2.runtime.output.XmlOutput;
> import com.sun.xml.fastinfoset.stax.StAXDocumentSerializer;
>
> import org.w3c.dom.Document;
> import org.w3c.dom.Node;
> import org.xml.sax.SAXException;
> import org.xml.sax.helpers.XMLFilterImpl;
>
> /**
> * Implementation of {_at_link Marshaller} interface for the JAXB RI.
> *
> * <p>
> * Eventually all the {_at_link #marshal} methods call into
> * the {_at_link #write} method.
> *
> * @author Kohsuke Kawaguchi
> * @author Vivek Pandey
> */
> public /*to make unit tests happy*/ final class MarshallerImpl extends AbstractMarshallerImpl implements ValidationEventHandler
> {
> /** Indentation string. Default is four whitespaces. */
> private String indent = " ";
>
> /** Used to assign prefixes to namespace URIs. */
> private NamespacePrefixMapper prefixMapper = null;
>
> /** Object that handles character escaping. */
> private CharacterEscapeHandler escapeHandler = null;
>
> /** Whether the xml declaration will be printed or not. */
> private boolean printXmlDeclaration = true;
>
> /** XML BLOB written after the XML declaration. */
> private String header=null;
>
> /** reference to the context that created this object */
> final JAXBContextImpl context;
>
> protected final XMLSerializer serializer;
>
> /**
> * Non-null if we work inside a {_at_link BinderImpl}.
> */
> private final AssociationMap assoc;
>
> /**
> * Non-null if we do the marshal-time validation.
> */
> private Schema schema;
>
> /**
> * @param assoc
> * non-null if the marshaller is working inside {_at_link BinderImpl}.
> */
> public MarshallerImpl( JAXBContextImpl c, AssociationMap assoc ) {
> // initialize datatype converter with ours
> DatatypeConverter.setDatatypeConverter(DatatypeConverterImpl.theInstance);
>
> context = c;
> this.assoc = assoc;
> serializer = new XMLSerializer(this);
>
> try {
> setEventHandler(this);
> } catch (JAXBException e) {
> throw new AssertionError(e); // impossible
> }
> }
>
> public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException {
> if (writer instanceof StAXDocumentSerializer) {
> write(obj, new FastInfosetStreamWriterOutput((StAXDocumentSerializer)writer),
> new StAXPostInitAction(writer,serializer));
> } else {
> write(obj, new XMLStreamWriterOutput(writer), new StAXPostInitAction(writer,serializer));
> }
> }
>
> public void marshal(Object obj, XMLEventWriter writer) throws JAXBException {
> write(obj, new XMLEventWriterOutput(writer), new StAXPostInitAction(writer,serializer));
> }
>
> public void marshal(Object obj, XmlOutput output) throws JAXBException {
> write(obj, output, null );
> }
>
> public void marshal(Object target,Result result) throws JAXBException {
> if (result instanceof SAXResult) {
> write(target, new SAXOutput(((SAXResult) result).getHandler()), null);
> return;
> }
> if (result instanceof DOMResult) {
> final Node node = ((DOMResult) result).getNode();
>
> if (node == null) {
> Document doc = JAXBContextImpl.createDom();
> ((DOMResult) result).setNode(doc);
> write(target, new SAXOutput(new SAX2DOMEx(doc)), null );
> } else {
> write(target, new SAXOutput(new SAX2DOMEx(node)), new DomPostInitAction(node,serializer));
> }
>
> return;
> }
> if (result instanceof StreamResult) {
> StreamResult sr = (StreamResult) result;
> XmlOutput w = null;
>
> if (sr.getWriter() != null)
> w = createWriter(sr.getWriter());
> else if (sr.getOutputStream() != null)
> w = createWriter(sr.getOutputStream());
> else if (sr.getSystemId() != null) {
> String fileURL = sr.getSystemId();
>
> if (fileURL.startsWith("file:///")) {
> if (fileURL.substring(8).indexOf(":") > 0)
> fileURL = fileURL.substring(8);
> else
> fileURL = fileURL.substring(7);
> } // otherwise assume that it's a file name
>
> try {
> w = createWriter(new FileOutputStream(fileURL));
> } catch (IOException e) {
> throw new MarshalException(e);
> }
> }
>
> if (w == null)
> throw new IllegalArgumentException();
>
> write(target, w, null);
> return;
> }
>
> // unsupported parameter type
> throw new MarshalException(
> Messages.format( Messages.UNSUPPORTED_RESULT ) );
> }
>
> /**
> * Used by {_at_link BridgeImpl} to write an arbitrary object.
> */
> protected final <T> void write(Name rootTagName, JaxBeanInfo<T> bi, T obj, XmlOutput out,Runnable postInitAction) throws JAXBException {
> try {
> prewrite(out, true, postInitAction);
> serializer.startElement(rootTagName,null);
> if(bi.jaxbType==Void.class || bi.jaxbType==void.class) {
> // special case for void
> serializer.endNamespaceDecls(null);
> serializer.endAttributes();
> } else { // normal cases
> if(obj==null)
> serializer.writeXsiNilTrue();
> else
> serializer.childAsXsiType(obj,"root",bi);
> }
> serializer.endElement();
> postwrite(out);
> } catch( SAXException e ) {
> throw new MarshalException(e);
> } catch (IOException e) {
> throw new MarshalException(e);
> } catch (XMLStreamException e) {
> throw new MarshalException(e);
> } finally {
> serializer.close();
> }
> }
>
> /**
> * All the marshal method invocation eventually comes down to this call.
> */
> private void write(Object obj, XmlOutput out, Runnable postInitAction)
> throws JAXBException {
>
> if( obj == null )
> throw new IllegalArgumentException(Messages.format(Messages.NOT_MARSHALLABLE));
>
> if( schema!=null ) {
> // send the output to the validator as well
> ValidatorHandler validator = schema.newValidatorHandler();
> validator.setErrorHandler(new FatalAdapter(serializer));
> // work around a bug in JAXP validator in Tiger
> XMLFilterImpl f = new XMLFilterImpl() {
> public void startPrefixMapping(String prefix, String uri) throws SAXException {
> super.startPrefixMapping(prefix.intern(), uri.intern());
> }
> };
> f.setContentHandler(validator);
> out = new ForkXmlOutput( new SAXOutput(f), out );
> }
>
> try {
> prewrite(out,isFragment(),postInitAction);
> serializer.childAsRoot(obj);
> postwrite(out);
> } catch( SAXException e ) {
> throw new MarshalException(e);
> } catch (IOException e) {
> throw new MarshalException(e);
> } catch (XMLStreamException e) {
> throw new MarshalException(e);
> } finally {
> serializer.close();
> }
> }
>
> // common parts between two write methods.
>
> private void prewrite(XmlOutput out, boolean fragment, Runnable postInitAction) throws IOException, SAXException, XMLStreamException {
> serializer.startDocument(out,fragment,getSchemaLocation(),getNoNSSchemaLocation());
> if(postInitAction!=null) postInitAction.run();
> if(prefixMapper!=null) {
> // be defensive as we work with the user's code
> String[] decls = prefixMapper.getContextualNamespaceDecls();
> if(decls!=null) { // defensive check
> for( int i=0; i<decls.length; i+=2 ) {
> String prefix = decls[i];
> String nsUri = decls[i+1];
> if(nsUri!=null && prefix!=null) // defensive check
> serializer.addInscopeBinding(nsUri,prefix);
> }
> }
> }
> serializer.setPrefixMapper(prefixMapper);
> }
>
> private void postwrite(XmlOutput out) throws IOException, SAXException, XMLStreamException {
> serializer.endDocument();
> serializer.reconcileID(); // extra check
> out.flush();
> }
>
>
> //
> //
> // create XMLWriter by specifing various type of output.
> //
> //
>
> protected CharacterEscapeHandler createEscapeHandler( String encoding ) {
> if( escapeHandler!=null )
> // user-specified one takes precedence.
> return escapeHandler;
>
> if( encoding.startsWith("UTF") )
> // no need for character reference. Use the handler
> // optimized for that pattern.
> return MinimumEscapeHandler.theInstance;
>
> // otherwise try to find one from the encoding
> try {
> // try new JDK1.4 NIO
> return new NioEscapeHandler( getJavaEncoding(encoding) );
> } catch( Throwable e ) {
> // if that fails, fall back to the dumb mode
> return DumbEscapeHandler.theInstance;
> }
> }
>
> public XmlOutput createWriter( Writer w, String encoding ) {
>
> // buffering improves the performance
> w = new BufferedWriter(w);
>
> CharacterEscapeHandler ceh = createEscapeHandler(encoding);
> XMLWriter xw;
>
> if(isFormattedOutput()) {
> DataWriter d = new DataWriter(w,encoding,ceh);
> d.setIndentStep(indent);
> xw=d;
> }
> else
> xw = new XMLWriter(w,encoding,ceh);
>
> // Marshaller.JAXB_FRAGMENT property overrides our c.s.x.b.xmlDeclaration vendor property
> xw.setXmlDecl(printXmlDeclaration && !isFragment());
> xw.setHeader(header);
> return new SAXOutput(xw); // TODO: don't we need a better writer?
> }
>
> public XmlOutput createWriter(Writer w) {
> return createWriter(w, getEncoding());
> }
>
> public XmlOutput createWriter( OutputStream os ) throws JAXBException {
> return createWriter(os, getEncoding());
> }
>
> public XmlOutput createWriter( OutputStream os, String encoding ) throws JAXBException {
> // buffering improves the performance, but not always
> if(!(os instanceof BufferedOutputStream) && !(os instanceof ByteArrayOutputStream))
> os = new BufferedOutputStream(os);
>
> if(encoding.equals("UTF-8")) {
> Encoded[] table = context.getUTF8NameTable();
> if(isFormattedOutput())
> return new IndentingUTF8XmlOutput(os,indent,table);
> else {
> if(context.c14nSupport)
> return new C14nXmlOutput(os,table);
> else
> return new UTF8XmlOutput(os,table);
> }
> }
>
> try {
> return createWriter(
> new OutputStreamWriter(os,getJavaEncoding(encoding)),
> encoding );
> } catch( UnsupportedEncodingException e ) {
> throw new MarshalException(
> Messages.format( Messages.UNSUPPORTED_ENCODING, encoding ),
> e );
> }
> }
>
>
> public Object getProperty(String name) throws PropertyException {
> if( INDENT_STRING.equals(name) )
> return indent;
> if( ENCODING_HANDLER.equals(name) )
> return escapeHandler;
> if( PREFIX_MAPPER.equals(name) )
> return prefixMapper;
> if( XMLDECLARATION.equals(name) )
> return printXmlDeclaration;
> if( XML_HEADERS.equals(name) )
> return header;
>
> return super.getProperty(name);
> }
>
> public void setProperty(String name, Object value) throws PropertyException {
> if( INDENT_STRING.equals(name) ) {
> indent = (String)value;
> return;
> }
> if( ENCODING_HANDLER.equals(name) ) {
> escapeHandler = (CharacterEscapeHandler)value;
> return;
> }
> if( PREFIX_MAPPER.equals(name) ) {
> prefixMapper = (NamespacePrefixMapper)value;
> return;
> }
> if( XMLDECLARATION.equals(name) ) {
> printXmlDeclaration = (Boolean) value;
> return;
> }
> if( XML_HEADERS.equals(name) ) {
> header = (String)value;
> return;
> }
>
> super.setProperty(name, value);
> }
>
>
> @Override
> public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) {
> if(type==null)
> throw new IllegalArgumentException();
> serializer.putAdapter(type,adapter);
> }
>
> @Override
> public <A extends XmlAdapter> A getAdapter(Class<A> type) {
> if(type==null)
> throw new IllegalArgumentException();
> if(serializer.containsAdapter(type))
> // so as not to create a new instance when this method is called
> return serializer.getAdapter(type);
> else
> return null;
> }
>
> @Override
> public void setAttachmentMarshaller(AttachmentMarshaller am) {
> serializer.attachmentMarshaller = am;
> }
>
> @Override
> public AttachmentMarshaller getAttachmentMarshaller() {
> return serializer.attachmentMarshaller;
> }
>
> public Schema getSchema() {
> return schema;
> }
>
> public void setSchema(Schema s) {
> this.schema = s;
> }
>
> /**
> * Default error handling behavior fot {_at_link Marshaller}.
> */
> public boolean handleEvent(ValidationEvent event) {
> // draconian by default
> return false;
> }
>
>
> private static final String INDENT_STRING = "com.sun.xml.bind.indentString";
> private static final String PREFIX_MAPPER = "com.sun.xml.bind.namespacePrefixMapper";
> private static final String ENCODING_HANDLER = "com.sun.xml.bind.characterEscapeHandler";
> private static final String XMLDECLARATION = "com.sun.xml.bind.xmlDeclaration";
> private static final String XML_HEADERS = "com.sun.xml.bind.xmlHeaders";
> }
>
>
> ------------------------------------------------------------------------
>
> package com.sun.xml.bind.v2.runtime.output;
>
> import com.sun.xml.bind.v2.runtime.unmarshaller.Base64Data;
> import com.sun.xml.fastinfoset.stax.StAXDocumentSerializer;
> import java.io.IOException;
> import javax.xml.stream.XMLStreamException;
> import org.xml.sax.SAXException;
>
> public class FastInfosetStreamWriterOutput extends XMLStreamWriterOutput {
> private final StAXDocumentSerializer fiout;
>
> public FastInfosetStreamWriterOutput(StAXDocumentSerializer out) {
> super(out);
> this.fiout = out;
> }
>
> public void text(CharSequence value, boolean needsSeparatingWhitespace) throws IOException, SAXException, XMLStreamException {
> if(needsSeparatingWhitespace) {
> fiout.writeCharacters(" ");
> }
>
> /*
> * Check if the CharSequence is from a base64Binary data type
> */
> if (!(value instanceof Base64Data)) {
> // Write out characters
> fiout.writeCharacters(value.toString());
> } else {
> final Base64Data dataValue = (Base64Data)value;
> // Write out the octets using the base64 encoding algorithm
> fiout.writeOctets(dataValue.get(), 0, dataValue.getDataLen());
> }
> }
> }
>
>
> ------------------------------------------------------------------------
>
> /*
> * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
> * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
> */
>
> /*
> * @(#)$Id: UnmarshallerImpl.java,v 1.14 2005/07/27 21:17:39 kohsuke Exp $
> */
> package com.sun.xml.bind.v2.runtime.unmarshaller;
>
> import com.sun.xml.fastinfoset.stax.StAXDocumentParser;
> import java.io.IOException;
> import java.net.URL;
>
> import javax.xml.bind.DatatypeConverter;
> import javax.xml.bind.JAXBContext;
> import javax.xml.bind.JAXBException;
> import javax.xml.bind.PropertyException;
> import javax.xml.bind.UnmarshalException;
> import javax.xml.bind.Unmarshaller;
> import javax.xml.bind.UnmarshallerHandler;
> import javax.xml.bind.ValidationEventHandler;
> import javax.xml.bind.ValidationEvent;
> import javax.xml.bind.JAXBElement;
> import javax.xml.bind.annotation.adapters.XmlAdapter;
> import javax.xml.bind.attachment.AttachmentUnmarshaller;
> import javax.xml.bind.helpers.AbstractUnmarshallerImpl;
> import javax.xml.stream.XMLEventReader;
> import javax.xml.stream.XMLStreamConstants;
> import javax.xml.stream.XMLStreamException;
> import javax.xml.stream.XMLStreamReader;
> import javax.xml.stream.events.XMLEvent;
> import javax.xml.validation.Schema;
> import javax.xml.transform.Source;
> import javax.xml.transform.dom.DOMSource;
> import javax.xml.transform.stream.StreamSource;
> import javax.xml.transform.sax.SAXSource;
>
> import com.sun.xml.bind.DatatypeConverterImpl;
> import com.sun.xml.bind.unmarshaller.DOMScanner;
> import com.sun.xml.bind.unmarshaller.InfosetScanner;
> import com.sun.xml.bind.unmarshaller.Messages;
> import com.sun.xml.bind.v2.AssociationMap;
> import com.sun.xml.bind.v2.runtime.JAXBContextImpl;
> import com.sun.xml.bind.v2.runtime.JaxBeanInfo;
> import com.sun.xml.bind.v2.stax.XMLEventReaderToContentHandler;
> import com.sun.xml.bind.v2.stax.XMLStreamReaderToContentHandler;
>
> import org.w3c.dom.Document;
> import org.w3c.dom.Element;
> import org.w3c.dom.Node;
> import org.xml.sax.InputSource;
> import org.xml.sax.SAXException;
> import org.xml.sax.XMLReader;
> import org.xml.sax.helpers.DefaultHandler;
>
> /**
> * Default Unmarshaller implementation.
> *
> * <p>
> * This class can be extended by the generated code to provide
> * type-safe unmarshall methods.
> *
> * @author
> * <a href="mailto:kohsuke.kawaguchi_at_sun.com">Kohsuke KAWAGUCHI</a>
> */
> public final class UnmarshallerImpl extends AbstractUnmarshallerImpl implements ValidationEventHandler
> {
> /** Owning {_at_link JAXBContext} */
> protected final JAXBContextImpl context;
>
> /**
> * schema which will be used to validate during calls to unmarshal
> */
> private Schema schema;
>
>
> public final UnmarshallingContext coordinator;
>
> /**
> * The attachment unmarshaller used to support MTOM and swaRef.
> */
> private AttachmentUnmarshaller attachmentUnmarshaller;
>
> public UnmarshallerImpl( JAXBContextImpl context, AssociationMap assoc ) {
> this.context = context;
> this.coordinator = new UnmarshallingContext( this, assoc );
>
> // initialize datatype converter with ours
> DatatypeConverter.setDatatypeConverter(DatatypeConverterImpl.theInstance);
>
> try {
> setEventHandler(this);
> } catch (JAXBException e) {
> throw new AssertionError(e); // impossible
> }
> }
>
> public UnmarshallerHandler getUnmarshallerHandler() {
> return getUnmarshallerHandler(true,null);
> }
>
> private SAXConnector getUnmarshallerHandler( boolean intern, JaxBeanInfo expectedType ) {
> XmlVisitor h = createUnmarshallerHandler(null,false,expectedType);
> if(intern)
> h = new InterningXmlVisitor(h);
> return new SAXConnector(h,null);
> }
>
> /**
> * Creates and configures a new unmarshalling pipe line.
> * Depending on the setting, we put a validator as a filter.
> *
> * @return
> * A component that implements both {_at_link UnmarshallerHandler}
> * and {_at_link ValidationEventHandler}. All the parsing errors
> * should be reported to this error handler for the unmarshalling
> * process to work correctly.
> *
> * Also, returned handler expects all the XML names to be interned.
> *
> */
> public final XmlVisitor createUnmarshallerHandler(InfosetScanner scanner, boolean inplace, JaxBeanInfo expectedType ) {
>
> coordinator.reset(scanner,inplace,expectedType);
> XmlVisitor unmarshaller = coordinator;
>
> // delegate to JAXP 1.3 for validation if the client provided a schema
> if (schema != null)
> unmarshaller = new ValidatingUnmarshaller(schema,unmarshaller);
>
> if(attachmentUnmarshaller!=null && attachmentUnmarshaller.isXOPPackage())
> unmarshaller = new MTOMDecorator(this,unmarshaller,attachmentUnmarshaller);
>
> return unmarshaller;
> }
>
> private static final DefaultHandler dummyHandler = new DefaultHandler();
>
> public static boolean needsInterning( XMLReader reader ) {
> // attempt to set it to true, which could fail
> try {
> reader.setFeature("http://xml.org/sax/features/string-interning",true);
> } catch (SAXException e) {
> ;
> }
>
> try {
> if( reader.getFeature("http://xml.org/sax/features/string-interning") )
> return false; // no need for intern
> } catch (SAXException e) {
> ; // unrecognized/unsupported
> }
> // otherwise we need intern
> return true;
> }
>
> protected Object unmarshal( XMLReader reader, InputSource source ) throws JAXBException {
> return unmarshal0(reader,source,null);
> }
>
> protected <T> JAXBElement<T> unmarshal( XMLReader reader, InputSource source, Class<T> expectedType ) throws JAXBException {
> if(expectedType==null)
> throw new IllegalArgumentException();
> return (JAXBElement)unmarshal0(reader,source,getBeanInfo(expectedType));
> }
> private Object unmarshal0( XMLReader reader, InputSource source, JaxBeanInfo expectedType ) throws JAXBException {
>
> SAXConnector connector = getUnmarshallerHandler(needsInterning(reader),expectedType);
>
> reader.setContentHandler(connector);
> // saxErrorHandler will be set by the getUnmarshallerHandler method.
> // configure XMLReader so that the error will be sent to it.
> // This is essential for the UnmarshallerHandler to be able to abort
> // unmarshalling when an error is found.
> //
> // Note that when this XMLReader is provided by the client code,
> // it might be already configured to call a client error handler.
> // This will clobber such handler, if any.
> //
> // Ryan noted that we might want to report errors to such a client
> // error handler as well.
> reader.setErrorHandler(coordinator);
>
> try {
> reader.parse(source);
> } catch( IOException e ) {
> throw new JAXBException(e);
> } catch( SAXException e ) {
> throw createUnmarshalException(e);
> }
>
> Object result = connector.getResult();
>
> // avoid keeping unnecessary references too long to let the GC
> // reclaim more memory.
> // setting null upsets some parsers, so use a dummy instance instead.
> reader.setContentHandler(dummyHandler);
> reader.setErrorHandler(dummyHandler);
>
> return result;
> }
>
> @Override
> public <T> JAXBElement<T> unmarshal( Source source, Class<T> expectedType ) throws JAXBException {
> if(source instanceof SAXSource) {
> SAXSource ss = (SAXSource)source;
>
> XMLReader reader = ss.getXMLReader();
> if( reader == null )
> reader = getXMLReader();
>
> return unmarshal( reader, ss.getInputSource(), expectedType );
> }
> if(source instanceof StreamSource) {
> return unmarshal( getXMLReader(), streamSourceToInputSource((StreamSource)source), expectedType );
> }
> if(source instanceof DOMSource)
> return unmarshal( ((DOMSource)source).getNode(), expectedType );
>
> // we don't handle other types of Source
> throw new IllegalArgumentException();
> }
>
>
> public final ValidationEventHandler getEventHandler() {
> try {
> return super.getEventHandler();
> } catch (JAXBException e) {
> // impossible
> throw new AssertionError();
> }
> }
>
> @Override
> public <T> JAXBElement<T> unmarshal(Node node, Class<T> expectedType) throws JAXBException {
> if(expectedType==null)
> throw new IllegalArgumentException();
> return (JAXBElement)unmarshal0(node,getBeanInfo(expectedType));
> }
>
> public final Object unmarshal( Node node ) throws JAXBException {
> return unmarshal0(node,null);
> }
>
> public final Object unmarshal0( Node node, JaxBeanInfo expectedType ) throws JAXBException {
> try {
> final DOMScanner scanner = new DOMScanner();
>
> InterningXmlVisitor handler = new InterningXmlVisitor(createUnmarshallerHandler(null,false,expectedType));
> scanner.setContentHandler(new SAXConnector(handler,scanner));
>
> if(node instanceof Element)
> scanner.scan((Element)node);
> else
> if(node instanceof Document)
> scanner.scan((Document)node);
> else
> // no other type of input is supported
> throw new IllegalArgumentException();
>
> return handler.getContext().getResult();
> } catch( SAXException e ) {
> throw createUnmarshalException(e);
> }
> }
>
> @Override
> public Object unmarshal(XMLStreamReader reader) throws JAXBException {
> return unmarshal0(reader,null);
> }
>
> @Override
> public <T> JAXBElement<T> unmarshal(XMLStreamReader reader, Class<T> expectedType) throws JAXBException {
> if(expectedType==null)
> throw new IllegalArgumentException();
> return (JAXBElement)unmarshal0(reader,getBeanInfo(expectedType));
> }
>
> public Object unmarshal0(XMLStreamReader reader, JaxBeanInfo expectedType) throws JAXBException {
> if (reader == null) {
> throw new IllegalArgumentException(
> Messages.format(Messages.NULL_READER));
> }
>
> int eventType = reader.getEventType();
> if (eventType != XMLStreamConstants.START_ELEMENT
> && eventType != XMLStreamConstants.START_DOCUMENT) {
> // TODO: convert eventType into event name
> throw new IllegalStateException(
> Messages.format(Messages.ILLEGAL_READER_STATE,eventType));
> }
>
> if (reader instanceof StAXDocumentParser) {
> StAXDocumentParser fastInfosetStreamReader = (StAXDocumentParser)reader;
> fastInfosetStreamReader.setStringInterning(true);
>
> XmlVisitor h = createUnmarshallerHandler(null,false,expectedType);
>
> try {
> new FastInfosetConnector(fastInfosetStreamReader, h).bridge();
> } catch (XMLStreamException e) {
> throw handleStreamException(e);
> }
>
> return h.getContext().getResult();
> } else {
> // Quick hack until SJSXP fixes 6270116
> boolean isZephyr = reader.getClass().getName().equals("com.sun.xml.stream.XMLReaderImpl");
> UnmarshallerHandler h = getUnmarshallerHandler(!isZephyr,expectedType);
>
> try {
> new XMLStreamReaderToContentHandler(reader,h).bridge();
> } catch (XMLStreamException e) {
> throw handleStreamException(e);
> }
> return h.getResult();
> }
> }
>
> @Override
> public <T> JAXBElement<T> unmarshal(XMLEventReader reader, Class<T> expectedType) throws JAXBException {
> if(expectedType==null)
> throw new IllegalArgumentException();
> return (JAXBElement)unmarshal0(reader,getBeanInfo(expectedType));
> }
>
> @Override
> public Object unmarshal(XMLEventReader reader) throws JAXBException {
> return unmarshal0(reader,null);
> }
>
> private Object unmarshal0(XMLEventReader reader,JaxBeanInfo expectedType) throws JAXBException {
> if (reader == null) {
> throw new IllegalArgumentException(
> Messages.format(Messages.NULL_READER));
> }
>
> try {
> XMLEvent event = reader.peek();
>
> if (!event.isStartElement() && !event.isStartDocument()) {
> // TODO: convert event into event name
> throw new IllegalStateException(
> Messages.format(
> Messages.ILLEGAL_READER_STATE,event.getEventType()));
> }
>
> UnmarshallerHandler h = getUnmarshallerHandler(true,expectedType);
> new XMLEventReaderToContentHandler(reader, h).bridge();
> return h.getResult();
> } catch (XMLStreamException e) {
> throw handleStreamException(e);
> }
> }
>
> // remove this method when you remove this use from BridgeImpl
> public Object unmarshal0( URL input, JaxBeanInfo expectedType ) throws JAXBException {
> return unmarshal0(getXMLReader(),new InputSource(input.toExternalForm()),expectedType);
> }
>
> private static JAXBException handleStreamException(XMLStreamException e) {
> // XMLStreamReaderToContentHandler wraps SAXException to XMLStreamException.
> // XMLStreamException doesn't print its nested stack trace when it prints
> // its stack trace, so if we wrap XMLStreamException in JAXBException,
> // it becomes harder to find out the real problem.
> // So we unwrap them here. But we don't want to unwrap too eagerly, because
> // that could throw away some meaningful exception information.
> Throwable ne = e.getNestedException();
> if(ne instanceof JAXBException)
> return (JAXBException)ne;
> if(ne instanceof SAXException)
> return new JAXBException(ne);
> return new JAXBException(e);
> }
>
> public void setProperty(String name, Object value) throws PropertyException {
> if(name.equals(FACTORY)) {
> coordinator.setFactories(value);
> return;
> }
> super.setProperty(name, value);
> }
>
> public static final String FACTORY = "com.sun.xml.bind.ObjectFactory";
>
> @Override
> public void setSchema(Schema schema) {
> this.schema = schema;
> }
>
> @Override
> public Schema getSchema() {
> return schema;
> }
>
> @Override
> public AttachmentUnmarshaller getAttachmentUnmarshaller() {
> return attachmentUnmarshaller;
> }
>
> @Override
> public void setAttachmentUnmarshaller(AttachmentUnmarshaller au) {
> this.attachmentUnmarshaller = au;
> }
>
> /**
> * @deprecated since 2.0
> */
> @Override
> public boolean isValidating() {
> throw new UnsupportedOperationException();
> }
>
> /**
> * @deprecated since 2.0
> */
> @Override
> public void setValidating(boolean validating) {
> throw new UnsupportedOperationException();
> }
>
> @Override
> public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) {
> if(type==null)
> throw new IllegalArgumentException();
> coordinator.putAdapter(type,adapter);
> }
>
> @Override
> public <A extends XmlAdapter> A getAdapter(Class<A> type) {
> if(type==null)
> throw new IllegalArgumentException();
> if(coordinator.containsAdapter(type))
> // so as not to create a new instance when this method is called
> return coordinator.getAdapter(type);
> else
> return null;
> }
>
> // opening up for public use
> public UnmarshalException createUnmarshalException( SAXException e ) {
> return super.createUnmarshalException(e);
> }
>
>
> /**
> * Default error handling behavior fot {_at_link Unmarshaller}.
> */
> public boolean handleEvent(ValidationEvent event) {
> return event.getSeverity()!=ValidationEvent.FATAL_ERROR;
> }
>
> private static InputSource streamSourceToInputSource( StreamSource ss ) {
> InputSource is = new InputSource();
> is.setSystemId( ss.getSystemId() );
> is.setByteStream( ss.getInputStream() );
> is.setCharacterStream( ss.getReader() );
>
> return is;
> }
>
> public <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) throws JAXBException {
> return context.getBeanInfo(clazz,true);
> }
> }
>
>
> ------------------------------------------------------------------------
>
> package com.sun.xml.bind.v2.runtime.unmarshaller;
>
> import com.sun.xml.bind.WhiteSpaceProcessor;
> import com.sun.xml.fastinfoset.stax.StAXDocumentParser;
> import javax.xml.bind.ValidationEventLocator;
> import javax.xml.bind.helpers.ValidationEventLocatorImpl;
>
> import javax.xml.stream.XMLStreamConstants;
> import javax.xml.stream.XMLStreamException;
> import org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
> import org.xml.sax.Locator;
> import org.xml.sax.SAXException;
>
>
> public class FastInfosetConnector {
>
> // event source
> private final StAXDocumentParser fastInfosetStreamReader;
>
> // event sink
> private final XmlVisitor visitor;
>
> // Flag set to true if there is octets instead of characters
> boolean hasBase64Data = false;
> // Flag set to true if the first chunk of CIIs
> boolean firstCIIChunk = true;
>
> // Buffer for octets
> private Base64Data base64Data = new Base64Data();
>
> // Buffer for characters
> private StringBuilder buffer = new StringBuilder();
>
> public FastInfosetConnector(StAXDocumentParser fastInfosetStreamReader,
> XmlVisitor visitor) {
> this.fastInfosetStreamReader = fastInfosetStreamReader;
> this.visitor = visitor;
> }
>
> public void bridge() throws XMLStreamException {
> try {
> handleStartDocument();
>
> while (fastInfosetStreamReader.hasNext()) {
> final int event = fastInfosetStreamReader.next();
> switch (event) {
> case XMLStreamConstants.START_ELEMENT :
> handleStartElement();
> break;
> case XMLStreamConstants.END_ELEMENT :
> handleEndElement();
> break;
> case XMLStreamConstants.CHARACTERS :
> handleCharacters();
> break;
> }
> }
>
> handleEndDocument();
> } catch (SAXException e) {
> throw new XMLStreamException(e);
> }
> }
>
> private void handleEndDocument() throws SAXException {
> visitor.endDocument();
> }
>
> private void handleStartDocument() throws SAXException {
> final Locator locator = new Locator() {
> public int getColumnNumber() {
> return fastInfosetStreamReader.getLocation().getColumnNumber();
> }
> public int getLineNumber() {
> return fastInfosetStreamReader.getLocation().getLineNumber();
> }
> public String getPublicId() {
> return fastInfosetStreamReader.getLocation().getPublicId();
> }
> public String getSystemId() {
> return fastInfosetStreamReader.getLocation().getSystemId();
> }
> };
>
> visitor.startDocument(new LocatorEx() {
> public ValidationEventLocator getLocation() {
> return new ValidationEventLocatorImpl(locator);
> }
> public String getPublicId() {
> return locator.getPublicId();
> }
> public String getSystemId() {
> return locator.getSystemId();
> }
> public int getLineNumber() {
> return locator.getLineNumber();
> }
> public int getColumnNumber() {
> return locator.getColumnNumber();
> }
> });
> }
>
> private void handleStartElement() throws XMLStreamException {
> try {
> processText(true);
>
> for (int i = 0; i < fastInfosetStreamReader.getNamespaceCount(); i++) {
> visitor.startPrefixMapping(fastInfosetStreamReader.getNamespacePrefix(i),
> fastInfosetStreamReader.getNamespaceURI(i));
> }
>
> visitor.startElement(
> fastInfosetStreamReader.getNamespaceURI(),
> fastInfosetStreamReader.getLocalName(),
> fastInfosetStreamReader.getNameString(),
> fastInfosetStreamReader.getAttributesHolder());
> } catch (SAXException e) {
> throw new XMLStreamException(e);
> }
> }
>
> private void handleCharacters() throws XMLStreamException {
> if (visitor.expectText()) {
> // If the first chunk of CIIs and character data is present
> if (firstCIIChunk &&
> fastInfosetStreamReader.getTextAlgorithmBytes() == null) {
> buffer.append(fastInfosetStreamReader.getTextCharacters(),
> fastInfosetStreamReader.getTextStart(),
> fastInfosetStreamReader.getTextLength());
> firstCIIChunk = false;
> // If the first chunk of CIIs and octet data is present
> } else if (firstCIIChunk &&
> fastInfosetStreamReader.getTextAlgorithmIndex() == EncodingAlgorithmIndexes.BASE64) {
> firstCIIChunk = false;
> hasBase64Data = true;
> // Clone the octets
> base64Data.set(fastInfosetStreamReader.getTextAlgorithmBytesClone(), "");
> return;
> // If a subsequent sequential chunk of CIIs
> } else {
> // If the first chunk is octet data
> if (hasBase64Data) {
> // Append base64 encoded octets to the character buffer
> buffer.append(base64Data);
> hasBase64Data = false;
> }
>
> // Append the second or subsequence chunk of CIIs to the buffer
> buffer.append(fastInfosetStreamReader.getTextCharacters(),
> fastInfosetStreamReader.getTextStart(),
> fastInfosetStreamReader.getTextLength());
> }
>
> }
> }
>
> private void handleEndElement() throws XMLStreamException {
> try {
> processText(false);
>
> visitor.endElement(
> fastInfosetStreamReader.getNamespaceURI(),
> fastInfosetStreamReader.getLocalName(),
> fastInfosetStreamReader.getNameString());
>
> for (int i = fastInfosetStreamReader.getNamespaceCount() - 1; i >= 0; i--) {
> visitor.endPrefixMapping(fastInfosetStreamReader.getNamespacePrefix(i));
> }
> } catch (SAXException e) {
> throw new XMLStreamException(e);
> }
> }
>
> private void processText(boolean ignorable) throws SAXException {
> if (firstCIIChunk == true) {
> return;
> }
> firstCIIChunk = true;
>
> // If there are characters
> if (buffer.length() > 0) {
> if (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer)) {
> visitor.text(buffer);
> }
>
> // avoid excessive object allocation, but also avoid
> // keeping a huge array inside StringBuffer.
> if (buffer.length()<1024) {
> buffer.setLength(0);
> } else {
> buffer = new StringBuilder();
> }
> // If there are octets
> } else if (hasBase64Data) {
> visitor.text(base64Data);
> hasBase64Data = false;
> }
> }
> }
>
>
>
> ------------------------------------------------------------------------
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_fi.dev.java.net
> For additional commands, e-mail: dev-help_at_fi.dev.java.net

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109