11/*
2- * Copyright (c) 2019-2023 , Inversoft Inc., All Rights Reserved
2+ * Copyright (c) 2019-2024 , Inversoft Inc., All Rights Reserved
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -49,51 +49,54 @@ public static QueryStringBuilder builder(String uri) {
4949 }
5050
5151 public QueryStringBuilder beginFragment () {
52- sb .append ("#" );
53- addSeparator = false ;
52+ // If query string contains no terms, remove the question mark
53+ if (sb .toString ().endsWith ("?" )) {
54+ sb .setLength (sb .length () - 1 );
55+ }
56+
57+ if (sb .indexOf ("#" ) == -1 ) {
58+ sb .append ("#" );
59+ addSeparator = false ;
60+ } else {
61+ char lastChar = sb .charAt (sb .length () - 1 );
62+ addSeparator = lastChar != '#' && lastChar != '&' ;
63+ }
5464 return this ;
5565 }
5666
5767 public QueryStringBuilder beginQuery () {
58- sb .append ("?" );
59- addSeparator = false ;
68+ if (sb .indexOf ("#" ) != -1 ) {
69+ throw new IllegalStateException ("You cannot add a query after a fragment" );
70+ }
71+
72+ if (sb .indexOf ("?" ) == -1 ) {
73+ sb .append ("?" );
74+ addSeparator = false ;
75+ } else {
76+ char lastChar = sb .charAt (sb .length () - 1 );
77+ addSeparator = lastChar != '?' && lastChar != '&' ;
78+ }
6079 return this ;
6180 }
6281
6382 public String build () {
64- if (uri .length () == 0 ) {
83+ if (uri .isEmpty () ) {
6584 return sb .toString ();
6685 }
6786
68- // URL provided contains a ?, perhaps other parameters as well
69- if (uri .indexOf ("?" ) != -1 ) {
70- if (sb .indexOf ("?" ) == 0 ) {
71- return uri + sb .substring (1 );
72- }
73- return uri .append (sb ).toString ();
74- } else {
75- if (segments .size () > 0 ) {
76- if (uri .lastIndexOf ("/" ) != uri .length () - 1 ) {
77- uri .append ("/" );
78- }
79-
80- uri .append (String .join ("/" , segments ));
87+ if (segments .size () > 0 ) {
88+ if (uri .lastIndexOf ("/" ) != uri .length () - 1 ) {
89+ uri .append ("/" );
8190 }
82- }
8391
84- if (sb .indexOf ("?" ) == 0 ) {
85- return uri .append (sb ).toString ();
92+ uri .append (String .join ("/" , segments ));
8693 }
8794
88- if (sb .indexOf ("#" ) == 0 ) {
95+ if (( sb .indexOf ("?" ) == 0 || sb . indexOf ( " #" ) == 0 ) && sb . length () > 1 ) {
8996 return uri .append (sb ).toString ();
9097 }
9198
92- if (uri .indexOf ("#" ) != -1 && sb .length () > 0 ) {
93- return uri .append ("&" ).append (sb ).toString ();
94- }
95-
96- if (sb .length () == 0 ) {
99+ if (sb .isEmpty () || sb .toString ().equals ("?" ) || sb .toString ().equals ("#" )) {
97100 return uri .toString ();
98101 }
99102
@@ -134,13 +137,26 @@ public QueryStringBuilder ifTrue(boolean test, Consumer<QueryStringBuilder> cons
134137 }
135138
136139 public QueryStringBuilder uri (String uri ) {
137- if (this .uri .length () > 0 ) {
140+ if (! this .uri .isEmpty () ) {
138141 throw new IllegalStateException ("Object has already been initialized with a URL" );
139142 }
140143
141144 if (uri != null ) {
142- this .uri .append (uri );
143- if (uri .contains ("?" ) && !uri .endsWith ("&" )) {
145+ String del = null ;
146+ if (uri .contains ("?" )) {
147+ del = "?" ;
148+ } else if (uri .contains ("#" )) {
149+ del = "#" ;
150+ }
151+
152+ if (del != null ) {
153+ this .uri .append (uri , 0 , uri .indexOf (del ));
154+ this .sb .append (uri , uri .indexOf (del ), uri .length ());
155+ } else {
156+ this .uri .append (uri );
157+ }
158+
159+ if ((uri .contains ("?" ) || uri .contains ("#" )) && !List .of ('#' , '?' , '&' ).contains (uri .charAt (uri .length () - 1 ))) {
144160 addSeparator = true ;
145161 }
146162 }
@@ -162,9 +178,7 @@ public QueryStringBuilder with(String name, Object value) {
162178 sb .append ("&" );
163179 }
164180
165- sb .append (URLEncoder .encode (name , StandardCharsets .UTF_8 ))
166- .append ("=" )
167- .append (URLEncoder .encode (value .toString (), StandardCharsets .UTF_8 ));
181+ sb .append (URLEncoder .encode (name , StandardCharsets .UTF_8 )).append ("=" ).append (URLEncoder .encode (value .toString (), StandardCharsets .UTF_8 ));
168182
169183 addSeparator = true ;
170184 return this ;
@@ -175,8 +189,13 @@ public QueryStringBuilder withActual(String name) {
175189 }
176190
177191 public QueryStringBuilder withSegment (Object segment ) {
178- if (uri .length () > 0 && (uri .indexOf ("?" ) == uri .length () - 1 )) {
179- throw new IllegalStateException ("You cannot add a URL segment after you have appended a ? to the end of the URL" );
192+ String message = "You cannot add a URL segment after you have appended a %s to the end of the URL" ;
193+
194+ if (!sb .isEmpty () && (sb .indexOf ("?" ) != -1 )) {
195+ throw new IllegalStateException (String .format (message , "?" ));
196+ }
197+ if (!sb .isEmpty () && (sb .indexOf ("#" ) != -1 )) {
198+ throw new IllegalStateException (String .format (message , "#" ));
180199 }
181200
182201 if (segment != null ) {
0 commit comments