2424import static org .jsonurl .CharUtil .IS_QUOTE ;
2525import static org .jsonurl .CharUtil .IS_STRUCTCHAR ;
2626import static org .jsonurl .CharUtil .hexDecode ;
27+ import static org .jsonurl .JsonUrlOptions .isCoerceNullToEmptyString ;
28+ import static org .jsonurl .JsonUrlOptions .isEmptyUnquotedKeyAllowed ;
29+ import static org .jsonurl .JsonUrlOptions .isEmptyUnquotedValueAllowed ;
30+ import static org .jsonurl .JsonUrlOptions .isImpliedStringLiterals ;
2731import static org .jsonurl .SyntaxException .Message .MSG_BAD_CHAR ;
2832import static org .jsonurl .SyntaxException .Message .MSG_BAD_PCT_ENC ;
2933import static org .jsonurl .SyntaxException .Message .MSG_BAD_QSTR ;
@@ -95,7 +99,7 @@ private static int percentDecode(
9599
96100 return (ch1 << 4 ) | ch2 ;
97101 }
98-
102+
99103 /**
100104 * parse true, false, and null literals.
101105 *
@@ -309,14 +313,14 @@ static String literalToJavaString(
309313 JsonUrlOptions options ) {
310314
311315 if (stop <= start ) {
312- if (JsonUrlOptions . isEmptyUnquotedKeyAllowed (options )) {
316+ if (isEmptyUnquotedKeyAllowed (options )) {
313317 return EMPTY_STRING ;
314318 }
315319
316320 throw new SyntaxException (MSG_EXPECT_LITERAL , start );
317321 }
318322
319- if (JsonUrlOptions . isImpliedStringLiterals (options )) {
323+ if (isImpliedStringLiterals (options )) {
320324 return string (buf , text , start , stop , false );
321325 }
322326
@@ -347,6 +351,33 @@ static String literalToJavaString(
347351 //
348352 return string (buf , text , start , stop , false );
349353 }
354+
355+ private static <V > V literalEmptyString (
356+ int start ,
357+ ValueFactory <V ,?,?,?,?,?,?,?,?,?> factory ,
358+ JsonUrlOptions options ) {
359+
360+ if (isEmptyUnquotedValueAllowed (options )) {
361+ return factory .getString (EMPTY_STRING );
362+ }
363+
364+ throw new SyntaxException (MSG_EXPECT_LITERAL , start );
365+ }
366+
367+ private static <V > V literalTrueFalseNull (
368+ V value ,
369+ ValueFactory <V ,?,?,?,?,?,?,?,?,?> factory ,
370+ JsonUrlOptions options ) {
371+
372+ boolean coerce = factory .isNull (value )
373+ && isCoerceNullToEmptyString (options );
374+
375+ if (coerce ) {
376+ return factory .getString (EMPTY_STRING );
377+ }
378+
379+ return value ;
380+ }
350381
351382 /**
352383 * parse a literal value
@@ -375,14 +406,10 @@ static <V> V literal(
375406 JsonUrlOptions options ) {
376407
377408 if (stop <= start ) {
378- if (JsonUrlOptions .isEmptyUnquotedValueAllowed (options )) {
379- return factory .getString ("" );
380- }
381-
382- throw new SyntaxException (MSG_EXPECT_LITERAL , start );
409+ return literalEmptyString (start , factory , options );
383410 }
384411
385- if (JsonUrlOptions . isImpliedStringLiterals (options )) {
412+ if (isImpliedStringLiterals (options )) {
386413 return factory .getString (
387414 string (buf , text , start , stop , false ));
388415 }
@@ -397,7 +424,7 @@ static <V> V literal(
397424
398425 V ret = factory .getTrueFalseNull (text , start , stop );
399426 if (ret != null ) {
400- return ret ;
427+ return literalTrueFalseNull ( ret , factory , options ) ;
401428 }
402429
403430 final NumberBuilder num = nbuilder == null
@@ -588,6 +615,32 @@ private static void encode(
588615 }
589616 }
590617 }
618+
619+ private static <T extends Appendable > boolean appendEmptyString (
620+ T dest ,
621+ boolean isKey ,
622+ JsonUrlOptions options ) throws IOException {
623+ //
624+ // empty string
625+ //
626+ boolean emptyOK = isKey
627+ ? isEmptyUnquotedKeyAllowed (options )
628+ : isEmptyUnquotedValueAllowed (options );
629+
630+ if (emptyOK ) {
631+ return false ;
632+ }
633+
634+ if (isImpliedStringLiterals (options )) {
635+ throw new IOException ("implied strings: unexpected empty string" );
636+ }
637+
638+ //
639+ // the empty string must be quoted
640+ //
641+ dest .append ("''" );
642+ return true ;
643+ }
591644 }
592645
593646 private JsonUrl () {
@@ -761,8 +814,9 @@ public static <V> V parseLiteral(
761814 int stop = start + length ;
762815
763816 final SyntaxException .Message errmsg =
764- JsonUrlOptions .isEmptyUnquotedValueAllowed (options )
765- ? null : MSG_EXPECT_LITERAL ;
817+ isEmptyUnquotedValueAllowed (options )
818+ ? null
819+ : MSG_EXPECT_LITERAL ;
766820
767821 parseLiteralLength (text , start , stop , errmsg );
768822
@@ -831,6 +885,7 @@ public static <V> V parseLiteral(
831885 ValueFactory <V ,?,?,?,?,?,?,?,?,?> factory ) {
832886 return parseLiteral (text , 0 , text .length (), factory , null );
833887 }
888+
834889
835890 /**
836891 * Append the given CharSequence as a string literal.
@@ -839,7 +894,35 @@ public static <V> V parseLiteral(
839894 * @param dest destination
840895 * @param text source
841896 * @param start offset in source
842- * @param end length of source
897+ * @param end offset in source
898+ * @return true if dest was modified
899+ */
900+ public static <T extends Appendable > boolean appendLiteral (
901+ T dest ,
902+ CharSequence text ,
903+ int start ,
904+ int end ,
905+ boolean isKey ) throws IOException {
906+
907+ return appendLiteral (
908+ dest ,
909+ text ,
910+ start ,
911+ end ,
912+ isKey ,
913+ JsonUrlOptions .fromObject (dest ));
914+ }
915+
916+
917+ /**
918+ * Append the given CharSequence as a string literal.
919+ *
920+ * @param <T> destination type
921+ * @param dest destination
922+ * @param text source
923+ * @param start offset in source
924+ * @param end offset in source
925+ * @param options a valid JsonUrlOptions or null
843926 * @return true if dest was modified
844927 */
845928 public static <T extends Appendable > boolean appendLiteral (// NOPMD - CyclomaticComplexity
@@ -851,29 +934,10 @@ public static <T extends Appendable> boolean appendLiteral(// NOPMD - Cyclomatic
851934 JsonUrlOptions options ) throws IOException {
852935
853936 if (end <= start ) {
854- //
855- // empty string
856- //
857- boolean emptyOK = isKey
858- ? JsonUrlOptions .isEmptyUnquotedKeyAllowed (options )
859- : JsonUrlOptions .isEmptyUnquotedValueAllowed (options );
860-
861- if (emptyOK ) {
862- return false ;
863- }
864-
865- if (JsonUrlOptions .isImpliedStringLiterals (options )) {
866- throw new IOException ("implied strings: unexpected empty string" );
867- }
868-
869- //
870- // the empty string must be quoted
871- //
872- dest .append ("''" );
873- return true ;
937+ return Encode .appendEmptyString (dest , isKey , options );
874938 }
875939
876- if (JsonUrlOptions . isImpliedStringLiterals (options )) {
940+ if (isImpliedStringLiterals (options )) {
877941 Encode .encode (dest , text , start , end , false , true );
878942 return true ;
879943 }
0 commit comments