4242public final class ServerSerializationStreamWriter extends
4343 AbstractSerializationStreamWriter {
4444
45- /**
46- * Builds a string that evaluates into an array containing the given elements.
47- * This class exists to work around a bug in IE6/7 that limits the size of
48- * array literals.
49- */
50- public static class LengthConstrainedArray {
51- public static final int MAXIMUM_ARRAY_LENGTH = 1 << 15 ;
52- private static final String POSTLUDE = "])" ;
53- private static final String PRELUDE = "].concat([" ;
54-
55- private final StringBuffer buffer ;
56- private int count = 0 ;
57- private boolean needsComma = false ;
58- private int total = 0 ;
59- private boolean javascript = false ;
60-
61- public LengthConstrainedArray () {
62- buffer = new StringBuffer ();
63- }
64-
65- public LengthConstrainedArray (int capacityGuess ) {
66- buffer = new StringBuffer (capacityGuess );
67- }
68-
69- public void addToken (CharSequence token ) {
70- total ++;
71- if (count ++ == MAXIMUM_ARRAY_LENGTH ) {
72- if (total == MAXIMUM_ARRAY_LENGTH + 1 ) {
73- buffer .append (PRELUDE );
74- javascript = true ;
75- } else {
76- buffer .append ("],[" );
77- }
78- count = 0 ;
79- needsComma = false ;
80- }
81-
82- if (needsComma ) {
83- buffer .append ("," );
84- } else {
85- needsComma = true ;
86- }
87-
88- buffer .append (token );
89- }
90-
91- public void addEscapedToken (String token ) {
92- addToken (escapeString (token , true , this ));
93- }
94-
95- public void addToken (int i ) {
96- addToken (String .valueOf (i ));
97- }
98-
99- public boolean isJavaScript () {
100- return javascript ;
101- }
102-
103- public void setJavaScript (boolean javascript ) {
104- this .javascript = javascript ;
105- }
106-
107- @ Override
108- public String toString () {
109- if (total > MAXIMUM_ARRAY_LENGTH ) {
110- return "[" + buffer .toString () + POSTLUDE ;
111- } else {
112- return "[" + buffer .toString () + "]" ;
113- }
114- }
115- }
116-
11745 /**
11846 * Enumeration used to provided typed instance writers.
11947 */
@@ -337,14 +265,6 @@ abstract void write(ServerSerializationStreamWriter stream, Object instance)
337265
338266 private static final char NON_BREAKING_HYPHEN = '\u2011' ;
339267
340- /**
341- * Maximum length of a string node in RPC responses, not including surrounding
342- * quote characters (2 ^ 16 - 1) = 65535.
343- * This exists to work around a Rhino parser bug in the hosted mode client
344- * that limits string node lengths to 64KB.
345- */
346- private static final int MAX_STRING_NODE_LENGTH = 0xFFFF ;
347-
348268 static {
349269 /*
350270 * NOTE: The JS VM in IE6 & IE7 do not interpret \v correctly. They convert
@@ -382,36 +302,15 @@ abstract void write(ServerSerializationStreamWriter stream, Object instance)
382302 CLASS_TO_VALUE_WRITER .put (String .class , ValueWriter .STRING );
383303 }
384304
385- /**
386- * This method takes a string and outputs a JavaScript string literal. The
387- * data is surrounded with quotes, and any contained characters that need to
388- * be escaped are mapped onto their escape sequence.
389- *
390- * Assumptions: We are targeting a version of JavaScript that that is later
391- * than 1.3 that supports unicode strings.
392- */
393- public static String escapeString (String toEscape ) {
394- return escapeString (toEscape , false , null );
395- }
396-
397305 /**
398306 * This method takes a string and outputs a JavaScript string literal. The
399307 * data is surrounded with quotes, and any contained characters that need to
400308 * be escaped are mapped onto their escape sequence.
401309 *
402- * This splits strings into 64KB chunks to workaround an issue with the hosted mode client where
403- * the Rhino parser can't handle string nodes larger than 64KB, e.g. {@code "longstring"} is
404- * converted to {@code "long" + "string"}.
405- *
406310 * Assumptions: We are targeting a version of JavaScript that that is later
407311 * than 1.3 that supports unicode strings.
408312 */
409- public static String escapeStringSplitNodes (String toEscape ) {
410- return escapeString (toEscape , true , null );
411- }
412-
413- private static String escapeString (String toEscape , boolean splitNodes ,
414- LengthConstrainedArray array ) {
313+ public static String escapeString (String toEscape ) {
415314 // Since escaped characters will increase the output size, allocate extra room to start.
416315 int length = toEscape .length ();
417316 int capacityIncrement = Math .max (length , 16 );
@@ -422,30 +321,14 @@ private static String escapeString(String toEscape, boolean splitNodes,
422321 int i = 0 ;
423322 while (i < length ) {
424323
425- // Add one segment at a time, up to maxNodeLength characters. Note this always leave room
426- // for at least 6 characters at the end (maximum unicode escaped character size).
427- int maxSegmentVectorSize = splitNodes
428- ? (charVector .getSize () + MAX_STRING_NODE_LENGTH - 5 )
429- : Integer .MAX_VALUE ;
430-
431- while (i < length && charVector .getSize () < maxSegmentVectorSize ) {
324+ while (i < length ) {
432325 char c = toEscape .charAt (i ++);
433326 if (needsUnicodeEscape (c )) {
434327 unicodeEscape (c , charVector );
435328 } else {
436329 charVector .add (c );
437330 }
438331 }
439-
440- // If there's another segment left, insert a '+' operator.
441- if (splitNodes && i < length ) {
442- charVector .add (JS_QUOTE_CHAR );
443- charVector .add ('+' );
444- charVector .add (JS_QUOTE_CHAR );
445- if (array != null ) {
446- array .setJavaScript (true );
447- }
448- }
449332 }
450333
451334 charVector .add (JS_QUOTE_CHAR );
@@ -502,7 +385,7 @@ private static Class<?> getClassForSerialization(Object instance) {
502385 * <li>Total Characters Escaped: 2082</li></li>
503386 * </ul> </li>
504387 * </ol>
505- *
388+ *
506389 * @param ch character to check
507390 * @return <code>true</code> if the character requires the \\uXXXX unicode
508391 * character escape
@@ -557,7 +440,7 @@ private static boolean needsUnicodeEscape(char ch) {
557440 * Writes a safe escape sequence for a character. Some characters have a short
558441 * form, such as \n for U+000D, while others are represented as \\xNN or
559442 * \\uNNNN.
560- *
443+ *
561444 * @param ch character to unicode escape
562445 * @param charVector char vector to receive the unicode escaped representation
563446 */
@@ -610,7 +493,7 @@ public void serializeValue(Object value, Class<?> type)
610493 /**
611494 * Build an array of JavaScript string literals that can be decoded by the
612495 * client via the eval function.
613- *
496+ *
614497 * NOTE: We build the array in reverse so the client can simply use the pop
615498 * function to remove the next item from the list.
616499 */
@@ -620,14 +503,14 @@ public String toString() {
620503 // We take a guess at how big to make to buffer to avoid numerous resizes.
621504 //
622505 int capacityGuess = 2 * tokenListCharCount + 2 * tokenList .size ();
623- LengthConstrainedArray stream = new LengthConstrainedArray (capacityGuess );
624- writePayload (stream );
625- writeStringTable (stream );
626- writeHeader (stream );
506+ StringBuffer buffer = new StringBuffer (capacityGuess );
507+ writePayload (buffer );
508+ writeStringTable (buffer );
509+ writeHeader (buffer );
627510
628- return stream .toString ();
511+ return "[" + buffer .toString () + "]" ;
629512 }
630-
513+
631514 @ Override
632515 public void writeLong (long value ) {
633516 if (getVersion () == SERIALIZATION_STREAM_MIN_VERSION ) {
@@ -702,7 +585,7 @@ protected void serialize(Object instance, String typeSignature)
702585 * Serialize an instance that is an array. Will default to serializing the
703586 * instance as an Object vector if the instance is not a vector of primitives,
704587 * Strings or Object.
705- *
588+ *
706589 * @param instanceClass
707590 * @param instance
708591 * @throws SerializationException
@@ -735,14 +618,14 @@ private void serializeClass(Object instance, Class<?> instanceClass)
735618 List <Field > serverFields = new ArrayList <Field >();
736619 for (Field declField : serializableFields ) {
737620 assert (declField != null );
738-
621+
739622 // Identify server-only fields
740623 if (!clientFieldNames .contains (declField .getName ())) {
741624 serverFields .add (declField );
742625 continue ;
743626 }
744627 }
745-
628+
746629 // Serialize the server-only fields into a byte array and encode as a String
747630 try {
748631 ByteArrayOutputStream baos = new ByteArrayOutputStream ();
@@ -765,7 +648,7 @@ private void serializeClass(Object instance, Class<?> instanceClass)
765648 throw new SerializationException (e );
766649 }
767650 }
768-
651+
769652 // Write the client-visible field data
770653 for (Field declField : serializableFields ) {
771654 if ((clientFieldNames != null ) && !clientFieldNames .contains (declField .getName ())) {
@@ -861,29 +744,39 @@ private void serializeWithCustomSerializer(Class<?> customSerializer,
861744 * Notice that the field are written in reverse order that the client can just
862745 * pop items out of the stream.
863746 */
864- private void writeHeader (LengthConstrainedArray stream ) {
865- stream .addToken (getFlags ());
866- if (stream .isJavaScript () && getVersion () >= SERIALIZATION_STREAM_JSON_VERSION ) {
867- // Ensure we are not using the JSON supported version if stream is Javascript instead of JSON
868- stream .addToken (SERIALIZATION_STREAM_JSON_VERSION - 1 );
869- } else {
870- stream .addToken (getVersion ());
871- }
747+ private void writeHeader (StringBuffer buffer ) {
748+ addToken (buffer , getFlags ());
749+ addToken (buffer , getVersion ());
872750 }
873751
874- private void writePayload (LengthConstrainedArray stream ) {
752+ private void writePayload (StringBuffer buffer ) {
875753 ListIterator <String > tokenIterator = tokenList .listIterator (tokenList .size ());
876754 while (tokenIterator .hasPrevious ()) {
877- stream . addToken (tokenIterator .previous ());
755+ addToken (buffer , tokenIterator .previous ());
878756 }
879757 }
880758
881- private void writeStringTable (LengthConstrainedArray stream ) {
882- LengthConstrainedArray tableStream = new LengthConstrainedArray ();
759+ private void writeStringTable (StringBuffer buffer ) {
760+ StringBuffer tableBuffer = new StringBuffer ();
883761 for (String s : getStringTable ()) {
884- tableStream . addEscapedToken (s );
762+ addEscapedToken (tableBuffer , s );
885763 }
886- stream .addToken (tableStream .toString ());
887- stream .setJavaScript (stream .isJavaScript () || tableStream .isJavaScript ());
764+ addToken (buffer , "[" + tableBuffer + "]" );
765+ }
766+
767+ public void addToken (StringBuffer buffer , CharSequence token ) {
768+ if (buffer .length () > 0 ) {
769+ buffer .append ("," );
770+ }
771+
772+ buffer .append (token );
773+ }
774+
775+ public void addEscapedToken (StringBuffer buffer , String token ) {
776+ addToken (buffer , escapeString (token ));
777+ }
778+
779+ public void addToken (StringBuffer buffer , int i ) {
780+ addToken (buffer , String .valueOf (i ));
888781 }
889782}
0 commit comments