2 -- Scans the input and generates an object tree that can be written as XML.
3 Copyright (C) 2005 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package gnu
.java
.beans
.encoder
;
42 import java
.beans
.Expression
;
43 import java
.beans
.Statement
;
44 import java
.io
.OutputStream
;
45 import java
.lang
.reflect
.Array
;
46 import java
.util
.HashMap
;
47 import java
.util
.IdentityHashMap
;
48 import java
.util
.List
;
49 import java
.util
.Stack
;
51 /** <p>The <code>ScanEngine</code> is the main class of the backend of the
52 * XML persistence algorithm. It scans {@link java.beans.Expression} and
53 * {@link java.beans.Statement} instances and some raw objects via the
54 * {@link #writeObject} method and feeds it to a state machine. The
55 * state machine then constructs and object tree which is finally
56 * written as XML by a {@link Writer} implementation.</p>
58 * <p>How does it work?</p>
59 * <p>The <code>ScanEngine</code> sits below the {@link java.beans.XMLEncoder}
60 * class and is called by it exclusively. The <code>XMLEncoder</code> sends
61 * interpretive data by invoking {@link #writeExpression}, {@link #writeStatement}
62 * and {@link #writeObject}. The invocations of <code>writeExpression</code> and
63 * <code>writeStatement</code> are usually nested into each other and provide
64 * more information then necessary to generate the XML representation.
65 * Furthermore the meaning of certain <code>Expressions</code> differs
66 * depending on the enclosing elements or the inner elements have to be
67 * simply discarded.</p>
69 * <p>To cope with this state dependant nature the <code>ScanEngine</code>
70 * contains a state machine which is programmed statically (no adjustments are
71 * needed, all <code>ScanEngine</code> engines use the same setup). The
72 * <code>ScanEngine</code>'s job is to decode the <code>Expression</code>s,
73 * <code>Statement</code>s and certain objects (namely <code>String</code>,
74 * <code>null</code> objects and instances which are repeatedly provided to
75 * the encoder) into 13 low-level (event) methods, which denote the meaning of the
76 * argument. For example an <code>Expression</code> can be an array
77 * instantiation which provokes a call to {@link arrayInstantiation} or
78 * it can be a class resolution leading to a call to {@link #classResolution}.
79 * For the state machione the 13 methods are the distinct way to transit
80 * from one state to another. Whenever the <code>ScanEngine</code> calls
81 * one of the event methods the current's state successor for that event
82 * is fetched from the state machine configuration, the successpr becomes
83 * the current state and then the event method is called in the new current
84 * state. The last step allows the state instance to do something meaningful
85 * to the object tree.</p>
87 * <p>The state machine knows the concept of returning to the previous
88 * state. This is done using a stack of states which is popped every
89 * time a call to <code>writeStatement</code>, <code>writeExpression</code>
90 * in the <code>XMLEncoder</code> ends by calling the {@link #end} method.
91 * Note that due to the inheritance relationship of <code>Encoder</code>
92 * and <code>XMLEncoder</code> it is impossible for the
93 * <code>ScanEngine</code> itself to decide when an expression or statement
94 * ended. This can only be done in case of {@link #writeObject} calls because
95 * they are not nested.</p>
97 * <p>When the XML persistence mechanism reaches an object twice (and more)
98 * it should generate an XML element using the "idref" attribute and add
99 * an "id" attribute to its first instantiation. This complicates things a bit
100 * because the first instantiation will always be part of the object tree
101 * as some {@link gnu.java.beans.encoder.elements.Element} subclass instance when the
102 * second and further objects accesses are written. Therefore the {@link ObjectId}
103 * class was introduced which is shared between all the object tree elements
104 * and has the notion of an "unused" state meaning that no identification
105 * is needed. The relationship between an object and its <code>ObjectId</code>
106 * instance is stored in the <code>ScanEngine</code> and gets cleared whenever
107 * the {@link #flush} method is called. This method also writes the currently
108 * built object tree and generates the XML representation.</p>
110 * @author Robert Schuster (robertschuster@fsfe.org)
112 public class ScanEngine
115 /** Change this to true to let the ScanEngine print state transition
118 boolean DEBUG
= false;
121 * Stores the scanner engine states as values and their names as keys.
123 HashMap states
= new HashMap();
126 * Stores former scanner state and makes it possible to come back to them.
128 Stack parents
= new Stack();
131 * The currently active scanner state.
133 ScannerState current
;
136 * The root of an object tree that is later written to XML.
141 * The Writer used to generate the XML output.
145 /** Stores the relationship between objects and their {@link ObjectId} instance.
147 IdentityHashMap objects
= new IdentityHashMap();
149 public ScanEngine(OutputStream os
)
151 // TODO: Provide another Writer implementation (e.g. one that does not use
152 // the XML APIs at all).
153 writer
= new StAXWriter(os
);
156 final ScannerState start
= current
= new GenericScannerState(root
);;
159 // Use the ReportingScannerState to debug serialization issues.
160 register(ScannerState
.DEFAULT_STATE_NAME
, new IgnoringScannerState());
162 register("start", start
);
164 // Special dead-end state where all transitions are ignored.
165 register("ignoreAll", new IgnoringScannerState())
166 .setDefaultSuccessor("ignoreAll");
168 // Object reference, string reference, null object
169 start
.putSuccessor(ScannerState
.TRANSITION_OBJECT_REFERENCE
, "simple");
170 start
.putSuccessor(ScannerState
.TRANSITION_STRING_REFERENCE
, "simple");
171 start
.putSuccessor(ScannerState
.TRANSITION_NULL_OBJECT
, "simple");
172 register("simple", new GenericScannerState(root
))
173 .setDefaultSuccessor("ignoreAll");
176 start
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "classRes0");
177 register("classRes0",
178 new GenericScannerState(root
)).setDefaultSuccessor("ignoreAll");
180 // Object instantiation.
181 start
.putSuccessor(ScannerState
.TRANSITION_OBJECT_INSTANTIATION
,
183 conf
= register("newObj0", new GenericScannerState(root
));
184 conf
.setDefaultSuccessor("ignoreAll");
186 // Simply use the start state to encode method invocations inside of
188 conf
.putSuccessor(ScannerState
.TRANSITION_METHOD_INVOCATION
, "start");
190 // Primitive instantiations.
191 start
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
193 register("newPrimitive0",
194 new GenericScannerState(root
)).setDefaultSuccessor("ignoreAll");
196 // Object arrays use the ARRAY_GET transition to create setting the
198 start
.putSuccessor(ScannerState
.TRANSITION_OBJECT_ARRAY_INSTANTIATION
,
200 conf
= register("newObjectArray", new GenericScannerState(root
));
201 conf
.putSuccessor(ScannerState
.TRANSITION_ARRAY_GET
, "newOArrayGet");
202 conf
.putSuccessor(ScannerState
.TRANSITION_ARRAY_SET
, "ignoreAll");
203 conf
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "ignoreAll");
204 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
207 // Get here when a value is set in the array.
208 register("newOArrayGet",
209 conf
= new GenericScannerState(root
));
211 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
212 "newOArrayGet_ignoreFirstInteger");
214 // "newArrayGet_ignoreFirstInteger" is set up mostly identical like the "start"
215 // state. Otherwise things would not behave the same when done inside
217 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_REFERENCE
, "simple");
218 conf
.putSuccessor(ScannerState
.TRANSITION_STRING_REFERENCE
, "simple");
219 conf
.putSuccessor(ScannerState
.TRANSITION_NULL_OBJECT
, "simple");
220 conf
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "classRes0");
221 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_INSTANTIATION
, "newObj0");
222 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION
,
223 "newPrimitiveArray");
224 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_ARRAY_INSTANTIATION
,
227 conf
= register("newOArrayGet_ignoreFirstInteger",
228 new GenericScannerState(root
, 1));
230 // In non-int primitive arrays class resolutions can happen
231 // but they should be ignored.
232 conf
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "ignoreAll");
234 // Spurious object and string references occur when setting array
235 // elements. This suppresses them.
236 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
238 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_REFERENCE
, "ignoreAll");
239 conf
.putSuccessor(ScannerState
.TRANSITION_STRING_REFERENCE
, "ignoreAll");
241 conf
.setDefaultSuccessor("start");
243 // Primitive arrays use the ARRAY_SET transition to create setting the
244 // array values. This turned out to be the only working solution.
245 // When primitive arrays were handled by ARRAY_GET the values in boolean
246 // arrays were always skipped.
247 start
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION
,
248 "newPrimitiveArray");
249 conf
= register("newPrimitiveArray", new GenericScannerState(root
));
250 conf
.putSuccessor(ScannerState
.TRANSITION_ARRAY_GET
, "ignoreAll");
251 conf
.putSuccessor(ScannerState
.TRANSITION_ARRAY_SET
, "newPArraySet");
252 conf
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "ignoreAll");
253 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
256 conf
= register("newPArraySet", new GenericScannerState(root
));
257 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
258 "newPArraySet_ignoreFirstInteger");
260 // Primitive arrays ignore all kinds of non-primitive object information.
261 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_REFERENCE
,
263 conf
.putSuccessor(ScannerState
.TRANSITION_STRING_REFERENCE
, "ignoreAll");
264 conf
.putSuccessor(ScannerState
.TRANSITION_NULL_OBJECT
, "ignoreAll");
265 conf
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "ingoreAll");
266 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_INSTANTIATION
, "ignoreAll");
267 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION
,
269 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_ARRAY_INSTANTIATION
,
272 conf
= register("newPArraySet_ignoreFirstInteger",
273 new GenericScannerState(root
, 1));
275 // In non-int primitive arrays class resolutions can happen
276 // but they should be ignored.
277 conf
.putSuccessor(ScannerState
.TRANSITION_CLASS_RESOLUTION
, "ignoreAll");
279 // Spurious object and string references occur when setting array
280 // elements. This suppresses them.
281 conf
.putSuccessor(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
,
283 conf
.putSuccessor(ScannerState
.TRANSITION_OBJECT_REFERENCE
, "ignoreAll");
284 conf
.putSuccessor(ScannerState
.TRANSITION_STRING_REFERENCE
, "ignoreAll");
285 conf
.setDefaultSuccessor("start");
289 /** Registers a <code>ScannerState</code> under a certain name.
291 * @param name Name of the state
292 * @param state The <code>ScannerState</code> instance.
293 * @return The second argument.
295 private ScannerState
register(String name
, ScannerState state
)
299 states
.put(name
, state
);
304 /** Generates or returns an id for the given object which can be activated
305 * later if the object is suitable.
307 * <p>Objects are unsuitable if they are an instance of a primitive wrapper
310 * @param value The object to retrieve an id for.
311 * @return The id for the object or <code>null</code>.
313 private ObjectId
retrieveId(Object value
)
315 Class valueClass
= value
.getClass();
318 // Although multiple accesses to Class objects are not handled
319 // through ids we generate one for them, too. This allows us to detect
320 // second time references to such objects in the writeObject method
321 // and handle them in a special way.
322 if (valueClass
!= String
.class
323 && valueClass
.getSuperclass() != Number
.class
324 && valueClass
!= Boolean
.class)
326 if ((id
= (ObjectId
) objects
.get(value
)) == null)
328 id
= new ObjectId(valueClass
);
329 objects
.put(value
, id
);
336 /** Scans the argument and calls one of event methods. See
337 * the introduction of this class for details.
339 * @param expr The expression to serialize.
341 public void writeExpression(Expression expr
)
343 String methodName
= expr
.getMethodName();
344 Object
[] args
= expr
.getArguments();
345 Object target
= expr
.getTarget();
350 value
= expr
.getValue();
354 throw (InternalError
)
356 "The Expression's value should be available at this point.")
360 // TODO: What if the value is null?
362 Class valueClass
= value
.getClass();
364 if (target
== Array
.class)
366 if (methodName
.equals("newInstance"))
368 id
= retrieveId(value
);
370 Class ct
= (Class
) args
[0];
372 if (ct
.isPrimitive() || ct
== Boolean
.class || ct
== Byte
.class
373 || ct
== Short
.class || ct
== Integer
.class || ct
== Long
.class
374 || ct
== Float
.class || ct
== Double
.class)
375 primitiveArrayInstantiation(ct
.getName(),
379 objectArrayInstantiation(ct
.getName(),
385 else if (methodName
.equals("get"))
387 arrayGet(args
[1].toString());
389 // The encoder does not call the ScanEngine
390 // when an object is serialized that we already know.
391 // We test for this situation and insert the object reference
393 // Since there is already a workaround for the Class class
394 // in writeObject we have to except it from this behavior.
395 id
= (ObjectId
) objects
.get(value
);
396 if (id
!= null && valueClass
!= Class
.class)
404 else if (methodName
.equals("set"))
406 arraySet(args
[1].toString());
411 id
= retrieveId(value
);
413 if (target
instanceof Class
)
415 if (methodName
.equals("new"))
417 Class targetClass
= (Class
) target
;
419 // All primitive types have short-hand forms for their
421 if (valueClass
== Boolean
.class)
422 primitiveInstantiation("boolean", args
[0].toString());
423 else if (valueClass
== Byte
.class)
424 primitiveInstantiation("byte", args
[0].toString());
425 else if (valueClass
== Short
.class)
426 primitiveInstantiation("short", args
[0].toString());
427 else if (valueClass
== Integer
.class)
428 primitiveInstantiation("int", args
[0].toString());
429 else if (valueClass
== Long
.class)
430 primitiveInstantiation("long", args
[0].toString());
431 else if (valueClass
== Float
.class)
432 primitiveInstantiation("float", args
[0].toString());
433 else if (valueClass
== Double
.class)
434 primitiveInstantiation("double", args
[0].toString());
436 objectInstantiation(targetClass
.getName(), id
);
440 else if (value
instanceof Class
)
442 String className
= ((Class
) value
).getName();
444 // At this point we know that some *static* method will be called.
446 if (methodName
.equals("forName"))
448 // However "Class.forName" represents class resolution and has a
450 classResolution(className
);
453 else if (methodName
.equals("getField"))
455 // The same goes for "Class.getField".
456 // Note: The name of the wanted field is given in
457 // the argument array.
458 staticFieldAccess(className
, args
[0].toString());
463 // If nothing fits it is just a static method
464 // invocation which we decode as such.
465 staticMethodInvocation(className
, methodName
);
470 else if (target
instanceof List
)
472 // Special behavior for indexed get and set method for list-style
474 // The arguments are in the args array but we need them as subelements.
475 if (methodName
.equals("get"))
480 else if (methodName
.equals("set"))
487 // If nothing else could be used then this is a normal
488 // method invocation.
489 methodInvocation(methodName
);
493 * Ends the current state and returns to the last one.
499 if (DEBUG
) System
.err
.print("back from " + current
.getName());
501 ScannerState oldCurrent
= current
;
502 current
= (ScannerState
) parents
.pop();
504 if (DEBUG
) System
.err
.println(" to " + current
.getName());
508 * Returns to the last state and deletes the last element in the object tree.
512 ScannerState oldCurrent
= current
;
513 current
= (ScannerState
) parents
.pop();
518 /** Scans the argument and calls one of event methods. See
519 * the introduction of this class for details.
521 * @param stmt The statement to serialize.
523 public void writeStatement(Statement stmt
)
525 // This is a simplified version of writeExpression. Everything
526 // that would not create something that is embedded in a <void> tag
527 // is left out (instantiation, getters, ...).
528 // TODO: Is this the right thing to do?
530 String methodName
= stmt
.getMethodName();
531 Object target
= stmt
.getTarget();
532 Object
[] args
= stmt
.getArguments();
534 if (target
== Array
.class && methodName
.equals("set"))
536 arraySet(args
[1].toString());
540 if (target
instanceof List
)
542 if (methodName
.equals("set"))
549 // If nothing else could be used then this is a normal
550 // method invocation.
551 methodInvocation(methodName
);
554 /** Scans the argument and calls one of event methods. See
555 * the introduction of this class for details.
557 * @param o The object to serialize.
559 public boolean writeObject(Object o
)
565 // Handle null objects which have a special syntax.
569 else if (o
.getClass() == String
.class)
571 // Handle strings which are treated extremely special
572 // in the encoder (they are never converted into a
574 stringReference((String
) o
);
577 else if ((id
= (ObjectId
) objects
.get(o
)) != null)
579 // Multiple references to a Class object do not generate
580 // an object reference but we use the id to detect that
582 if (o
.getClass() == Class
.class)
584 classResolution(((Class
) o
).getName());
589 // If our object has a corresponding ObjectId instance
590 // then generate an objectReference. This will
591 // initialize the id (= brings it in the "used" state)
592 // when this is the first referal.
602 * Writes the currently constructed object tree out as
603 * XML and clears the object to {@link ObjectId} relations.
607 // Make all references unreachable. That means we have to generate
611 root
.traverse(writer
);
614 /** Writes the final bits if the object tree and closes the stream
624 * Does a transition from one state to another using the given event.
626 * <p>This involves saving the current state, retrieving it's
627 * successor and setting it as the current state.</p>
629 * @param transition One of {@link ScannerStates]'s transition constants.
631 private void transition(int transition
)
633 parents
.push(current
);
635 String stateName
= current
.getSuccessor(transition
);
639 System
.err
.println("from state: " + current
.getName() + "\n\troute: "
640 + ScannerState
.transitionNames
[transition
]
645 ScannerState newState
= (ScannerState
) states
.get(stateName
);
647 newState
.enter(new Context(current
.getName(), current
.getCalls()));
649 assert (newState
!= null) : "State '" + stateName
+ "' was not defined.";
654 /** Event method that denotes a (non-static) method invocation.
656 * <p>More details about this method can be found in this
657 * class' introduction.</p>
659 * @param methodName The name of the method which is called.
661 void methodInvocation(String methodName
)
663 transition(ScannerState
.TRANSITION_METHOD_INVOCATION
);
665 current
.methodInvocation(methodName
);
668 /** Event method that denotes a static method invocation.
670 * <p>More details about this method can be found in this
671 * class' introduction.</p>
673 * @param methodName The name of the method which is called.
674 * @param className The name of the class in which the method is called.
676 void staticMethodInvocation(String className
, String methodName
)
678 transition(ScannerState
.TRANSITION_STATIC_METHOD_INVOCATION
);
680 current
.staticMethodInvocation(className
, methodName
);
683 /** Event method that denotes the retrieval of a static field's value.
685 * <p>More details about this method can be found in this
686 * class' introduction.</p>
688 * @param fieldName The name of the field whose value is retrieved.
689 * @param className The name of the class in which the method is called.
691 void staticFieldAccess(String className
, String fieldName
)
693 transition(ScannerState
.TRANSITION_STATIC_FIELD_ACCESS
);
695 current
.staticFieldAccess(className
, fieldName
);
698 /** Event method that denotes the resolution of a class.
700 * <p>More details about this method can be found in this
701 * class' introduction.</p>
703 * @param className The name of the class in which the method is called.
705 void classResolution(String className
)
707 transition(ScannerState
.TRANSITION_CLASS_RESOLUTION
);
709 current
.classResolution(className
);
712 /** Event method that denotes the instantiation of an object.
714 * <p>More details about this method can be found in this
715 * class' introduction.</p>
717 * @param className The name of the class in which the method is called.
718 * @param objectId An ObjectId instance which can be activated later.
720 void objectInstantiation(String className
, ObjectId objectId
)
722 transition(ScannerState
.TRANSITION_OBJECT_INSTANTIATION
);
724 current
.objectInstantiation(className
, objectId
);
727 /** Event method that denotes the instantiation of a primitive.
729 * <p>More details about this method can be found in this
730 * class' introduction.</p>
732 * @param primitiveName One of "boolean, "byte", "short", "int", "long"
733 * , "float" or "double"
734 * @param valueAsString The value of the primitive as a String.
736 void primitiveInstantiation(String primitiveName
, String valueAsString
)
738 transition(ScannerState
.TRANSITION_PRIMITIVE_INSTANTIATION
);
740 current
.primitiveInstantiation(primitiveName
, valueAsString
);
743 /** Event method that denotes the instantiation of an object array.
745 * <p>More details about this method can be found in this
746 * class' introduction.</p>
748 * @param arrayClassName The array's class name.
749 * @param objectId An ObjectId instance which can be activated later.
750 * @param lengthAsString The array's length as String.
752 void objectArrayInstantiation(String arrayClassName
, String lengthAsString
,
755 transition(ScannerState
.TRANSITION_OBJECT_ARRAY_INSTANTIATION
);
757 current
.objectArrayInstantiation(arrayClassName
, lengthAsString
, objectId
);
760 /** Event method that denotes the instantiation of a primitive array.
762 * <p>More details about this method can be found in this
763 * class' introduction.</p>
765 * @param arrayClassName The array's class name.
766 * @param objectId An ObjectId instance which can be activated later.
767 * @param lengthAsString The array's length as String.
769 void primitiveArrayInstantiation(String arrayClassName
, String lengthAsString
,
772 transition(ScannerState
.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION
);
774 current
.objectArrayInstantiation(arrayClassName
, lengthAsString
, objectId
);
777 /** Event method that denotes the setting of a value in an array.
779 * <p>More details about this method can be found in this
780 * class' introduction.</p>
782 * @param indexAsString The index to as a String.
784 void arraySet(String indexAsString
)
786 transition(ScannerState
.TRANSITION_ARRAY_SET
);
788 current
.arraySet(indexAsString
);
791 /** Event method that denotes the retrieval of a value in an array.
793 * <p>More details about this method can be found in this
794 * class' introduction.</p>
796 * @param indexAsString The index to as a String.
798 void arrayGet(String indexAsString
)
800 transition(ScannerState
.TRANSITION_ARRAY_GET
);
802 current
.arrayGet(indexAsString
);
805 /** Event method that denotes the setting of a value in a list.
807 * <p>More details about this method can be found in this
808 * class' introduction.</p>
812 transition(ScannerState
.TRANSITION_LIST_SET
);
817 /** Event method that denotes the retrieval of a value in a list.
819 * <p>More details about this method can be found in this
820 * class' introduction.</p>
824 transition(ScannerState
.TRANSITION_LIST_GET
);
829 /** Event method that denotes the null value.
833 transition(ScannerState
.TRANSITION_NULL_OBJECT
);
835 current
.nullObject();
838 /** Event method that denotes a string.
840 * @param string The string that should be written.
842 void stringReference(String string
)
844 transition(ScannerState
.TRANSITION_STRING_REFERENCE
);
846 current
.stringReference(string
);
849 /** Event method that denotes a reference to an existing object.
851 * @param id The ObjectId to be used.
853 void objectReference(ObjectId id
)
855 transition(ScannerState
.TRANSITION_OBJECT_REFERENCE
);
857 current
.objectReference(id
);