18
18
19
19
import java .net .URI ;
20
20
import java .util .ArrayList ;
21
- import java .util .Collection ;
21
+ import java .util .LinkedList ;
22
22
import java .util .List ;
23
23
import java .util .Map ;
24
24
import java .util .regex .Matcher ;
29
29
import org .springframework .util .MultiValueMap ;
30
30
import org .springframework .util .ObjectUtils ;
31
31
import org .springframework .util .StringUtils ;
32
+ import org .springframework .web .util .HierarchicalUriComponents .PathComponent ;
32
33
33
34
/**
34
35
* Builder for {@link UriComponents}.
46
47
*
47
48
* @author Arjen Poutsma
48
49
* @author Rossen Stoyanchev
50
+ * @author Phillip Webb
49
51
* @since 3.1
50
52
* @see #newInstance()
51
53
* @see #fromPath(String)
@@ -91,7 +93,7 @@ public class UriComponentsBuilder {
91
93
92
94
private int port = -1 ;
93
95
94
- private PathComponentBuilder pathBuilder = NULL_PATH_COMPONENT_BUILDER ;
96
+ private CompositePathComponentBuilder pathBuilder = new CompositePathComponentBuilder () ;
95
97
96
98
private final MultiValueMap <String , String > queryParams = new LinkedMultiValueMap <String , String >();
97
99
@@ -334,7 +336,7 @@ public UriComponentsBuilder uri(URI uri) {
334
336
this .port = uri .getPort ();
335
337
}
336
338
if (StringUtils .hasLength (uri .getRawPath ())) {
337
- this .pathBuilder = new FullPathComponentBuilder (uri .getRawPath ());
339
+ this .pathBuilder = new CompositePathComponentBuilder (uri .getRawPath ());
338
340
}
339
341
if (StringUtils .hasLength (uri .getRawQuery ())) {
340
342
this .queryParams .clear ();
@@ -352,7 +354,7 @@ private void resetHierarchicalComponents() {
352
354
this .userInfo = null ;
353
355
this .host = null ;
354
356
this .port = -1 ;
355
- this .pathBuilder = NULL_PATH_COMPONENT_BUILDER ;
357
+ this .pathBuilder = new CompositePathComponentBuilder () ;
356
358
this .queryParams .clear ();
357
359
}
358
360
@@ -436,12 +438,7 @@ public UriComponentsBuilder port(int port) {
436
438
* @return this UriComponentsBuilder
437
439
*/
438
440
public UriComponentsBuilder path (String path ) {
439
- if (path != null ) {
440
- this .pathBuilder = this .pathBuilder .appendPath (path );
441
- }
442
- else {
443
- this .pathBuilder = NULL_PATH_COMPONENT_BUILDER ;
444
- }
441
+ this .pathBuilder .addPath (path );
445
442
resetSchemeSpecificPart ();
446
443
return this ;
447
444
}
@@ -453,22 +450,21 @@ public UriComponentsBuilder path(String path) {
453
450
* @return this UriComponentsBuilder
454
451
*/
455
452
public UriComponentsBuilder replacePath (String path ) {
456
- this .pathBuilder = NULL_PATH_COMPONENT_BUILDER ;
457
- path (path );
453
+ this .pathBuilder = new CompositePathComponentBuilder (path );
458
454
resetSchemeSpecificPart ();
459
455
return this ;
460
456
}
461
457
462
458
/**
463
- * Appends the given path segments to the existing path of this builder. Each given path segments may contain URI
464
- * template variables.
459
+ * Appends the given path segments to the existing path of this builder. Each given
460
+ * path segments may contain URI template variables.
465
461
*
466
462
* @param pathSegments the URI path segments
467
463
* @return this UriComponentsBuilder
468
464
*/
469
465
public UriComponentsBuilder pathSegment (String ... pathSegments ) throws IllegalArgumentException {
470
466
Assert .notNull (pathSegments , "'segments' must not be null" );
471
- this .pathBuilder = this . pathBuilder . appendPathSegments (pathSegments );
467
+ this .pathBuilder . addPathSegments (pathSegments );
472
468
resetSchemeSpecificPart ();
473
469
return this ;
474
470
}
@@ -590,131 +586,122 @@ public UriComponentsBuilder fragment(String fragment) {
590
586
return this ;
591
587
}
592
588
593
- /**
594
- * Represents a builder for {@link HierarchicalUriComponents.PathComponent}
595
- */
596
- private interface PathComponentBuilder {
597
-
598
- HierarchicalUriComponents .PathComponent build ();
599
589
600
- PathComponentBuilder appendPath (String path );
601
-
602
- PathComponentBuilder appendPathSegments (String ... pathSegments );
590
+ private interface PathComponentBuilder {
591
+ PathComponent build ();
603
592
}
604
593
605
- /**
606
- * Represents a builder for full string paths.
607
- */
608
- private static class FullPathComponentBuilder implements PathComponentBuilder {
609
-
610
- private final StringBuilder path ;
594
+ private static class CompositePathComponentBuilder implements PathComponentBuilder {
611
595
612
- private FullPathComponentBuilder (String path ) {
613
- this .path = new StringBuilder (path );
614
- }
615
-
616
- public HierarchicalUriComponents .PathComponent build () {
617
- return new HierarchicalUriComponents .FullPathComponent (path .toString ());
618
- }
596
+ private LinkedList <PathComponentBuilder > componentBuilders = new LinkedList <PathComponentBuilder >();
619
597
620
- public PathComponentBuilder appendPath (String path ) {
621
- this .path .append (path );
622
- return this ;
623
- }
624
-
625
- public PathComponentBuilder appendPathSegments (String ... pathSegments ) {
626
- PathComponentCompositeBuilder builder = new PathComponentCompositeBuilder (this );
627
- builder .appendPathSegments (pathSegments );
628
- return builder ;
598
+ public CompositePathComponentBuilder () {
629
599
}
630
- }
631
-
632
- /**
633
- * Represents a builder for paths segment paths.
634
- */
635
- private static class PathSegmentComponentBuilder implements PathComponentBuilder {
636
-
637
- private final List <String > pathSegments = new ArrayList <String >();
638
600
639
- private PathSegmentComponentBuilder (String ... pathSegments ) {
640
- this . pathSegments . addAll ( removeEmptyPathSegments ( pathSegments ) );
601
+ public CompositePathComponentBuilder (String path ) {
602
+ addPath ( path );
641
603
}
642
604
643
- private Collection <String > removeEmptyPathSegments (String ... pathSegments ) {
644
- List <String > result = new ArrayList <String >();
645
- for (String segment : pathSegments ) {
646
- if (StringUtils .hasText (segment )) {
647
- result .add (segment );
605
+ public void addPathSegments (String ... pathSegments ) {
606
+ if (!ObjectUtils .isEmpty (pathSegments )) {
607
+ PathSegmentComponentBuilder psBuilder = getLastBuilder (PathSegmentComponentBuilder .class );
608
+ FullPathComponentBuilder fpBuilder = getLastBuilder (FullPathComponentBuilder .class );
609
+ if (psBuilder == null ) {
610
+ psBuilder = new PathSegmentComponentBuilder ();
611
+ this .componentBuilders .add (psBuilder );
612
+ if (fpBuilder != null ) {
613
+ fpBuilder .removeTrailingSlash ();
614
+ }
648
615
}
616
+ psBuilder .append (pathSegments );
649
617
}
650
- return result ;
651
618
}
652
619
653
- public HierarchicalUriComponents .PathComponent build () {
654
- return new HierarchicalUriComponents .PathSegmentComponent (pathSegments );
620
+ public void addPath (String path ) {
621
+ if (StringUtils .hasText (path )) {
622
+ PathSegmentComponentBuilder psBuilder = getLastBuilder (PathSegmentComponentBuilder .class );
623
+ FullPathComponentBuilder fpBuilder = getLastBuilder (FullPathComponentBuilder .class );
624
+ if (psBuilder != null ) {
625
+ path = path .startsWith ("/" ) ? path : "/" + path ;
626
+ }
627
+ if (fpBuilder == null ) {
628
+ fpBuilder = new FullPathComponentBuilder ();
629
+ this .componentBuilders .add (fpBuilder );
630
+ }
631
+ fpBuilder .append (path );
632
+ }
655
633
}
656
634
657
- public PathComponentBuilder appendPath (String path ) {
658
- PathComponentCompositeBuilder builder = new PathComponentCompositeBuilder (this );
659
- builder .appendPath (path );
660
- return builder ;
635
+ @ SuppressWarnings ("unchecked" )
636
+ private <T > T getLastBuilder (Class <T > builderClass ) {
637
+ if (!this .componentBuilders .isEmpty ()) {
638
+ PathComponentBuilder last = this .componentBuilders .getLast ();
639
+ if (builderClass .isInstance (last )) {
640
+ return (T ) last ;
641
+ }
642
+ }
643
+ return null ;
661
644
}
662
645
663
- public PathComponentBuilder appendPathSegments (String ... pathSegments ) {
664
- this .pathSegments .addAll (removeEmptyPathSegments (pathSegments ));
665
- return this ;
646
+ public PathComponent build () {
647
+ int size = this .componentBuilders .size ();
648
+ List <PathComponent > components = new ArrayList <PathComponent >(size );
649
+ for (int i = 0 ; i < size ; i ++) {
650
+ PathComponent pathComponent = this .componentBuilders .get (i ).build ();
651
+ if (pathComponent != null ) {
652
+ components .add (pathComponent );
653
+ }
654
+ }
655
+ if (components .isEmpty ()) {
656
+ return HierarchicalUriComponents .NULL_PATH_COMPONENT ;
657
+ }
658
+ if (components .size () == 1 ) {
659
+ return components .get (0 );
660
+ }
661
+ return new HierarchicalUriComponents .PathComponentComposite (components );
666
662
}
667
663
}
668
664
669
- /**
670
- * Represents a builder for a collection of PathComponents.
671
- */
672
- private static class PathComponentCompositeBuilder implements PathComponentBuilder {
665
+ private static class FullPathComponentBuilder implements PathComponentBuilder {
673
666
674
- private final List < PathComponentBuilder > pathComponentBuilders = new ArrayList < PathComponentBuilder > ();
667
+ private StringBuilder path = new StringBuilder ();
675
668
676
- private PathComponentCompositeBuilder ( PathComponentBuilder builder ) {
677
- pathComponentBuilders . add ( builder );
669
+ public void append ( String path ) {
670
+ this . path . append ( path );
678
671
}
679
672
680
- public HierarchicalUriComponents .PathComponent build () {
681
- List <HierarchicalUriComponents .PathComponent > pathComponents =
682
- new ArrayList <HierarchicalUriComponents .PathComponent >(pathComponentBuilders .size ());
683
-
684
- for (PathComponentBuilder pathComponentBuilder : pathComponentBuilders ) {
685
- pathComponents .add (pathComponentBuilder .build ());
673
+ public PathComponent build () {
674
+ if (this .path .length () == 0 ) {
675
+ return null ;
686
676
}
687
- return new HierarchicalUriComponents .PathComponentComposite (pathComponents );
688
- }
689
-
690
- public PathComponentBuilder appendPath (String path ) {
691
- this .pathComponentBuilders .add (new FullPathComponentBuilder (path ));
692
- return this ;
677
+ String path = this .path .toString ().replace ("//" , "/" );
678
+ return new HierarchicalUriComponents .FullPathComponent (path );
693
679
}
694
680
695
- public PathComponentBuilder appendPathSegments (String ... pathSegments ) {
696
- this .pathComponentBuilders .add (new PathSegmentComponentBuilder (pathSegments ));
697
- return this ;
681
+ public void removeTrailingSlash () {
682
+ int index = this .path .length () - 1 ;
683
+ if (this .path .charAt (index ) == '/' ) {
684
+ this .path .deleteCharAt (index );
685
+ }
698
686
}
699
687
}
700
688
689
+ private static class PathSegmentComponentBuilder implements PathComponentBuilder {
701
690
702
- /**
703
- * Represents a builder for an empty path.
704
- */
705
- private static PathComponentBuilder NULL_PATH_COMPONENT_BUILDER = new PathComponentBuilder () {
706
-
707
- public HierarchicalUriComponents .PathComponent build () {
708
- return HierarchicalUriComponents .NULL_PATH_COMPONENT ;
709
- }
691
+ private List <String > pathSegments = new LinkedList <String >();
710
692
711
- public PathComponentBuilder appendPath (String path ) {
712
- return new FullPathComponentBuilder (path );
693
+ public void append (String ... pathSegments ) {
694
+ for (String pathSegment : pathSegments ) {
695
+ if (StringUtils .hasText (pathSegment )) {
696
+ this .pathSegments .add (pathSegment );
697
+ }
698
+ }
713
699
}
714
700
715
- public PathComponentBuilder appendPathSegments (String ... pathSegments ) {
716
- return new PathSegmentComponentBuilder (pathSegments );
701
+ public PathComponent build () {
702
+ return this .pathSegments .isEmpty () ?
703
+ null : new HierarchicalUriComponents .PathSegmentComponent (this .pathSegments );
717
704
}
718
- };
705
+ }
719
706
720
707
}
0 commit comments