/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Center of the unmarshalling.
*
* <p>
* This object is responsible for coordinating {@link Loader}s to
* perform the whole unmarshalling.
*
* @author Kohsuke Kawaguchi
*/
implements NamespaceContext, ValidationEventHandler, ErrorHandler, XmlVisitor, XmlVisitor.TextPredictor {
/**
* Root state.
*/
/**
* The currently active state.
*/
static {
}
/** Root object that is being unmarshalled. */
/**
* If non-null, this unmarshaller will unmarshal {@code JAXBElement<EXPECTEDTYPE>}
* regardless of the tag name, as opposed to deciding the root object by using
* the tag name.
*
* The property has a package-level access, because we cannot copy this value
* to {@link UnmarshallingContext} when it is created. The property
* on {@link Unmarshaller} could be changed after the handler is created.
*/
/**
*/
/**
* This flag is set to true at the startDocument event
* and false at the endDocument event.
*
* Until the first document is unmarshalled, we don't
* want to return an object. So this variable is initialized
* to true.
*/
private boolean isUnmarshalInProgress = true;
private boolean aborted = false;
/**
* If the unmarshaller is doing associative unmarshalling,
* this field is initialized to non-null.
*/
/**
* Indicates whether we are doing in-place unmarshalling
* or not.
*
* <p>
* This flag is unused when {@link #assoc}==null.
* If it's non-null, then <tt>true</tt> indicates
* that we are doing in-place associative unmarshalling.
* If <tt>false</tt>, then we are doing associative unmarshalling
* without object reuse.
*/
private boolean isInplaceMode;
/**
* This object is consulted to get the element object for
* the current element event.
*
* This is used when we are building an association map.
*/
/**
* @see XmlVisitor#startDocument(LocatorEx, NamespaceContext)
*/
/**
*/
/**
* User-supplied {@link ClassLoader} for converting name to {@link Class}.
* For backward compatibility, when null, use thread context classloader.
*/
/**
* State information for each element.
*/
public final class State {
/**
* Loader that owns this element.
*/
/**
* Once {@link #loader} is completed, this receiver
* receives the result.
*/
/**
* Object being unmarshalled by this {@link #loader}.
*/
/**
* Hack for making JAXBElement unmarshalling work.
*
* <p>
* While the unmarshalling is in progress, the {@link #target} field stores the object being unmarshalled.
* This makes it convenient to keep track of the unmarshalling activity in context of XML infoset, but
* since there's only one {@link State} per element, this mechanism only works when there's one object
* per element, which breaks down when we have {@link JAXBElement}, since the presence of JAXBElement
* requires that we have two objects unmarshalled (a JAXBElement X and a value object Y bound to an XML type.)
*
* <p>
* So to make room for storing both, this {@link #backup} field is used. When we create X instance
* in the above example, we set that to {@code state.prev.target} and displace its old value to
* {@code state.prev.backup} (where Y goes to {@code state.target}.) Upon the completion of the unmarshalling
* of Y, we revert this.
*
* <p>
* it thereby makes {@link Receiver} mechanism simpler.
*
* <p>
* Yes, I know this is a hack, and no, I'm not proud of it.
*
* @see ElementBeanInfoImpl.IntercepterLoader#startElement(State, TagName)
* @see ElementBeanInfoImpl.IntercepterLoader#intercept(State, Object)
*/
/**
* Number of {@link UnmarshallingContext#nsBind}s declared thus far.
* (The value of {@link UnmarshallingContext#nsLen} when this state is pushed.
*/
private int numNsDecl;
/**
* If this element has an element default value.
*
* This should be set by either a parent {@link Loader} when
* {@link Loader#childElement(State, TagName)} is called
* or by a child {@link Loader} when
* {@link Loader#startElement(State, TagName)} is called.
*/
/**
* {@link State} for the parent element
*
* {@link State} objects form a doubly linked list.
*/
public boolean nil = false;
/**
* Gets the context.
*/
return UnmarshallingContext.this;
}
}
private void push() {
current = n;
}
private void pop() {
nil = false;
intercepter = null;
}
}
/**
* Stub to the user-specified factory method.
*/
private static class Factory {
this.factorInstance = factorInstance;
}
try {
} catch (IllegalAccessException e) {
getInstance().handleError(e,false);
} catch (InvocationTargetException e) {
getInstance().handleError(e,false);
}
return null; // can never be executed
}
}
/**
* Creates a new unmarshaller.
*
* @param assoc
* Must be both non-null when the unmarshaller does the
* in-place unmarshalling. Otherwise must be both null.
*/
}
public void reset(InfosetScanner scanner,boolean isInplaceMode, JaxBeanInfo expectedType, IDResolver idResolver) {
this.isInplaceMode = isInplaceMode;
this.expectedType = expectedType;
this.idResolver = idResolver;
}
}
return current;
}
/**
* On top of {@link JAXBContextImpl#selectRootLoader(State, TagName)},
* this method also consults {@link ClassResolver}.
*
* @throws SAXException
* if {@link ValidationEventHandler} reported a failure.
*/
try {
if(l!=null) return l;
if(classResolver!=null) {
}
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handleError(e);
}
return null;
}
/**
* Allocates a few more {@link State}s.
*
* Allocating multiple {@link State}s at once allows those objects
* to be allocated near each other, which reduces the working set
* of CPU. It improves the chance the relevant data is in the cache.
*/
private void allocateMoreStates() {
// this method should be used only when we run out of a state.
for( int i=0; i<8; i++ )
s = new State(s);
}
public void clearStates() {
}
}
/**
* User-specified factory methods.
*/
if(factoryInstances==null) {
return;
}
if(factoryInstances instanceof Object[]) {
// look for all the public methods inlcuding derived ones
}
} else {
}
}
// look for methods whose signature is T createXXX()
continue;
continue;
}
}
this.environmentNamespaceContext = nsContext;
// reset the object
patchersLen=0;
aborted = false;
isUnmarshalInProgress = true;
nsLen=0;
if(expectedType!=null)
else
idResolver.startDocument(this);
}
try {
} finally {
}
}
// remember the current element if we are interested in it.
// because the inner peer might not be found while we consume
// the enter element token, we need to keep this information
// longer than this callback. That's why we assign it to a field.
// tell the parent about the new child
// and tell the new child that you are activated
}
try {
// send the default value into the unmarshaller instead
}
}
} finally {
}
}
try {
// tell the child that your time is up
// child.pop will erase them so store them now
// then let the parent know
if(intercepter!=null)
} finally {
}
}
runPatchers();
isUnmarshalInProgress = false;
// at the successful completion, scope must be all closed
}
/**
* You should be always calling this through {@link TextPredictor}.
*/
public boolean expectText() {
}
/**
* You should be always getting {@link TextPredictor} from {@link XmlVisitor}.
*/
return this;
}
return this;
}
/**
* Gets the result of the unmarshalling
*/
throw new IllegalStateException();
// there was an error.
}
void clearResult() {
if (isUnmarshalInProgress) {
throw new IllegalStateException();
}
}
/**
* Creates a new instance of the specified class.
* In the unmarshaller, we need to check the user-specified factory class.
*/
return factory.createInstance();
}
}
/**
* Creates a new instance of the specified class.
* In the unmarshaller, we need to check the user-specified factory class.
*/
return factory.createInstance();
}
try {
return beanInfo.createInstance(this);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (InstantiationException e) {
}
return null; // can never be here
}
//
//
// error handling
//
//
/**
* to recover. If the canRecover flag is false, regardless
* of the client instruction, an exception will be thrown.
*
* Only if the flag is true and the user wants to recover from an error,
* the method returns normally.
*
* The thrown exception will be catched by the unmarshaller.
*/
// if the handler says "abort", we will not return the object
// from the unmarshaller.getResult()
if( !canRecover || !recover )
new UnmarshalException(
event.getMessage(),
event.getLinkedException() ) );
}
try {
// if the handler says "abort", we will not return the object.
return recover;
} catch( RuntimeException re ) {
// if client event handler causes a runtime exception, then we
// have to return false.
return false;
}
}
/**
* Reports an exception found during the unmarshalling to the user.
* This method is a convenience method that calls into
* {@link #handleEvent(ValidationEvent, boolean)}
*/
handleError(e,true);
}
handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,e.getMessage(),locator.getLocation(),e),canRecover);
}
}
return locator.getLocation();
}
/**
* Gets the current source location information in SAX {@link Locator}.
* <p>
* Sometimes the unmarshaller works against a different kind of XML source,
* making this information meaningless.
*/
/**
* Called when there's no corresponding ID value.
*/
loc.getLocation()), true );
}
//
//
//
//
/**
* Submitted patchers in the order they've submitted.
* initialize it with null.
*/
/**
* Adds a job that will be executed at the last of the unmarshalling.
* for other purposes as well.
*
* @param job
* The run method of this object is called.
*/
// re-allocate buffer if necessary
}
}
/** Executes all the patchers. */
for( int i=0; i<patchersLen; i++ ) {
}
}
}
/**
* Adds the object which is currently being unmarshalled
* to the ID table.
*
* @return
* Returns the value passed as the parameter.
* This is a hack, but this makes it easier for ID
* transducer to do its job.
*/
// TODO: what shall we do if the ID is already declared?
//
// throwing an exception is one way. Overwriting the previous one
// is another way. The latter allows us to process invalid documents,
// while the former makes it impossible to handle them.
//
// I prefer to be flexible in terms of invalid document handling,
// so chose not to throw an exception.
//
// I believe this is an implementation choice, not the spec issue.
// -kk
// Hmm...
// in cases such as when ID is used as an attribute, or as @XmlValue
// the target wilil be current.target.
// but in some other cases, such as when ID is used as a child element
// or a value of JAXBElement, it's current.prev.target.
// I don't know if this detection logic is complete
if(o==null)
return id;
}
/**
* Looks up the ID table and gets associated object.
*
* <p>
* The exception thrown from {@link Callable#call()} means the unmarshaller should abort
* right away.
*
* @see IDResolver#resolve(String, Class)
*/
}
//
//
// namespace binding maintainance
//
//
// expand the buffer
nsBind=n;
}
}
nsLen-=2;
}
return XMLConstants.XML_NS_URI;
return nsBind[i+1];
}
// temporary workaround until Zephyr fixes 6337180
// by default, the default ns is bound to "".
// but allow environmentNamespaceContext to take precedence
return "";
// unresolved. error.
return null;
}
/**
* Returns a list of prefixes newly declared on the current element.
*
* @return
* A possible zero-length array of prefixes. The default prefix
* is represented by the empty string.
*/
}
/**
* Returns a list of all in-scope prefixes.
*
* @return
* A possible zero-length array of prefixes. The default prefix
* is represented by the empty string.
*/
return getPrefixList(0);
}
for( int i=0; i<r.length; i++ )
return r;
}
// NamespaceContext2 implementation
//
// TODO: could be implemented much faster
// wrap it into unmodifiable list so that the remove method
// will throw UnsupportedOperationException.
return Collections.unmodifiableList(
}
throw new IllegalArgumentException();
return a;
}
return a;
}
// make sure that this prefix is still effective.
return a;
}
throw new IllegalArgumentException();
return XMLConstants.XML_NS_PREFIX;
return XMLConstants.XMLNS_ATTRIBUTE;
// make sure that this prefix is still effective.
return nsBind[i];
return null;
}
throw new IllegalArgumentException();
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
return resolveNamespacePrefix(prefix);
}
//
//
//
// scope management
//
//
//
/**
* Points to the top of the scope stack (=size-1).
*/
{
}
/**
* Starts a new packing scope.
*
* <p>
* This method allocates a specified number of fresh {@link Scope} objects.
* They can be accessed by the {@link #getScope} method until the corresponding
* {@link #endScope} method is invoked.
*
* <p>
* A new scope will mask the currently active scope. Only one frame of {@link Scope}s
* can be accessed at any given time.
*
* @param frameSize
* The # of slots to be allocated.
*/
// reallocation
s[i] = new Scope(this);
scopes = s;
}
}
/**
* Ends the current packing scope.
*
* <p>
* If any packing in progress will be finalized by this method.
*
* @param frameSize
* The same size that gets passed to the {@link #startScope(int)}
* method.
*/
try {
} catch (AccessorException e) {
handleError(e);
// the error might have left scopes in inconsistent state,
// so replace them by fresh ones
}
}
/**
* Gets the currently active {@link Scope}.
*
* @param offset
* a number between [0,frameSize)
*
* @return
* always a valid {@link Scope} object.
*/
}
//
//
//
//
//
//
//
/**
* Root loader that uses the tag name and possibly its @xsi:type
* to decide how to start unmarshalling.
*/
/**
* Receives the root element and determines how to start
* unmarshalling.
*/
return;
}
// the registry doesn't know about this element.
// try its xsi:type
// we don't even know its xsi:type
reportUnexpectedChildElement(ea,false);
return;
}
}
}
}
}
}
}
/**
* Root loader that uses {@link UnmarshallingContext#expectedType}
* to decide how to start unmarshalling.
*/
/**
* Receives the root element and determines how to start
* unmarshalling.
*/
// unmarshals the specified type
// this is bit wasteful, as in theory we should have each expectedType keep
// nillable version --- but that increases the combination from two to four,
// which adds the resident memory footprint. Since XsiNilLoader is small,
// I intentionally allocate a new instance freshly.
}
e.setValue(o);
}
}
//
// in-place unmarshalling related capabilities
//
/**
* Notifies the context about the inner peer of the current element.
*
* <p>
* If the unmarshalling is building the association, the context
* will use this information. Otherwise it will be just ignored.
*/
}
/**
* Gets the inner peer JAXB object associated with the current element.
*
* @return
* null if the current element doesn't have an inner peer,
* or if we are not doing the in-place unmarshalling.
*/
else
return null;
}
/**
* Notifies the context about the outer peer of the current element.
*
* <p>
* If the unmarshalling is building the association, the context
* will use this information. Otherwise it will be just ignored.
*/
}
/**
* Gets the outer peer JAXB object associated with the current element.
*
* @return
* null if the current element doesn't have an inner peer,
* or if we are not doing the in-place unmarshalling.
*/
else
return null;
}
/**
* Gets the xmime:contentType value for the current object.
*
* @see JAXBContextImpl#getXMIMEContentType(Object)
*/
/*
this won't work when the class is like
class Foo {
@XmlValue Image img;
}
because the target will return Foo, not the class enclosing Foo
which will have xmime:contentType
*/
return getJAXBContext().getXMIMEContentType(t);
}
/**
* When called from within the realm of the unmarshaller, this method
* returns the current {@link UnmarshallingContext} in charge.
*/
}
/**
* Allows to access elements which are expected in current state.
* Useful for getting elements for current parent.
*
* @return
*/
try {
State s = getCurrentState();
} finally {
}
}
/**
* Allows to access attributes which are expected in current state.
* Useful for getting attributes for current parent.
*
* @return
*/
try {
State s = getCurrentState();
} finally {
}
}
/**
* Gets StructureLoader if used as loader.
* Useful when determining if element is mixed or not.
*
*/
return null;
}
}