001 /*
002 * Java GPX Library (jpx-3.1.0).
003 * Copyright (c) 2016-2023 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020 package io.jenetics.jpx;
021
022 import static java.lang.String.format;
023 import static java.util.Objects.hash;
024 import static java.util.Objects.requireNonNull;
025 import static io.jenetics.jpx.Format.toIntString;
026 import static io.jenetics.jpx.Lists.copyOf;
027 import static io.jenetics.jpx.Lists.copyTo;
028
029 import java.io.DataInput;
030 import java.io.DataOutput;
031 import java.io.IOException;
032 import java.io.InvalidObjectException;
033 import java.io.ObjectInputStream;
034 import java.io.Serial;
035 import java.io.Serializable;
036 import java.net.URI;
037 import java.util.ArrayList;
038 import java.util.Iterator;
039 import java.util.List;
040 import java.util.Objects;
041 import java.util.Optional;
042 import java.util.function.Consumer;
043 import java.util.function.Function;
044 import java.util.function.Predicate;
045 import java.util.stream.Stream;
046
047 import org.w3c.dom.Document;
048
049 import io.jenetics.jpx.GPX.Version;
050
051 /**
052 * Represents a route - an ordered list of way-points representing a series of
053 * turn points leading to a destination.
054 * <p>
055 * Create a new route via the builder:
056 * <pre>{@code
057 * final Route route = Route.builder()
058 * .name("Route 1")
059 * .description("Fancy mountain-bike tour.")
060 * .addPoint(p -> p.lat(48.2081743).lon(16.3738189).ele(160))
061 * .addPoint(p -> p.lat(48.2081743).lon(16.3738189).ele(161))
062 * .addPoint(p -> p.lat(48.2081743).lon(16.3738189).ele(162))))
063 * .build();
064 * }</pre>
065 *
066 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
067 * @version 1.5
068 * @since 1.0
069 */
070 public final class Route implements Iterable<WayPoint>, Serializable {
071
072 @Serial
073 private static final long serialVersionUID = 2L;
074
075 private final String _name;
076 private final String _comment;
077 private final String _description;
078 private final String _source;
079 private final List<Link> _links;
080 private final UInt _number;
081 private final String _type;
082 private final Document _extensions;
083 private final List<WayPoint> _points;
084
085 /**
086 * Create a new {@code Route} with the given parameters and way-points.
087 *
088 * @param name the GPS name of the route
089 * @param comment the GPS comment of the route
090 * @param description the Text description of route for user. Not sent to GPS.
091 * @param source the source of data. Included to give user some idea of
092 * reliability and accuracy of data.
093 * @param links the links to external information about the route
094 * @param number the GPS route number
095 * @param type the type (classification) of the route
096 * @param extensions the extensions document
097 * @param points the sequence of route points
098 */
099 private Route(
100 final String name,
101 final String comment,
102 final String description,
103 final String source,
104 final List<Link> links,
105 final UInt number,
106 final String type,
107 final Document extensions,
108 final List<WayPoint> points
109 ) {
110 _name = name;
111 _comment = comment;
112 _description = description;
113 _source = source;
114 _links = copyOf(links);
115 _number = number;
116 _type = type;
117 _extensions = extensions;
118 _points = copyOf(points);
119 }
120
121 /**
122 * Return the route name.
123 *
124 * @return the route name
125 */
126 public Optional<String> getName() {
127 return Optional.ofNullable(_name);
128 }
129
130 /**
131 * Return the GPS comment of the route.
132 *
133 * @return the GPS comment of the route
134 */
135 public Optional<String> getComment() {
136 return Optional.ofNullable(_comment);
137 }
138
139 /**
140 * Return the Text description of route for user. Not sent to GPS.
141 *
142 * @return the Text description of route for user. Not sent to GPS
143 */
144 public Optional<String> getDescription() {
145 return Optional.ofNullable(_description);
146 }
147
148 /**
149 * Return the source of data. Included to give user some idea of reliability
150 * and accuracy of data.
151 *
152 * @return the source of data
153 */
154 public Optional<String> getSource() {
155 return Optional.ofNullable(_source);
156 }
157
158 /**
159 * Return the links to external information about the route.
160 *
161 * @return the links to external information about the route
162 */
163 public List<Link> getLinks() {
164 return _links;
165 }
166
167 /**
168 * Return the GPS route number.
169 *
170 * @return the GPS route number
171 */
172 public Optional<UInt> getNumber() {
173 return Optional.ofNullable(_number);
174 }
175
176 /**
177 * Return the type (classification) of the route.
178 *
179 * @return the type (classification) of the route
180 */
181 public Optional<String> getType() {
182 return Optional.ofNullable(_type);
183 }
184
185 /**
186 * Return the sequence of route points.
187 *
188 * @return the sequence of route points
189 */
190 public List<WayPoint> getPoints() {
191 return _points;
192 }
193
194 /**
195 * Return a stream of {@link WayPoint} objects this route contains.
196 *
197 * @return a stream of {@link WayPoint} objects this route contains
198 */
199 public Stream<WayPoint> points() {
200 return _points.stream();
201 }
202
203 /**
204 * Return the (cloned) extensions document. The root element of the returned
205 * document has the name {@code extensions}.
206 * <pre>{@code
207 * <extensions>
208 * ...
209 * </extensions>
210 * }</pre>
211 *
212 * @since 1.5
213 *
214 * @return the extensions document
215 * @throws org.w3c.dom.DOMException if the document could not be cloned,
216 * because of an erroneous XML configuration
217 */
218 public Optional<Document> getExtensions() {
219 return Optional.ofNullable(_extensions).map(XML::clone);
220 }
221
222 @Override
223 public Iterator<WayPoint> iterator() {
224 return _points.iterator();
225 }
226
227 /**
228 * Convert the <em>immutable</em> route object into a <em>mutable</em>
229 * builder initialized with the current route values.
230 *
231 * @since 1.1
232 *
233 * @return a new route builder initialized with the values of {@code this}
234 * route
235 */
236 public Builder toBuilder() {
237 return builder()
238 .name(_name)
239 .cmt(_comment)
240 .desc(_description)
241 .src(_source)
242 .links(_links)
243 .number(_number)
244 .extensions(_extensions)
245 .points(_points);
246 }
247
248 /**
249 * Return {@code true} if all route properties are {@code null} or empty.
250 *
251 * @return {@code true} if all route properties are {@code null} or empty
252 */
253 public boolean isEmpty() {
254 return _name == null &&
255 _comment == null &&
256 _description == null &&
257 _source == null &&
258 _links.isEmpty() &&
259 _number == null &&
260 _extensions == null &&
261 _points.isEmpty();
262 }
263
264 /**
265 * Return {@code true} if not all route properties are {@code null} or empty.
266 *
267 * @since 1.1
268 *
269 * @return {@code true} if not all route properties are {@code null} or empty
270 */
271 public boolean nonEmpty() {
272 return !isEmpty();
273 }
274
275 @Override
276 public int hashCode() {
277 return hash(
278 _name,
279 _comment,
280 _description,
281 _source,
282 _type,
283 Lists.hashCode(_links),
284 _number,
285 _points
286 );
287 }
288
289 @Override
290 public boolean equals(final Object obj) {
291 return obj == this ||
292 obj instanceof Route route &&
293 Objects.equals(route._name, _name) &&
294 Objects.equals(route._comment, _comment) &&
295 Objects.equals(route._description, _description) &&
296 Objects.equals(route._source, _source) &&
297 Objects.equals(route._type, _type) &&
298 Lists.equals(route._links, _links) &&
299 Objects.equals(route._number, _number) &&
300 Objects.equals(route._points, _points);
301 }
302
303 @Override
304 public String toString() {
305 return format("Route[name=%s, points=%s]", _name, _points.size());
306 }
307
308 /* *************************************************************************
309 * Static object creation methods
310 * ************************************************************************/
311
312 /**
313 * Return a new {@code Route} builder object.
314 *
315 * @return a new {@code Route} builder object
316 */
317 public static Builder builder() {
318 return new Builder();
319 }
320
321 /**
322 * Builder class for building {@code Route} objects.
323 * <pre>{@code
324 * final Route route = Route.builder()
325 * .name("Route 1")
326 * .description("Fancy mountain-bike tour.")
327 * .addPoint(p -> p.lat(48.2081743).lon(16.3738189).ele(160))
328 * .addPoint(p -> p.lat(48.2081743).lon(16.3738189).ele(161))
329 * .addPoint(p -> p.lat(48.2081743).lon(16.3738189).ele(162))))
330 * .build();
331 * }</pre>
332 */
333 public static final class Builder implements Filter<WayPoint, Route> {
334
335 private String _name;
336 private String _comment;
337 private String _description;
338 private String _source;
339 private final List<Link> _links = new ArrayList<>();
340 private UInt _number;
341 private String _type;
342 private Document _extensions;
343 private final List<WayPoint> _points = new ArrayList<>();
344
345 private Builder() {
346 }
347
348 /**
349 * Set the route name.
350 *
351 * @param name the route name.
352 * @return {@code this} {@code Builder} for method chaining
353 */
354 public Builder name(final String name) {
355 _name = name;
356 return this;
357 }
358
359 /**
360 * Return the current name value.
361 *
362 * @since 1.1
363 *
364 * @return the current name value
365 */
366 public Optional<String> name() {
367 return Optional.ofNullable(_name);
368 }
369
370 /**
371 * Set the route comment.
372 *
373 * @param comment the route comment
374 * @return {@code this} {@code Builder} for method chaining
375 */
376 public Builder cmt(final String comment) {
377 _comment = comment;
378 return this;
379 }
380
381 /**
382 * Return the current comment value.
383 *
384 * @since 1.1
385 *
386 * @return the current comment value
387 */
388 public Optional<String> cmt() {
389 return Optional.ofNullable(_comment);
390 }
391
392 /**
393 * Set the route description.
394 *
395 * @param description the route description
396 * @return {@code this} {@code Builder} for method chaining
397 */
398 public Builder desc(final String description) {
399 _description = description;
400 return this;
401 }
402
403 /**
404 * Return the current description value.
405 *
406 * @since 1.1
407 *
408 * @return the current description value
409 */
410 public Optional<String> desc() {
411 return Optional.ofNullable(_description);
412 }
413
414 /**
415 * Set the source of the data. Included to give user some idea of
416 * reliability and accuracy of data.
417 *
418 * @param source the source of the data
419 * @return {@code this} {@code Builder} for method chaining
420 */
421 public Builder src(final String source) {
422 _source = source;
423 return this;
424 }
425
426 /**
427 * Return the current source value.
428 *
429 * @since 1.1
430 *
431 * @return the current source value
432 */
433 public Optional<String> src() {
434 return Optional.ofNullable(_source);
435 }
436
437 /**
438 * Set the links to additional information about the route. The link
439 * list may be {@code null}.
440 *
441 * @param links the links to additional information about the route
442 * @return {@code this} {@code Builder} for method chaining
443 * @throws NullPointerException if one of the links in the list is
444 * {@code null}
445 */
446 public Builder links(final List<Link> links) {
447 copyTo(links, _links);
448 return this;
449 }
450
451 /**
452 * Set the links to external information about the route.
453 *
454 * @param link the links to external information about the route.
455 * @return {@code this} {@code Builder} for method chaining
456 * @throws NullPointerException if the given {@code link} is {@code null}
457 */
458 public Builder addLink(final Link link) {
459 _links.add(requireNonNull(link));
460 return this;
461 }
462
463 /**
464 * Set the links to external information about the route.
465 *
466 * @param href the links to external information about the route.
467 * @return {@code this} {@code Builder} for method chaining
468 * @throws NullPointerException if the given {@code href} is
469 * {@code null}
470 * @throws IllegalArgumentException if the given {@code href} is not a
471 * valid URL
472 */
473 public Builder addLink(final String href) {
474 _links.add(Link.of(href));
475 return this;
476 }
477
478 /**
479 * Return the current links. The returned link list is mutable.
480 *
481 * @since 1.1
482 *
483 * @return the current links
484 */
485 public List<Link> links() {
486 return new NonNullList<>(_links);
487 }
488
489 /**
490 * Set the GPS route number.
491 *
492 * @param number the GPS route number
493 * @return {@code this} {@code Builder} for method chaining
494 */
495 public Builder number(final UInt number) {
496 _number = number;
497 return this;
498 }
499
500 /**
501 * Set the GPS route number.
502 *
503 * @param number the GPS route number
504 * @return {@code this} {@code Builder} for method chaining
505 */
506 public Builder number(final int number) {
507 _number = UInt.of(number);
508 return this;
509 }
510
511 /**
512 * Return the current number value.
513 *
514 * @since 1.1
515 *
516 * @return the current number value
517 */
518 public Optional<UInt> number() {
519 return Optional.ofNullable(_number);
520 }
521
522 /**
523 * Set the type (classification) of the route.
524 *
525 * @param type the type (classification) of the route.
526 * @return {@code this} {@code Builder} for method chaining
527 */
528 public Builder type(final String type) {
529 _type = type;
530 return this;
531 }
532
533 /**
534 * Return the current type value.
535 *
536 * @since 1.1
537 *
538 * @return the current type value
539 */
540 public Optional<String> type() {
541 return Optional.ofNullable(_type);
542 }
543
544 /**
545 * Sets the extensions object, which may be {@code null}. The root
546 * element of the extensions document must be {@code extensions}.
547 * <pre>{@code
548 * <extensions>
549 * ...
550 * </extensions>
551 * }</pre>
552 *
553 * @since 1.5
554 *
555 * @param extensions the document
556 * @return {@code this} {@code Builder} for method chaining
557 * @throws IllegalArgumentException if the root element is not the
558 * an {@code extensions} node
559 */
560 public Builder extensions(final Document extensions) {
561 _extensions = XML.checkExtensions(extensions);
562 return this;
563 }
564
565 /**
566 * Return the current extensions
567 *
568 * @since 1.5
569 *
570 * @return the extensions document
571 */
572 public Optional<Document> extensions() {
573 return Optional.ofNullable(_extensions);
574 }
575
576 /**
577 * Sets the way-points of the route. The way-point list may be
578 * {@code null}.
579 *
580 * @param points the way-points
581 * @return {@code this} {@code Builder} for method chaining
582 * @throws NullPointerException if one of the way-points is {@code null}
583 */
584 public Builder points(final List<WayPoint> points) {
585 copyTo(points, _points);
586 return this;
587 }
588
589 /**
590 * Adds a way-point to the route.
591 *
592 * @param point the way-point which is added to the route
593 * @return {@code this} {@code Builder} for method chaining
594 * @throws NullPointerException if the {@code point} is {@code null}
595 */
596 public Builder addPoint(final WayPoint point) {
597 _points.add(requireNonNull(point));
598 return this;
599 }
600
601 /**
602 * Add a new way-point via the given {@code WayPoint.Builder} class.
603 *
604 * @param point the way-point builder
605 * @return {@code this} {@code Builder} for method chaining
606 */
607 public Builder addPoint(final Consumer<? super WayPoint.Builder> point) {
608 final WayPoint.Builder builder = WayPoint.builder();
609 point.accept(builder);
610 return addPoint(builder.build());
611 }
612
613 /**
614 * Return the current way-points. The returned list is mutable.
615 *
616 * @since 1.1
617 *
618 * @return the current, mutable way-point list
619 */
620 public List<WayPoint> points() {
621 return new NonNullList<>(_points);
622 }
623
624 @Override
625 public Builder filter(final Predicate<? super WayPoint> predicate) {
626 points(_points.stream().filter(predicate).toList());
627 return this;
628 }
629
630 @Override
631 public Builder map(
632 final Function<? super WayPoint, ? extends WayPoint> mapper
633 ) {
634 points(
635 _points.stream()
636 .map(mapper)
637 .map(WayPoint.class::cast)
638 .toList()
639 );
640 return this;
641 }
642
643 @Override
644 public Builder flatMap(
645 final Function<
646 ? super WayPoint,
647 ? extends List<WayPoint>> mapper
648 ) {
649 points(
650 _points.stream()
651 .flatMap(wp -> mapper.apply(wp).stream())
652 .toList()
653 );
654 return this;
655 }
656
657 @Override
658 public Builder listMap(
659 final Function<
660 ? super List<WayPoint>,
661 ? extends List<WayPoint>> mapper
662 ) {
663 points(mapper.apply(_points));
664 return this;
665 }
666
667 /**
668 * Create a new {@code Route} object with the set values.
669 *
670 * @return a new {@code Route} object with the set values
671 */
672 @Override
673 public Route build() {
674 return of(
675 _name,
676 _comment,
677 _description,
678 _source,
679 _links,
680 _number,
681 _type,
682 _extensions,
683 _points
684 );
685 }
686
687 }
688
689 /* *************************************************************************
690 * Static object creation methods
691 * ************************************************************************/
692
693 /**
694 * Create a new {@code Route} with the given parameters and way-points.
695 *
696 * @since 1.5
697 *
698 * @param name the GPS name of the route
699 * @param comment the GPS comment of the route
700 * @param description the Text description of route for user. Not sent to GPS.
701 * @param source the source of data. Included to give user some idea of
702 * reliability and accuracy of data.
703 * @param links the links to external information about the route
704 * @param number the GPS route number
705 * @param type the type (classification) of the route
706 * @param extensions the extensions document
707 * @param points the sequence of route points
708 * @return a new route object with the given parameters
709 */
710 public static Route of(
711 final String name,
712 final String comment,
713 final String description,
714 final String source,
715 final List<Link> links,
716 final UInt number,
717 final String type,
718 final Document extensions,
719 final List<WayPoint> points
720 ) {
721 return new Route(
722 name,
723 comment,
724 description,
725 source,
726 links,
727 number,
728 type,
729 XML.extensions(XML.clone(extensions)),
730 points
731 );
732 }
733
734 /**
735 * Create a new {@code Route} with the given parameters and way-points.
736 *
737 * @param name the GPS name of the route
738 * @param comment the GPS comment of the route
739 * @param description the Text description of route for user. Not sent to GPS.
740 * @param source the source of data. Included to give user some idea of
741 * reliability and accuracy of data.
742 * @param links the links to external information about the route
743 * @param number the GPS route number
744 * @param type the type (classification) of the route
745 * @param points the sequence of route points
746 * @return a new route object with the given parameters
747 */
748 public static Route of(
749 final String name,
750 final String comment,
751 final String description,
752 final String source,
753 final List<Link> links,
754 final UInt number,
755 final String type,
756 final List<WayPoint> points
757 ) {
758 return of(
759 name,
760 comment,
761 description,
762 source,
763 links,
764 number,
765 type,
766 null,
767 points
768 );
769 }
770
771 /**
772 * Create a new {@code Route} with the given parameters and way-points.
773 *
774 * @param name the GPS name of the route
775 * @param points the sequence of route points
776 * @return a new route object with the given parameters
777 */
778 public static Route of(
779 final String name,
780 final List<WayPoint> points
781 ) {
782 return of(
783 name,
784 null,
785 null,
786 null,
787 null,
788 null,
789 null,
790 null,
791 points
792 );
793 }
794
795 /**
796 * Create a new {@code Route} with the given parameters and way-points.
797 *
798 * @param points the sequence of route points
799 * @return a new route object with the given parameters
800 */
801 public static Route of(final List<WayPoint> points) {
802 return of(
803 null,
804 null,
805 null,
806 null,
807 null,
808 null,
809 null,
810 null,
811 points
812 );
813 }
814
815
816 /* *************************************************************************
817 * Java object serialization
818 * ************************************************************************/
819
820 @Serial
821 private Object writeReplace() {
822 return new SerialProxy(SerialProxy.ROUTE, this);
823 }
824
825 @Serial
826 private void readObject(final ObjectInputStream stream)
827 throws InvalidObjectException
828 {
829 throw new InvalidObjectException("Serialization proxy required.");
830 }
831
832 void write(final DataOutput out) throws IOException {
833 IO.writeNullableString(_name, out);
834 IO.writeNullableString(_comment, out);
835 IO.writeNullableString(_description, out);
836 IO.writeNullableString(_source, out);
837 IO.writes(_links, Link::write, out);
838 IO.writeNullable(_number, UInt::write, out);
839 IO.writeNullableString(_type, out);
840 IO.writeNullable(_extensions, IO::write, out);
841 IO.writes(_points, WayPoint::write, out);
842 }
843
844 static Route read(final DataInput in) throws IOException {
845 return new Route(
846 IO.readNullableString(in),
847 IO.readNullableString(in),
848 IO.readNullableString(in),
849 IO.readNullableString(in),
850 IO.reads(Link::read, in),
851 IO.readNullable(UInt::read, in),
852 IO.readNullableString(in),
853 IO.readNullable(IO::readDoc, in),
854 IO.reads(WayPoint::read, in)
855 );
856 }
857
858 /* *************************************************************************
859 * XML stream object serialization
860 * ************************************************************************/
861
862 private static String url(final Route route) {
863 return route.getLinks().isEmpty()
864 ? null
865 : route.getLinks().get(0).getHref().toString();
866 }
867
868 private static String urlname(final Route route) {
869 return route.getLinks().isEmpty()
870 ? null
871 : route.getLinks().get(0).getText().orElse(null);
872 }
873
874 // Define the needed writers for the different versions.
875 private static XMLWriters<Route>
876 writers(final Function<? super Number, String> formatter) {
877 return new XMLWriters<Route>()
878 .v00(XMLWriter.elem("name").map(r -> r._name))
879 .v00(XMLWriter.elem("cmt").map(r -> r._comment))
880 .v00(XMLWriter.elem("desc").map(r -> r._description))
881 .v00(XMLWriter.elem("src").map(r -> r._source))
882 .v11(XMLWriter.elems(Link.WRITER).map(r -> r._links))
883 .v10(XMLWriter.elem("url").map(Route::url))
884 .v10(XMLWriter.elem("urlname").map(Route::urlname))
885 .v00(XMLWriter.elem("number").map(r -> toIntString(r._number)))
886 .v00(XMLWriter.elem("type").map(r -> r._type))
887 .v00(XMLWriter.doc("extensions").map(gpx -> gpx._extensions))
888 .v10(XMLWriter.elems(WayPoint.xmlWriter(Version.V10, "rtept", formatter)).map(r -> r._points))
889 .v11(XMLWriter.elems(WayPoint.xmlWriter(Version.V11, "rtept", formatter)).map(r -> r._points));
890 }
891
892
893 // Define the needed readers for the different versions.
894 private static XMLReaders
895 readers(final Function<? super String, Length> lengthParser) {
896 return new XMLReaders()
897 .v00(XMLReader.elem("name"))
898 .v00(XMLReader.elem("cmt"))
899 .v00(XMLReader.elem("desc"))
900 .v00(XMLReader.elem("src"))
901 .v11(XMLReader.elems(Link.READER))
902 .v10(XMLReader.elem("url").map(Format::parseURI))
903 .v10(XMLReader.elem("urlname"))
904 .v00(XMLReader.elem("number").map(UInt::parse))
905 .v00(XMLReader.elem("type"))
906 .v00(XMLReader.doc("extensions"))
907 .v10(XMLReader.elems(WayPoint.xmlReader(Version.V10, "rtept", lengthParser)))
908 .v11(XMLReader.elems(WayPoint.xmlReader(Version.V11, "rtept", lengthParser)));
909 }
910
911 static XMLWriter<Route> xmlWriter(
912 final Version version,
913 final Function<? super Number, String> formatter
914 ) {
915 return XMLWriter.elem("rte", writers(formatter).writers(version));
916 }
917
918 static XMLReader<Route> xmlReader(
919 final Version version,
920 final Function<? super String, Length> lengthParser
921 ) {
922 return XMLReader.elem(
923 version == Version.V10 ? Route::toRouteV10 : Route::toRouteV11,
924 "rte",
925 readers(lengthParser).readers(version)
926 );
927 }
928
929 @SuppressWarnings("unchecked")
930 private static Route toRouteV11(final Object[] v) {
931 return new Route(
932 (String)v[0],
933 (String)v[1],
934 (String)v[2],
935 (String)v[3],
936 (List<Link>)v[4],
937 (UInt)v[5],
938 (String)v[6],
939 XML.extensions((Document)v[7]),
940 (List<WayPoint>)v[8]
941 );
942 }
943
944 @SuppressWarnings("unchecked")
945 private static Route toRouteV10(final Object[] v) {
946 return new Route(
947 (String)v[0],
948 (String)v[1],
949 (String)v[2],
950 (String)v[3],
951 v[4] != null
952 ? List.of(Link.of((URI)v[4], (String)v[5], null))
953 : null,
954 (UInt)v[6],
955 (String)v[7],
956 XML.extensions((Document)v[8]),
957 (List<WayPoint>)v[9]
958 );
959 }
960
961 }
|