DeserializerImplpublic class DeserializerImpl extends org.apache.axis.message.SOAPHandler implements Callback, Deserializer, javax.xml.rpc.encoding.DeserializerThe Deserializer base class. |
Fields Summary |
---|
protected static Log | log | protected Object | value | private final boolean | debugEnabled | protected boolean | isEnded | protected Vector | targets | protected QName | defaultType | protected boolean | componentsReadyFlag | private HashSet | activeDeserializersA set of sub-deserializers whose values must complete before our
value is complete. | protected boolean | isHref | protected boolean | isNil | protected String | id |
Constructors Summary |
---|
public DeserializerImpl() // Set to the id of the element
|
Methods Summary |
---|
public void | addChildDeserializer(Deserializer dSer)
// Keep track of our active deserializers. This enables us to figure
// out whether or not we're really done in the case where we get to
// our end tag, but still have open hrefs for members.
if (activeDeserializers != null) {
activeDeserializers.add(dSer);
}
// In concert with the above, we make sure each field deserializer
// lets us know when it's done so we can take it off our list.
dSer.registerValueTarget(new CallbackTarget(this, dSer));
| public boolean | componentsReady()Some deserializers (ArrayDeserializer) require
all of the component values to be known before the
value is complete.
(For the ArrayDeserializer this is important because
the elements are stored in an ArrayList, and all values
must be known before the ArrayList is converted into the
expected array.
This routine is used to indicate when the components are ready.
The default (true) is useful for most Deserializers.
return (componentsReadyFlag ||
(!isHref && isEnded && activeDeserializers.isEmpty()));
| public final void | endElement(java.lang.String namespace, java.lang.String localName, DeserializationContext context)endElement is called when the end element tag is reached.
It handles href/id information for multi-ref processing
and invokes the valueComplete() method of the deserializer
which sets the targets with the deserialized value.
super.endElement(namespace, localName, context);
isEnded = true;
if (!isHref) {
onEndElement(namespace, localName, context);
}
// Time to call valueComplete to copy the value to
// the targets. First a call is made to componentsReady
// to ensure that all components are ready.
if (componentsReady()) {
valueComplete();
}
// If this element has an id, then associate the value with the id.
// Subsequent hrefs to the id will obtain the value directly.
// This is necessary for proper multi-reference deserialization.
if (id != null) {
context.addObjectById(id, value);
if (debugEnabled) {
log.debug(Messages.getMessage("deserPutValueDebug00", "" + value, id));
}
}
| public javax.xml.namespace.QName | getDefaultType()
return defaultType;
| public java.lang.String | getMechanismType()JAX-RPC compliant method which returns mechanism type.
return Constants.AXIS_SAX;
| public java.lang.Object | getValue()Get the deserialized value.
return value;
| public java.lang.Object | getValue(java.lang.Object hint)If the deserializer has component values (like ArrayDeserializer)
this method gets the specific component via the hint.
The default implementation returns null.
return null;
| public java.util.Vector | getValueTargets()Get the Value Targets of the Deserializer.
return targets;
| public void | moveValueTargets(Deserializer other)Move someone else's targets to our own (see DeserializationContext)
The DeserializationContext only allows one Deserializer to
wait for a unknown multi-ref'ed value. So to ensure
that all of the targets are updated, this method is invoked
to copy the Target objects to the waiting Deserializer.
if ((other == null) || (other.getValueTargets() == null)) {
return;
}
if (targets == null) {
targets = new Vector();
}
targets.addAll(other.getValueTargets());
other.removeValueTargets();
| public void | onEndElement(java.lang.String namespace, java.lang.String localName, DeserializationContext context)onEndElement is called by endElement. It is not called
if the element has an href.
// If we only have SAX events, but someone really wanted a
// value, try sending them the contents of this element
// as a String...
// ??? Is this the right thing to do here?
if (this.getClass().equals(DeserializerImpl.class) &&
targets != null &&
!targets.isEmpty()) {
StringWriter writer = new StringWriter();
SerializationContext serContext =
new SerializationContext(writer,
context.getMessageContext());
serContext.setSendDecl(false);
SAXOutputter so = null;
so = new SAXOutputter(serContext);
context.getCurElement().publishContents(so);
if (!isNil) {
value = writer.getBuffer().toString();
}
}
| public org.apache.axis.message.SOAPHandler | onStartChild(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, DeserializationContext context)onStartChild is called on each child element.
The default behavior supplied by DeserializationImpl is to do nothing.
A specific deserializer may perform other tasks. For example a
BeanDeserializer will construct a deserializer for the indicated
property and return it.
return null;
| public void | onStartElement(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, DeserializationContext context)This method is invoked after startElement when the element requires
deserialization (i.e. the element is not an href and the value is not nil.)
DeserializerImpl provides default behavior, which simply
involves obtaining a correct Deserializer and plugging its handler.
// If I'm the base class, try replacing myself with an
// appropriate deserializer gleaned from type info.
if (this.getClass().equals(DeserializerImpl.class)) {
QName type = context.getTypeFromAttributes(namespace,
localName,
attributes);
// If no type is specified, use the defaultType if available.
// xsd:string is used if no type is provided.
if (type == null) {
type = defaultType;
if (type == null) {
type = Constants.XSD_STRING;
}
}
if (debugEnabled) {
log.debug(Messages.getMessage("gotType00", "Deser", "" + type));
}
// We know we're deserializing, but we don't have
// a specific deserializer. So create one using the
// attribute type qname.
if (type != null) {
Deserializer dser = context.getDeserializerForType(type);
if (dser == null) {
dser = context.getDeserializerForClass(null);
}
if (dser != null) {
// Move the value targets to the new deserializer
dser.moveValueTargets(this);
context.replaceElementHandler((SOAPHandler) dser);
// And don't forget to give it the start event...
boolean isRef = context.isProcessingRef();
context.setProcessingRef(true);
dser.startElement(namespace, localName, prefix,
attributes, context);
context.setProcessingRef(isRef);
} else {
throw new SAXException(
Messages.getMessage("noDeser00", "" + type));
}
}
}
| public void | registerValueTarget(Target target)For deserializers of non-primitives, the value may not be
known until later (due to multi-referencing). In such
cases the deserializer registers Target object(s). When
the value is known, the set(value) will be invoked for
each Target registered with the Deserializer. The Target
object abstracts the function of setting a target with a
value. See the Target interface for more info.
if (targets == null) {
targets = new Vector();
}
targets.addElement(target);
| public void | removeValueTargets()Remove the Value Targets of the Deserializer.
if (targets != null) {
targets = null;
}
| public void | setChildValue(java.lang.Object value, java.lang.Object hint)If the deserializer has component values (like ArrayDeserializer)
this method sets the specific component via the hint.
The default implementation does nothing.
| public void | setDefaultType(javax.xml.namespace.QName qName)In some circumstances an element may not have
a type attribute, but a default type qname is known from
information in the container. For example,
an element of an array may not have a type= attribute,
so the default qname is the component type of the array.
This method is used to communicate the default type information
to the deserializer.
defaultType = qName;
| public void | setValue(java.lang.Object value)Set the deserialized value.
this.value = value;
| public void | setValue(java.lang.Object value, java.lang.Object hint)
if (hint instanceof Deserializer) {
// This one's done
activeDeserializers.remove(hint);
// If we're past the end of our XML, and this is the last one,
// our value has been assembled completely.
if (componentsReady()) {
// Got everything we need, call valueComplete()
valueComplete();
}
}
| public void | startElement(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, DeserializationContext context)This method is invoked when an element start tag is encountered.
DeserializerImpl provides default behavior, which involves the following:
- directly handling the deserialization of a nill value
- handling the registration of the id value.
- handling the registration of a fixup if this element is an href.
- calling onStartElement to do the actual deserialization if not nill or href cases.
super.startElement(namespace, localName, prefix, attributes, context);
// If the nil attribute is present and true, set the value to null
// and return since there is nothing to deserialize.
if (context.isNil(attributes)) {
value = null;
isNil = true;
return;
}
SOAPConstants soapConstants = context.getSOAPConstants();
// If this element has an id, then associate the value with the id.
// (Prior to this association, the MessageElement of the element is
// associated with the id. Failure to replace the MessageElement at this
// point will cause an infinite loop during deserialization if the
// current element contains child elements that cause an href back to this id.)
// Also note that that endElement() method is responsible for the final
// association of this id with the completed value.
id = attributes.getValue("id");
if (id != null) {
context.addObjectById(id, value);
if (debugEnabled) {
log.debug(Messages.getMessage("deserInitPutValueDebug00", "" + value, id));
}
context.registerFixup("#" + id, this);
}
String href = attributes.getValue(soapConstants.getAttrHref());
if (href != null) {
isHref = true;
Object ref = context.getObjectByRef(href);
if (debugEnabled) {
log.debug(Messages.getMessage(
"gotForID00",
new String[] {"" + ref, href, (ref == null ? "*null*" : ref.getClass().toString())}));
}
if (ref == null) {
// Nothing yet... register for later interest.
context.registerFixup(href, this);
return;
}
if (ref instanceof MessageElement) {
context.replaceElementHandler(new EnvelopeHandler(this));
SAX2EventRecorder r = context.getRecorder();
context.setRecorder(null);
((MessageElement)ref).publishToHandler((DefaultHandler) context);
context.setRecorder(r);
} else {
if( !href.startsWith("#") && defaultType != null && ref instanceof Part ){
//For attachments this is the end of the road-- invoke deserializer
Deserializer dser = context.getDeserializerForType(defaultType );
if(null != dser){
dser.startElement(namespace, localName,
prefix, attributes,
context);
ref = dser.getValue();
}
}
// If the ref is not a MessageElement, then it must be an
// element that has already been deserialized. Use it directly.
value = ref;
componentsReadyFlag = true;
valueComplete();
}
} else {
isHref = false;
onStartElement(namespace, localName, prefix, attributes,
context);
}
| public void | valueComplete()The valueComplete() method is invoked when the
end tag of the element is read. This results
in the setting of all registered Targets (see
registerValueTarget).
Note that the valueComplete() only processes
the Targets if componentReady() returns true.
So if you override componentReady(), then your
specific Deserializer will need to call valueComplete()
when your components are ready (See ArrayDeserializer)
if (componentsReady()) {
if (targets != null) {
for (int i = 0; i < targets.size(); i++) {
Target target = (Target) targets.get(i);
target.set(value);
if (debugEnabled) {
log.debug(Messages.getMessage("setValueInTarget00",
"" + value, "" + target));
}
}
// Don't need targets any more, so clear them
removeValueTargets();
}
}
|
|