From 23b15a866a537d2080fcfdc82d20b69deea8bbb6 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Wed, 13 May 2026 17:27:57 +0200 Subject: [PATCH 1/2] refactor: use records for data models (#94) --- CHANGELOG.md | 1 + .../de/stklcode/pubtrans/ura/UraClient.java | 8 +- .../stklcode/pubtrans/ura/model/Message.java | 163 +++------- .../de/stklcode/pubtrans/ura/model/Model.java | 2 +- .../de/stklcode/pubtrans/ura/model/Stop.java | 175 +++-------- .../de/stklcode/pubtrans/ura/model/Trip.java | 289 ++++-------------- .../ura/reader/AsyncUraTripReader.java | 4 +- .../stklcode/pubtrans/ura/UraClientTest.java | 170 +++++------ .../pubtrans/ura/model/MessageTest.java | 78 ++--- .../stklcode/pubtrans/ura/model/StopTest.java | 44 +-- .../stklcode/pubtrans/ura/model/TripTest.java | 128 ++++---- 11 files changed, 357 insertions(+), 705 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c338d6f..8ab4fbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. * Java 17 or later required (#91) * Updated JUnit to 6.0.3 (#92) * Updated Jackson dependency to 3.1.3 (#93) +* Use Java _record_ classes for `Message`, `Stop` and `Trip` models (#94) ## 2.0.11 - 2026-05-14 diff --git a/src/main/java/de/stklcode/pubtrans/ura/UraClient.java b/src/main/java/de/stklcode/pubtrans/ura/UraClient.java index 8f8c6c8..0223bc7 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/UraClient.java +++ b/src/main/java/de/stklcode/pubtrans/ura/UraClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -276,7 +276,7 @@ public List getTrips(final Query query, final Integer limit) throws UraCli if (l.get(0).equals(RES_TYPE_URA_VERSION)) { version = l.get(1).toString(); } else if (l.get(0).equals(RES_TYPE_PREDICTION)) { - trips.add(new Trip(l, version)); + trips.add(Trip.of(l, version)); } } line = br.readLine(); @@ -360,7 +360,7 @@ public List getStops(final Query query) throws UraClientException { List l = mapper.readValue(line, mapper.getTypeFactory().constructCollectionType(List.class, Serializable.class)); /* Check if result exists and has correct response type */ if (l != null && !l.isEmpty() && l.get(0).equals(RES_TYPE_STOP)) { - stops.add(new Stop(l)); + stops.add(Stop.of(l)); } } } catch (IOException | JacksonException e) { @@ -433,7 +433,7 @@ public List getMessages(final Query query, final Integer limit) throws if (l.get(0).equals(RES_TYPE_URA_VERSION)) { version = l.get(1).toString(); } else if (l.get(0).equals(RES_TYPE_FLEX_MESSAGE)) { - messages.add(new Message(l, version)); + messages.add(Message.of(l, version)); } } line = br.readLine(); diff --git a/src/main/java/de/stklcode/pubtrans/ura/model/Message.java b/src/main/java/de/stklcode/pubtrans/ura/model/Message.java index 75aa67f..2e54bd6 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/model/Message.java +++ b/src/main/java/de/stklcode/pubtrans/ura/model/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,11 +23,26 @@ /** * Entity for a message. * + * @param stop The stop, the message is targeted. + * @param uuid Message's unique identifier. + * @param type Messages are assigned a type. + * This is predominantly in order to define how they should be displayed on on-street signs, however can + * be used to alter display on other devices. + *
    + *
  • 0: “Normal”
  • + *
  • 1: “Special”
  • + *
  • 2: “Full Matrix” – Stop is temporarily out of service and predictions should not be presented
  • + *
+ * @param priority Messages are assigned a priority in order for them to be ranked. + * Since it is possible for a stop to be assigned multiple messages it is important to ensure priority + * is given.* Priorities are between 1 and 10 (where 1 is the highest priority). By default, the message + * priority is set to 3. + * @param text The text of the message. This should be displayed to the public. * @author Stefan Kalscheuer * @since 1.3 + * @since 3.0 record */ -public class Message implements Model { - private static final long serialVersionUID = 5233610751062774273L; +public record Message(Stop stop, String uuid, int type, int priority, String text) implements Model { private static final int MSG_UUID = 7; private static final int MSG_TYPE = 8; @@ -35,31 +50,6 @@ public class Message implements Model { private static final int MSG_TEXT = 10; private static final int NUM_OF_FIELDS = 11; - /** - * Corresponding stop. - */ - private final Stop stop; - - /** - * Message UUID. - */ - private final String uuid; - - /** - * Message type. - */ - private final Integer type; - - /** - * Message priority. - */ - private final Integer priority; - - /** - * Message text. - */ - private final String text; - /** * Construct Message object from complete set of data. * @@ -85,36 +75,15 @@ public Message(final String stopID, final Integer msgPriority, final String msgText) { this(new Stop(stopID, - stopName, - stopIndicator, - stopState, - stopLatitude, - stopLongitude), - msgUUID, - msgType, - msgPriority, - msgText); - } - - /** - * Construct Message object from Stop model and set of additional data. - * - * @param stop Stop model - * @param msgUUID Message UUID. - * @param msgType Message type. - * @param msgPriority Message priority. - * @param msgText Message text. - */ - public Message(final Stop stop, - final String msgUUID, - final Integer msgType, - final Integer msgPriority, - final String msgText) { - this.stop = stop; - this.uuid = msgUUID; - this.type = msgType; - this.priority = msgPriority; - this.text = msgText; + stopName, + stopIndicator, + stopState, + stopLatitude, + stopLongitude), + msgUUID, + msgType, + msgPriority, + msgText); } /** @@ -123,8 +92,8 @@ public Message(final Stop stop, * @param raw List of attributes from JSON line * @throws IOException Thrown on invalid line format. */ - public Message(final List raw) throws IOException { - this(raw, null); + public static Message of(final List raw) throws IOException { + return of(raw, null); } /** @@ -134,89 +103,29 @@ public Message(final List raw) throws IOException { * @param version API version * @throws IOException Thrown on invalid line format. */ - public Message(final List raw, final String version) throws IOException { + public static Message of(final List raw, final String version) throws IOException { if (raw == null || raw.size() < NUM_OF_FIELDS) { throw new IOException("Invalid number of fields"); } - stop = new Stop(raw); + var stop = Stop.of(raw); - if (raw.get(MSG_UUID) instanceof String) { - uuid = (String) raw.get(MSG_UUID); - } else { + if (!(raw.get(MSG_UUID) instanceof String uuid)) { throw Model.typeErrorString(MSG_UUID, raw.get(MSG_UUID).getClass()); } - if (raw.get(MSG_TYPE) instanceof Integer) { - type = (Integer) raw.get(MSG_TYPE); - } else { + if (!(raw.get(MSG_TYPE) instanceof Integer type)) { throw Model.typeError(MSG_TYPE, raw.get(MSG_TYPE).getClass(), "Integer"); } - if (raw.get(MSG_PRIORITY) instanceof Integer) { - priority = (Integer) raw.get(MSG_PRIORITY); - } else { + if (!(raw.get(MSG_PRIORITY) instanceof Integer priority)) { throw Model.typeError(MSG_PRIORITY, raw.get(MSG_PRIORITY).getClass(), "Integer"); } - if (raw.get(MSG_TEXT) instanceof String) { - text = (String) raw.get(MSG_TEXT); - } else { + if (!(raw.get(MSG_TEXT) instanceof String text)) { throw Model.typeErrorString(MSG_TEXT, raw.get(MSG_TEXT).getClass()); } - } - - /** - * The stop, the message is targeted. - * - * @return The affected stop. - */ - public Stop getStop() { - return stop; - } - - /** - * This is the unique identifier of the flexible message. - * - * @return Message's unique identifier. - */ - public String getUuid() { - return uuid; - } - - /** - * Messages are assigned a type. - * This is predominantly in order to define how they should be displayed on on-street signs, however can be used to - * alter display on other devices. - *
    - *
  • 0: “Normal”
  • - *
  • 1: “Special”
  • - *
  • 2: “Full Matrix” – Stop is temporarily out of service and predictions should not be presented
  • - *
- * - * @return Message type. - */ - public Integer getType() { - return type; - } - - /** - * Messages are assigned a priority in order for them to be ranked. - * Since it is possible for a stop to be assigned multiple messages it is important to ensure priority is given. - * Priorities are between 1 and 10 (where 1 is the highest priority). By default, the message priority is set to 3. - * - * @return Message priority. - */ - public Integer getPriority() { - return priority; - } - /** - * The text of the message. This should be displayed to the public. - * - * @return Message text. - */ - public String getText() { - return text; + return new Message(stop, uuid, type, priority, text); } } diff --git a/src/main/java/de/stklcode/pubtrans/ura/model/Model.java b/src/main/java/de/stklcode/pubtrans/ura/model/Model.java index c5ba85a..81b0b9d 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/model/Model.java +++ b/src/main/java/de/stklcode/pubtrans/ura/model/Model.java @@ -47,6 +47,6 @@ static IOException typeErrorString(int field, Class actual) { */ static IOException typeError(int field, Class actual, String expected) { return new IOException(String.format("Field %d not of expected type %s, found %s", - field, expected, actual.getSimpleName())); + field, expected, actual.getSimpleName())); } } diff --git a/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java b/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java index 27adeaa..fa36457 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java +++ b/src/main/java/de/stklcode/pubtrans/ura/model/Stop.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,11 +23,33 @@ /** * Entity for a single stop. * + * @param id Stop identifier. + * @param name The name of the bus stop. + * @param indicator The letter(s) that are displayed on top of the bus stop flag (e.g. SA). + * These are used to help passengers easily identify a bus stop from others in the locality. + * @param state The different stop states and their definitions are provided below: + *
    + *
  • 0: “Open”: Bus stop is being served as usual
  • + *
  • 1: “Temporarily Closed” : Vehicles are not serving the stop but may be serving a nearby bus + * stop, predictions may be available
  • + *
  • 2: “Closed” : Vehicles are not serving the stop. + * Stop should display the closed message and predictions should not be shown.
  • + *
  • 3: “Suspended” : Vehicles are not serving the stop. + * Stop should display the closed message and predictions should not be shown.
  • + *
+ * @param latitude The latitude of the stop. This is expressed using the WGS84 coordinate system. + * @param longitude The longitude of the stop. This is expressed using the WGS84 coordinate system. * @author Stefan Kalscheuer + * @since 2.0 record */ -public final class Stop implements Model { - private static final long serialVersionUID = 202040044477267787L; - +public record Stop( + String id, + String name, + String indicator, + int state, + double latitude, + double longitude +) implements Model { private static final int F_STOP_NAME = 1; private static final int F_STOP_ID = 2; private static final int F_INDICATOR = 3; @@ -36,171 +58,46 @@ public final class Stop implements Model { private static final int F_LONGITUDE = 6; private static final int F_NUM_OF_FIELDS = 7; - /** - * Stop identifier. - */ - private final String id; - - /** - * The name of the bus stop. - */ - private final String name; - - /** - * The stop indicator. - */ - private final String indicator; - - /** - * The stop state - */ - private final Integer state; - - /** - * The stop geolocation latitude. - */ - private final Double latitude; - - /** - * The stop geolocation longitude. - */ - private final Double longitude; - - /** - * Construct Stop object. - * - * @param id Stop ID. - * @param name Stop name. - * @param indicator Stop indicator. - * @param state Stop state. - * @param latitude Stop geolocation latitude. - * @param longitude Stop geolocation longitude. - */ - public Stop(final String id, - final String name, - final String indicator, - final Integer state, - final Double latitude, - final Double longitude) { - this.id = id; - this.name = name; - this.indicator = indicator; - this.state = state; - this.latitude = latitude; - this.longitude = longitude; - } - /** * Construct Stop object from raw list of attributes parsed from JSON. * * @param raw List of attributes from JSON line * @throws IOException Thrown on invalid line format. */ - public Stop(final List raw) throws IOException { + public static Stop of(final List raw) throws IOException { if (raw == null || raw.size() < F_NUM_OF_FIELDS) { throw new IOException("Invalid number of fields"); } - if (raw.get(1) instanceof String) { - name = (String) raw.get(F_STOP_NAME); - } else { + if (!(raw.get(F_STOP_NAME) instanceof String name)) { throw Model.typeErrorString(F_STOP_NAME, raw.get(F_STOP_NAME).getClass()); } - if (raw.get(F_STOP_ID) instanceof String) { - id = (String) raw.get(F_STOP_ID); - } else { + if (!(raw.get(F_STOP_ID) instanceof String id)) { throw Model.typeErrorString(F_STOP_ID, raw.get(F_STOP_ID).getClass()); } - if (raw.get(F_INDICATOR) instanceof String) { - indicator = (String) raw.get(F_INDICATOR); + String indicator; + if (raw.get(F_INDICATOR) instanceof String indicatorStr) { + indicator = indicatorStr; } else if (raw.get(F_INDICATOR) == null) { indicator = null; } else { throw Model.typeErrorString(F_INDICATOR, raw.get(F_INDICATOR).getClass()); } - if (raw.get(F_STATE) instanceof Integer) { - state = (Integer) raw.get(F_STATE); - } else { + if (!(raw.get(F_STATE) instanceof Integer state)) { throw Model.typeError(F_STATE, raw.get(F_STATE).getClass(), "Integer"); } - if (raw.get(F_LATITUDE) instanceof Double) { - latitude = (Double) raw.get(F_LATITUDE); - } else { + if (!(raw.get(F_LATITUDE) instanceof Double latitude)) { throw Model.typeError(F_LATITUDE, raw.get(F_LATITUDE).getClass(), "Double"); } - if (raw.get(F_LONGITUDE) instanceof Double) { - longitude = (Double) raw.get(F_LONGITUDE); - } else { + if (!(raw.get(F_LONGITUDE) instanceof Double longitude)) { throw Model.typeError(F_LONGITUDE, raw.get(F_LONGITUDE).getClass(), "Double"); } - } - - /** - * Stop identifier. - * - * @return The stop ID. - */ - public String getId() { - return id; - } - /** - * The name of the bus stop. - * - * @return The stop name. - */ - public String getName() { - return name; - } - - /** - * The letter(s) that are displayed on top of the bus stop flag (e.g. SA). - * These are used to help passengers easily identify a bus stop from others in the locality. - * - * @return The stop indicator. - */ - public String getIndicator() { - return indicator; - } - - /** - * The different stop states and their definitions are provided below: - *
    - *
  • 0: “Open”: Bus stop is being served as usual
  • - *
  • 1: “Temporarily Closed” : Vehicles are not serving the stop but may be serving a nearby bus stop, - * predictions may be available
  • - *
  • 2: “Closed” : Vehicles are not serving the stop. - * Stop should display the closed message and predictions should not be shown.
  • - *
  • 3: “Suspended” : Vehicles are not serving the stop. - * Stop should display the closed message and predictions should not be shown.
  • - *
- * - * @return The stop state. - */ - public Integer getState() { - return state; - } - - /** - * The latitude of the stop. This is expressed using the WGS84 coordinate system. - * - * @return The stop geolocation latitude. - */ - public Double getLatitude() { - return latitude; - } - - /** - * The longitude of the stop. This is expressed using the WGS84 coordinate system. - * - * @return The stop geolocation longitude. - */ - public Double getLongitude() { - return longitude; + return new Stop(id, name, indicator, state, latitude, longitude); } } diff --git a/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java b/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java index ee21dc7..ebde06e 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java +++ b/src/main/java/de/stklcode/pubtrans/ura/model/Trip.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,11 +23,38 @@ /** * Entity for a single trip. * + * @param stop The starting stop. + * @param id The identifier of the specific trip that the prediction is for. + * @param visitID Visit identifier. + * @param lineID The identifier of a route. This is an internal identifier and is not equal to the route number + * displayed on the front of the bus. It should not be displayed to the public. + * @param lineName This is the route number that is displayed on the front of the bus and on any publicity + * advertising the route. + * @param directionID This identifies the direction of the trip that the vehicle is on. + * It indicates whether the vehicle is on an outbound or inbound trip. + * @param destinationName The full length destination name of the trip the vehicle is on. + * The destination name is based on the route and end point of the trip. + * @param destinationText The abbreviated destination name of the trip the vehicle is on. + * The destination text is based on the route and end point of the trip. + * @param estimatedTime This is the predicted time of arrival for the vehicle at a specific stop. + * It is an absolute time in UTC as per Unix epoch (in milliseconds). + * @param vehicleID The unique identifier of the vehicle. This is an internal identifier and should not be + * displayed to the public. * @author Stefan Kalscheuer + * @since 2.0 record */ -public final class Trip implements Model { - private static final long serialVersionUID = 7477381188869237381L; - +public record Trip( + Stop stop, + String id, + int visitID, + String lineID, + String lineName, + int directionID, + String destinationName, + String destinationText, + long estimatedTime, + String vehicleID +) implements Model { private static final int VISIT_ID = 7; private static final int LINE_ID = 8; private static final int LINE_NAME = 9; @@ -39,55 +66,6 @@ public final class Trip implements Model { private static final int ESTIMATED_TIME = 15; private static final int NUM_OF_FIELDS = 16; - /** - * The starting stop. - */ - private final Stop stop; - - /** - * The identifier of the specific trip that the prediction is for. - */ - private final String id; - - /** - * Visit identifier. - */ - private final Integer visitID; - - /** - * The line ID. - */ - private final String lineID; - - /** - * The line name - */ - private final String lineName; - - /** - * The direction ID. - */ - private final Integer directionID; - - /** - * The destination name. - */ - private final String destinationName; - - /** - * The destination text. - */ - private final String destinationText; - - /** - * The estimated departure time. - */ - private final Long estimatedTime; - - /** - * The vehicle ID. - */ - private final String vehicleID; /** * Construct Trip object from complete set of data. @@ -124,57 +102,22 @@ public Trip(final String stopID, final String tripID, final Long estimatedTime) { this(new Stop(stopID, - stopName, - stopIndicator, - stopState, - stopLatitude, - stopLongitude), - visitID, - lineID, - lineName, - directionID, - destinationName, - destinationText, - vehicleID, - tripID, - estimatedTime); + stopName, + stopIndicator, + stopState, + stopLatitude, + stopLongitude), + tripID, + visitID, + lineID, + lineName, + directionID, + destinationName, + destinationText, + estimatedTime, + vehicleID); } - /** - * Construct Trip object from Stop model and set of additional data. - * - * @param stop Stop model - * @param visitID Visit ID - * @param lineID Line ID - * @param lineName Line name - * @param directionID Direction ID - * @param destinationName Destination name - * @param destinationText Destination text - * @param vehicleID Vehicle ID - * @param tripID Trip ID - * @param estimatedTime Estimated time - */ - public Trip(final Stop stop, - final Integer visitID, - final String lineID, - final String lineName, - final Integer directionID, - final String destinationName, - final String destinationText, - final String vehicleID, - final String tripID, - final Long estimatedTime) { - this.stop = stop; - this.visitID = visitID; - this.lineID = lineID; - this.lineName = lineName; - this.directionID = directionID; - this.destinationName = destinationName; - this.destinationText = destinationText; - this.vehicleID = vehicleID; - this.id = tripID; - this.estimatedTime = estimatedTime; - } /** * Construct Trip object from raw list of attributes parsed from JSON. @@ -182,8 +125,8 @@ public Trip(final Stop stop, * @param raw List of attributes from JSON line * @throws IOException Thrown on invalid line format. */ - public Trip(final List raw) throws IOException { - this(raw, null); + public static Trip of(final List raw) throws IOException { + return of(raw, null); } /** @@ -193,35 +136,30 @@ public Trip(final List raw) throws IOException { * @param version API version * @throws IOException Thrown on invalid line format. */ - public Trip(final List raw, final String version) throws IOException { + public static Trip of(final List raw, final String version) throws IOException { if (raw == null || raw.size() < NUM_OF_FIELDS) { throw new IOException("Invalid number of fields"); } - stop = new Stop(raw); + var stop = Stop.of(raw); - if (raw.get(VISIT_ID) instanceof Integer) { - visitID = (Integer) raw.get(VISIT_ID); - } else { + if (!(raw.get(VISIT_ID) instanceof Integer visitID)) { throw Model.typeError(VISIT_ID, raw.get(VISIT_ID).getClass(), "Integer"); } - if (raw.get(LINE_ID) instanceof String) { - lineID = (String) raw.get(LINE_ID); - } else { + if (!(raw.get(LINE_ID) instanceof String lineID)) { throw Model.typeErrorString(LINE_ID, raw.get(LINE_ID).getClass()); } - if (raw.get(LINE_NAME) instanceof String) { - lineName = (String) raw.get(LINE_NAME); - } else { + if (!(raw.get(LINE_NAME) instanceof String lineName)) { throw Model.typeErrorString(LINE_NAME, raw.get(LINE_NAME).getClass()); } + int directionID; if (raw.get(DIRECTION_ID) instanceof String // Also accept Strings (#2) - || raw.get(DIRECTION_ID) instanceof Integer - || raw.get(DIRECTION_ID) instanceof Long) { - directionID = Integer.valueOf(raw.get(DIRECTION_ID).toString()); + || raw.get(DIRECTION_ID) instanceof Integer + || raw.get(DIRECTION_ID) instanceof Long) { + directionID = Integer.parseInt(raw.get(DIRECTION_ID).toString()); if (directionID < 0 || directionID > 2) { throw new IOException("Direction out of range. Expected 1 or 2, found " + directionID); } @@ -229,22 +167,19 @@ public Trip(final List raw, final String version) throws IOExcepti throw Model.typeError(DIRECTION_ID, raw.get(DIRECTION_ID).getClass(), "String/Long/Integer"); } - if (raw.get(DESTINATION_NAME) instanceof String) { - destinationName = (String) raw.get(DESTINATION_NAME); - } else { + if (!(raw.get(DESTINATION_NAME) instanceof String destinationName)) { throw Model.typeErrorString(DESTINATION_NAME, raw.get(DESTINATION_NAME).getClass()); } - if (raw.get(DESTINATION_TEXT) instanceof String) { - destinationText = (String) raw.get(DESTINATION_TEXT); - } else { + if (!(raw.get(DESTINATION_TEXT) instanceof String destinationText)) { throw Model.typeErrorString(DESTINATION_TEXT, raw.get(DESTINATION_TEXT).getClass()); } /* TFL and ASEAG deliver different types with the same API version, so this field is a little more tolerant */ + String vehicleID; if (raw.get(VEHICLE_ID) instanceof String - || raw.get(VEHICLE_ID) instanceof Integer - || raw.get(VEHICLE_ID) instanceof Long) { + || raw.get(VEHICLE_ID) instanceof Integer + || raw.get(VEHICLE_ID) instanceof Long) { vehicleID = raw.get(VEHICLE_ID).toString(); } else if (raw.get(VEHICLE_ID) == null) { // Only fail of field is not NULL (#3). vehicleID = null; @@ -252,111 +187,19 @@ public Trip(final List raw, final String version) throws IOExcepti throw Model.typeError(VEHICLE_ID, raw.get(VEHICLE_ID).getClass(), "String/Integer/Long"); } + String id; if (raw.get(TRIP_ID) instanceof String - || raw.get(TRIP_ID) instanceof Integer - || raw.get(TRIP_ID) instanceof Long) { + || raw.get(TRIP_ID) instanceof Integer + || raw.get(TRIP_ID) instanceof Long) { id = raw.get(TRIP_ID).toString(); } else { throw Model.typeError(TRIP_ID, raw.get(TRIP_ID).getClass(), "String/Integer/Long"); } - if (raw.get(ESTIMATED_TIME) instanceof Long) { - estimatedTime = (Long) raw.get(ESTIMATED_TIME); - } else { + if (!(raw.get(ESTIMATED_TIME) instanceof Long estimatedTime)) { throw Model.typeError(ESTIMATED_TIME, raw.get(ESTIMATED_TIME).getClass(), "Long"); } - } - - /** - * The starting stop. - * - * @return The (starting) stop. - */ - public Stop getStop() { - return stop; - } - - /** - * @return The trip ID. - */ - public String getId() { - return id; - } - - /** - * Visit identifier. - * - * @return The visit ID. - */ - public Integer getVisitID() { - return visitID; - } - - /** - * The identifier of a route. This is an internal identifier and is not equal to the route number displayed on - * the front of the bus. It should not be displayed to the public. - * - * @return The line ID. - */ - public String getLineID() { - return lineID; - } - - /** - * This is the route number that is displayed on the front of the bus and on any publicity advertising the route. - * - * @return The line name. - */ - public String getLineName() { - return lineName; - } - - /** - * This identifies the direction of the trip that the vehicle is on. - * It indicates whether the vehicle is on an outbound or inbound trip. - * - * @return The direction ID. - */ - public Integer getDirectionID() { - return directionID; - } - - /** - * The full length destination name of the trip the vehicle is on. - * The destination name is based on the route and end point of the trip. - * - * @return The destination name. - */ - public String getDestinationName() { - return destinationName; - } - - /** - * The abbreviated destination name of the trip the vehicle is on. - * The destination text is based on the route and end point of the trip. - * - * @return The destination text. - */ - public String getDestinationText() { - return destinationText; - } - - /** - * This is the predicted time of arrival for the vehicle at a specific stop. - * It is an absolute time in UTC as per Unix epoch (in milliseconds). - * - * @return The estimated departure time. - */ - public Long getEstimatedTime() { - return estimatedTime; - } - /** - * The unique identifier of the vehicle. This is an internal identifier and should not be displayed to the public. - * - * @return The vehicle ID or {@code null} if not present. - */ - public String getVehicleID() { - return vehicleID; + return new Trip(stop, id, visitID, lineID, lineName, directionID, destinationName, destinationText, estimatedTime, vehicleID); } } diff --git a/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java b/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java index 5ce06e1..13b59c9 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java +++ b/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,7 +182,7 @@ public void onNext(String item) { version = l.get(1).toString(); } else if (l.get(0).equals(RES_TYPE_PREDICTION)) { // Parse Trip and pass to each consumer. - Trip trip = new Trip(l, version); + Trip trip = Trip.of(l, version); consumers.forEach(c -> c.accept(trip)); } } diff --git a/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java b/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java index bf9e354..961794a 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/UraClientTest.java @@ -64,11 +64,11 @@ void getStopsTest() throws UraClientException { // List stops and verify some values. List stops = new UraClient(wireMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream").getStops(); assertThat(stops, hasSize(10)); - assertThat(stops.get(0).getId(), is("100210")); - assertThat(stops.get(1).getName(), is("Brockenberg")); - assertThat(stops.get(2).getState(), is(0)); - assertThat(stops.get(3).getLatitude(), is(50.7578775)); - assertThat(stops.get(4).getLongitude(), is(6.0708663)); + assertThat(stops.get(0).id(), is("100210")); + assertThat(stops.get(1).name(), is("Brockenberg")); + assertThat(stops.get(2).state(), is(0)); + assertThat(stops.get(3).latitude(), is(50.7578775)); + assertThat(stops.get(4).longitude(), is(6.0708663)); // Test Exception handling. mockHttpToError(500); @@ -92,12 +92,12 @@ void getStopsForLineTest() throws UraClientException { .forLines("33") .getStops(); assertThat(stops, hasSize(47)); - assertThat(stops.get(0).getId(), is("100000")); - assertThat(stops.get(1).getName(), is("Kuckelkorn")); - assertThat(stops.get(2).getState(), is(0)); - assertThat(stops.get(3).getLatitude(), is(50.7690688)); - assertThat(stops.get(4).getIndicator(), is("H.1")); - assertThat(stops.get(5).getLongitude(), is(6.2314072)); + assertThat(stops.get(0).id(), is("100000")); + assertThat(stops.get(1).name(), is("Kuckelkorn")); + assertThat(stops.get(2).state(), is(0)); + assertThat(stops.get(3).latitude(), is(50.7690688)); + assertThat(stops.get(4).indicator(), is("H.1")); + assertThat(stops.get(5).longitude(), is(6.2314072)); } @Test @@ -110,12 +110,12 @@ void getStopsForPositionTest() throws UraClientException { .forPosition(51.51009, -0.1345734, 200) .getStops(); assertThat(stops, hasSize(13)); - assertThat(stops.get(0).getId(), is("156")); - assertThat(stops.get(1).getName(), is("Piccadilly Circus")); - assertThat(stops.get(2).getState(), is(0)); - assertThat(stops.get(3).getLatitude(), is(51.509154)); - assertThat(stops.get(4).getLongitude(), is(-0.134172)); - assertThat(stops.get(5).getIndicator(), is(nullValue())); + assertThat(stops.get(0).id(), is("156")); + assertThat(stops.get(1).name(), is("Piccadilly Circus")); + assertThat(stops.get(2).state(), is(0)); + assertThat(stops.get(3).latitude(), is(51.509154)); + assertThat(stops.get(4).longitude(), is(-0.134172)); + assertThat(stops.get(5).indicator(), is(nullValue())); mockHttpToFile(1, "instant_V1_stops_circle_name.txt"); stops = new UraClient(wireMock.baseUrl()) @@ -123,7 +123,7 @@ void getStopsForPositionTest() throws UraClientException { .forPosition(51.51009, -0.1345734, 200) .getStops(); assertThat(stops, hasSize(7)); - assertThat(stops.stream().filter(t -> !t.getName().equals("Piccadilly Circus")).findAny(), is(Optional.empty())); + assertThat(stops.stream().filter(t -> !t.name().equals("Piccadilly Circus")).findAny(), is(Optional.empty())); } @Test @@ -134,7 +134,7 @@ void getTripsForDestinationNamesTest() throws UraClientException { // List stops and verify some values. List trips = new UraClient(wireMock.baseUrl()).forDestinationNames("Piccadilly Circus").getTrips(); assertThat(trips, hasSize(9)); - assertThat(trips.stream().filter(t -> !t.getDestinationName().equals("Piccadilly Cir")).findAny(), + assertThat(trips.stream().filter(t -> !t.destinationName().equals("Piccadilly Cir")).findAny(), is(Optional.empty())); mockHttpToFile(1, "instant_V1_trips_stop_destination.txt"); @@ -143,9 +143,9 @@ void getTripsForDestinationNamesTest() throws UraClientException { .forDestinationNames("Marble Arch") .getTrips(); assertThat(trips, hasSize(5)); - assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("156")).findAny(), + assertThat(trips.stream().filter(t -> !t.stop().id().equals("156")).findAny(), is(Optional.empty())); - assertThat(trips.stream().filter(t -> !t.getDestinationName().equals("Marble Arch")).findAny(), + assertThat(trips.stream().filter(t -> !t.destinationName().equals("Marble Arch")).findAny(), is(Optional.empty())); } @@ -161,7 +161,7 @@ void getTripsTowardsTest() throws UraClientException { mockHttpToFile(1, "instant_V1_trips_stop_towards.txt"); trips = new UraClient(wireMock.baseUrl()).forStops("156").towards("Marble Arch").getTrips(); assertThat(trips, hasSize(17)); - assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("156")).findAny(), is(Optional.empty())); + assertThat(trips.stream().filter(t -> !t.stop().id().equals("156")).findAny(), is(Optional.empty())); } @Test @@ -172,16 +172,16 @@ void getTripsTest() throws UraClientException { // Get trips without filters and verify some values. List trips = new UraClient(wireMock.baseUrl()).getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.get(0).getId(), is("27000165015001")); - assertThat(trips.get(1).getLineID(), is("55")); - assertThat(trips.get(2).getLineName(), is("28")); - assertThat(trips.get(3).getDirectionID(), is(1)); - assertThat(trips.get(4).getDestinationName(), is("Verlautenheide Endstr.")); - assertThat(trips.get(5).getDestinationText(), is("Aachen Bushof")); - assertThat(trips.get(6).getVehicleID(), is("247")); - assertThat(trips.get(7).getEstimatedTime(), is(1482854580000L)); - assertThat(trips.get(8).getVisitID(), is(30)); - assertThat(trips.get(9).getStop().getId(), is("100002")); + assertThat(trips.get(0).id(), is("27000165015001")); + assertThat(trips.get(1).lineID(), is("55")); + assertThat(trips.get(2).lineName(), is("28")); + assertThat(trips.get(3).directionID(), is(1)); + assertThat(trips.get(4).destinationName(), is("Verlautenheide Endstr.")); + assertThat(trips.get(5).destinationText(), is("Aachen Bushof")); + assertThat(trips.get(6).vehicleID(), is("247")); + assertThat(trips.get(7).estimatedTime(), is(1482854580000L)); + assertThat(trips.get(8).visitID(), is(30)); + assertThat(trips.get(9).stop().id(), is("100002")); // With limit. trips = new UraClient(wireMock.baseUrl()).getTrips(5); @@ -196,16 +196,16 @@ void getTripsTest() throws UraClientException { trips = new UraClient(wireMock.baseUrl(), "/interfaces/ura/instant_V2", "/interfaces/ura/stream") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.get(0).getId(), is("27000165015001")); - assertThat(trips.get(1).getLineID(), is("55")); - assertThat(trips.get(2).getLineName(), is("28")); - assertThat(trips.get(3).getDirectionID(), is(1)); - assertThat(trips.get(4).getDestinationName(), is("Verlautenheide Endstr.")); - assertThat(trips.get(5).getDestinationText(), is("Aachen Bushof")); - assertThat(trips.get(6).getVehicleID(), is("247")); - assertThat(trips.get(7).getEstimatedTime(), is(1482854580000L)); - assertThat(trips.get(8).getVisitID(), is(30)); - assertThat(trips.get(9).getStop().getId(), is("100002")); + assertThat(trips.get(0).id(), is("27000165015001")); + assertThat(trips.get(1).lineID(), is("55")); + assertThat(trips.get(2).lineName(), is("28")); + assertThat(trips.get(3).directionID(), is(1)); + assertThat(trips.get(4).destinationName(), is("Verlautenheide Endstr.")); + assertThat(trips.get(5).destinationText(), is("Aachen Bushof")); + assertThat(trips.get(6).vehicleID(), is("247")); + assertThat(trips.get(7).estimatedTime(), is(1482854580000L)); + assertThat(trips.get(8).visitID(), is(30)); + assertThat(trips.get(9).stop().id(), is("100002")); // Get limited number of trips. mockHttpToFile(1, "instant_V1_trips_all.txt"); @@ -242,11 +242,11 @@ void getTripsForStopTest() throws UraClientException { .forStops("100000") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("100000")).findAny(), is(Optional.empty())); - assertThat(trips.get(0).getId(), is("27000158010001")); - assertThat(trips.get(1).getLineID(), is("7")); - assertThat(trips.get(2).getLineName(), is("25")); - assertThat(trips.get(3).getStop().getIndicator(), is("H.15")); + assertThat(trips.stream().filter(t -> !t.stop().id().equals("100000")).findAny(), is(Optional.empty())); + assertThat(trips.get(0).id(), is("27000158010001")); + assertThat(trips.get(1).lineID(), is("7")); + assertThat(trips.get(2).lineName(), is("25")); + assertThat(trips.get(3).stop().indicator(), is("H.15")); // With limit. trips = new UraClient(wireMock.baseUrl()) @@ -260,12 +260,12 @@ void getTripsForStopTest() throws UraClientException { .forStopsByName("Uniklinik") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getStop().getName().equals("Uniklinik")).findAny(), + assertThat(trips.stream().filter(t -> !t.stop().name().equals("Uniklinik")).findAny(), is(Optional.empty())); - assertThat(trips.get(0).getId(), is("92000043013001")); - assertThat(trips.get(1).getLineID(), is("5")); - assertThat(trips.get(2).getVehicleID(), is("317")); - assertThat(trips.get(3).getDirectionID(), is(1)); + assertThat(trips.get(0).id(), is("92000043013001")); + assertThat(trips.get(1).lineID(), is("5")); + assertThat(trips.get(2).vehicleID(), is("317")); + assertThat(trips.get(3).directionID(), is(1)); mockHttpToException(); UraClientException exception = assertThrows( @@ -287,11 +287,11 @@ void getTripsForLine() throws UraClientException { .forLines("3") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getLineID().equals("3")).findAny(), is(Optional.empty())); - assertThat(trips.get(0).getId(), is("27000154004001")); - assertThat(trips.get(1).getLineID(), is("3")); - assertThat(trips.get(2).getLineName(), is("3.A")); - assertThat(trips.get(3).getStop().getIndicator(), is("H.4 (Pontwall)")); + assertThat(trips.stream().filter(t -> !t.lineID().equals("3")).findAny(), is(Optional.empty())); + assertThat(trips.get(0).id(), is("27000154004001")); + assertThat(trips.get(1).lineID(), is("3")); + assertThat(trips.get(2).lineName(), is("3.A")); + assertThat(trips.get(3).stop().indicator(), is("H.4 (Pontwall)")); // Get trips for line name "3.A" and verify some values. mockHttpToFile(1, "instant_V1_trips_line_name.txt"); @@ -299,11 +299,11 @@ void getTripsForLine() throws UraClientException { .forLinesByName("3.A") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getLineName().equals("3.A")).findAny(), is(Optional.empty())); - assertThat(trips.get(0).getId(), is("92000288014001")); - assertThat(trips.get(1).getLineID(), is("3")); - assertThat(trips.get(2).getLineName(), is("3.A")); - assertThat(trips.get(3).getStop().getName(), is("Aachen Gartenstraße")); + assertThat(trips.stream().filter(t -> !t.lineName().equals("3.A")).findAny(), is(Optional.empty())); + assertThat(trips.get(0).id(), is("92000288014001")); + assertThat(trips.get(1).lineID(), is("3")); + assertThat(trips.get(2).lineName(), is("3.A")); + assertThat(trips.get(3).stop().name(), is("Aachen Gartenstraße")); // Get trips for line 3 with direction 1 and verify some values. mockHttpToFile(1, "instant_V1_trips_line_direction.txt"); @@ -312,8 +312,8 @@ void getTripsForLine() throws UraClientException { .forDirection(2) .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getLineID().equals("412")).findAny(), is(Optional.empty())); - assertThat(trips.stream().filter(t -> !t.getDirectionID().equals(2)).findAny(), is(Optional.empty())); + assertThat(trips.stream().filter(t -> !t.lineID().equals("412")).findAny(), is(Optional.empty())); + assertThat(trips.stream().filter(t -> t.directionID() != 2).findAny(), is(Optional.empty())); // Test lineID and direction in different order. mockHttpToFile(1, "instant_V1_trips_line_direction.txt"); @@ -322,8 +322,8 @@ void getTripsForLine() throws UraClientException { .forLines("412") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getLineID().equals("412")).findAny(), is(Optional.empty())); - assertThat(trips.stream().filter(t -> !t.getDirectionID().equals(2)).findAny(), is(Optional.empty())); + assertThat(trips.stream().filter(t -> !t.lineID().equals("412")).findAny(), is(Optional.empty())); + assertThat(trips.stream().filter(t -> t.directionID() != 2).findAny(), is(Optional.empty())); } @Test @@ -337,13 +337,13 @@ void getTripsForStopAndLine() throws UraClientException { .forStops("100000") .getTrips(); assertThat(trips, hasSize(10)); - assertThat(trips.stream().filter(t -> !t.getLineID().equals("25") && !t.getLineID().equals("35")).findAny(), + assertThat(trips.stream().filter(t -> !t.lineID().equals("25") && !t.lineID().equals("35")).findAny(), is(Optional.empty())); - assertThat(trips.stream().filter(t -> !t.getStop().getId().equals("100000")).findAny(), is(Optional.empty())); - assertThat(trips.get(0).getId(), is("27000078014001")); - assertThat(trips.get(1).getLineID(), is("25")); - assertThat(trips.get(3).getLineName(), is("35")); - assertThat(trips.get(5).getStop().getIndicator(), is("H.12")); + assertThat(trips.stream().filter(t -> !t.stop().id().equals("100000")).findAny(), is(Optional.empty())); + assertThat(trips.get(0).id(), is("27000078014001")); + assertThat(trips.get(1).lineID(), is("25")); + assertThat(trips.get(3).lineName(), is("35")); + assertThat(trips.get(5).stop().indicator(), is("H.12")); } @@ -357,14 +357,14 @@ void getMessages() throws UraClientException { // Get messages without filter and verify some values. List messages = uraClient.getMessages(); assertThat(messages, hasSize(2)); - assertThat(messages.get(0).getStop().getId(), is("100707")); - assertThat(messages.get(0).getUuid(), is("016e1231d4e30014_100707")); - assertThat(messages.get(1).getStop().getName(), is("Herzogenr. Rathaus")); - assertThat(messages.get(1).getUuid(), is("016e2cc3a3750006_210511")); - assertThat(messages.get(0).getType(), is(0)); - assertThat(messages.get(1).getPriority(), is(0)); - assertThat(messages.get(0).getText(), is("Sehr geehrte Fahrgäste, wegen Strassenbauarbeiten kann diese Haltestelle nicht von den Bussen der Linien 17, 44 und N2 angefahren werden.")); - assertThat(messages.get(1).getText(), is("Sehr geehrte Fahrgäste, diese Haltestelle wird vorübergehend von den Linien 47, 147 und N3 nicht angefahren.")); + assertThat(messages.get(0).stop().id(), is("100707")); + assertThat(messages.get(0).uuid(), is("016e1231d4e30014_100707")); + assertThat(messages.get(1).stop().name(), is("Herzogenr. Rathaus")); + assertThat(messages.get(1).uuid(), is("016e2cc3a3750006_210511")); + assertThat(messages.get(0).type(), is(0)); + assertThat(messages.get(1).priority(), is(0)); + assertThat(messages.get(0).text(), is("Sehr geehrte Fahrgäste, wegen Strassenbauarbeiten kann diese Haltestelle nicht von den Bussen der Linien 17, 44 und N2 angefahren werden.")); + assertThat(messages.get(1).text(), is("Sehr geehrte Fahrgäste, diese Haltestelle wird vorübergehend von den Linien 47, 147 und N3 nicht angefahren.")); // With limit. messages = uraClient.getMessages(1); @@ -392,11 +392,11 @@ void getMessagesForStop() throws UraClientException { // Get trips for stop ID 100707 (Berensberger Str.) and verify some values. List messages = uraClient.forStops("100707").getMessages(); assertThat(messages, hasSize(1)); - assertThat(messages.stream().filter(t -> !t.getStop().getId().equals("100707")).findAny(), is(Optional.empty())); - assertThat(messages.get(0).getUuid(), is("016e1231d4e30014_100707")); - assertThat(messages.get(0).getType(), is(0)); - assertThat(messages.get(0).getPriority(), is(3)); - assertThat(messages.get(0).getText(), is("Sehr geehrte Fahrgäste, wegen Strassenbauarbeiten kann diese Haltestelle nicht von den Bussen der Linien 17, 44 und N2 angefahren werden.")); + assertThat(messages.stream().filter(t -> !t.stop().id().equals("100707")).findAny(), is(Optional.empty())); + assertThat(messages.get(0).uuid(), is("016e1231d4e30014_100707")); + assertThat(messages.get(0).type(), is(0)); + assertThat(messages.get(0).priority(), is(3)); + assertThat(messages.get(0).text(), is("Sehr geehrte Fahrgäste, wegen Strassenbauarbeiten kann diese Haltestelle nicht von den Bussen der Linien 17, 44 und N2 angefahren werden.")); // With limit. messages = uraClient.forStops("100707").getMessages(0); diff --git a/src/test/java/de/stklcode/pubtrans/ura/model/MessageTest.java b/src/test/java/de/stklcode/pubtrans/ura/model/MessageTest.java index 3caa543..076d16f 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/model/MessageTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/model/MessageTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,26 +37,28 @@ class MessageTest { @Test void basicConstructorTest() { - Message message = new Message("sid", - "name", - "indicator", - 1, - 2.345, - 6.789, - "msg_uuid", - 1, - 3, - "message text"); - assertThat(message.getStop().getId(), is("sid")); - assertThat(message.getStop().getName(), is("name")); - assertThat(message.getStop().getIndicator(), is("indicator")); - assertThat(message.getStop().getState(), is(1)); - assertThat(message.getStop().getLatitude(), is(2.345)); - assertThat(message.getStop().getLongitude(), is(6.789)); - assertThat(message.getUuid(), is("msg_uuid")); - assertThat(message.getType(), is(1)); - assertThat(message.getPriority(), is(3)); - assertThat(message.getText(), is("message text")); + Message message = new Message( + "sid", + "name", + "indicator", + 1, + 2.345, + 6.789, + "msg_uuid", + 1, + 3, + "message text" + ); + assertThat(message.stop().id(), is("sid")); + assertThat(message.stop().name(), is("name")); + assertThat(message.stop().indicator(), is("indicator")); + assertThat(message.stop().state(), is(1)); + assertThat(message.stop().latitude(), is(2.345)); + assertThat(message.stop().longitude(), is(6.789)); + assertThat(message.uuid(), is("msg_uuid")); + assertThat(message.type(), is(1)); + assertThat(message.priority(), is(3)); + assertThat(message.text(), is("message text")); } @Test @@ -76,17 +78,17 @@ void listConstructorTest() { raw.add("message text"); try { - Message message = new Message(raw); - assertThat(message.getStop().getId(), is("stopId")); - assertThat(message.getStop().getName(), is("stopName")); - assertThat(message.getStop().getIndicator(), is("stopIndicator")); - assertThat(message.getStop().getState(), is(9)); - assertThat(message.getStop().getLatitude(), is(8.765)); - assertThat(message.getStop().getLongitude(), is(43.21)); - assertThat(message.getUuid(), is("msg_uuid")); - assertThat(message.getType(), is(1)); - assertThat(message.getPriority(), is(3)); - assertThat(message.getText(), is("message text")); + Message message = Message.of(raw); + assertThat(message.stop().id(), is("stopId")); + assertThat(message.stop().name(), is("stopName")); + assertThat(message.stop().indicator(), is("stopIndicator")); + assertThat(message.stop().state(), is(9)); + assertThat(message.stop().latitude(), is(8.765)); + assertThat(message.stop().longitude(), is(43.21)); + assertThat(message.uuid(), is("msg_uuid")); + assertThat(message.type(), is(1)); + assertThat(message.priority(), is(3)); + assertThat(message.text(), is("message text")); } catch (IOException e) { fail("Creation of Message from valid list failed: " + e.getMessage()); } @@ -94,7 +96,7 @@ void listConstructorTest() { /* Excess elements should be ignored */ raw.add("foo"); try { - Message message = new Message(raw); + Message message = Message.of(raw); assertThat(message, is(notNullValue())); raw.remove(11); } catch (IOException e) { @@ -106,7 +108,7 @@ void listConstructorTest() { invalid.remove(7); invalid.add(7, 123L); try { - new Message(invalid); + Message.of(invalid); fail("Creation of Message with invalid UUID field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -116,7 +118,7 @@ void listConstructorTest() { invalid.remove(8); invalid.add(8, "abc"); try { - new Message(invalid); + Message.of(invalid); fail("Creation of Message with invalid type field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -126,7 +128,7 @@ void listConstructorTest() { invalid.remove(9); invalid.add(9, "xyz"); try { - new Message(invalid); + Message.of(invalid); fail("Creation of Message with invalid priority field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -136,7 +138,7 @@ void listConstructorTest() { invalid.remove(10); invalid.add(10, 1.23); try { - new Message(invalid); + Message.of(invalid); fail("Creation of Message with invalid text field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -145,7 +147,7 @@ void listConstructorTest() { invalid = new ArrayList<>(raw); invalid.remove(10); try { - new Message(invalid); + Message.of(invalid); fail("Creation of Message with too short list successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); diff --git a/src/test/java/de/stklcode/pubtrans/ura/model/StopTest.java b/src/test/java/de/stklcode/pubtrans/ura/model/StopTest.java index 6e44b9b..75e583a 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/model/StopTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/model/StopTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,12 +38,12 @@ class StopTest { @Test void basicConstructorTest() { Stop stop = new Stop("id", "name", "indicator", 1, 2.345, 6.789); - assertThat(stop.getId(), is("id")); - assertThat(stop.getName(), is("name")); - assertThat(stop.getIndicator(), is("indicator")); - assertThat(stop.getState(), is(1)); - assertThat(stop.getLatitude(), is(2.345)); - assertThat(stop.getLongitude(), is(6.789)); + assertThat(stop.id(), is("id")); + assertThat(stop.name(), is("name")); + assertThat(stop.indicator(), is("indicator")); + assertThat(stop.state(), is(1)); + assertThat(stop.latitude(), is(2.345)); + assertThat(stop.longitude(), is(6.789)); } @Test @@ -59,13 +59,13 @@ void listConstructorTest() { raw.add(4.321); try { - Stop stop = new Stop(raw); - assertThat(stop.getId(), is("stopId")); - assertThat(stop.getName(), is("stopName")); - assertThat(stop.getIndicator(), is("stopIndicator")); - assertThat(stop.getState(), is(9)); - assertThat(stop.getLatitude(), is(8.765)); - assertThat(stop.getLongitude(), is(4.321)); + Stop stop = Stop.of(raw); + assertThat(stop.id(), is("stopId")); + assertThat(stop.name(), is("stopName")); + assertThat(stop.indicator(), is("stopIndicator")); + assertThat(stop.state(), is(9)); + assertThat(stop.latitude(), is(8.765)); + assertThat(stop.longitude(), is(4.321)); } catch (IOException e) { fail("Creation of Stop from valid list failed: " + e.getMessage()); } @@ -73,7 +73,7 @@ void listConstructorTest() { /* Excess elements should be ignored */ raw.add("foo"); try { - Stop stop = new Stop(raw); + Stop stop = Stop.of(raw); assertThat(stop, is(notNullValue())); raw.remove(7); } catch (IOException e) { @@ -85,7 +85,7 @@ void listConstructorTest() { invalid.remove(1); invalid.add(1, 5); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with invalid name field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -95,7 +95,7 @@ void listConstructorTest() { invalid.remove(2); invalid.add(2, 0); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with invalid id field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -105,7 +105,7 @@ void listConstructorTest() { invalid.remove(3); invalid.add(3, -1.23); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with invalid indicator field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -115,7 +115,7 @@ void listConstructorTest() { invalid.remove(4); invalid.add(4, "foo"); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with invalid state field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -125,7 +125,7 @@ void listConstructorTest() { invalid.remove(5); invalid.add(5, "123"); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with invalid latitude field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -135,7 +135,7 @@ void listConstructorTest() { invalid.remove(6); invalid.add(6, 456); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with invalid longitude field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -144,7 +144,7 @@ void listConstructorTest() { invalid = new ArrayList<>(raw); invalid.remove(6); try { - new Stop(invalid); + Stop.of(invalid); fail("Creation of Stop with too short list successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); diff --git a/src/test/java/de/stklcode/pubtrans/ura/model/TripTest.java b/src/test/java/de/stklcode/pubtrans/ura/model/TripTest.java index 4c9aa32..279e750 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/model/TripTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/model/TripTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,35 +38,35 @@ class TripTest { @Test void basicConstructorTest() { Trip trip = new Trip("sid", - "name", - "indicator", - 1, - 2.345, - 6.789, - 123, - "lineid", - "linename", - 0, - "destination name", - "destination text", - "vehicle", - "id", - 123456789123456789L); - assertThat(trip.getStop().getId(), is("sid")); - assertThat(trip.getStop().getName(), is("name")); - assertThat(trip.getStop().getIndicator(), is("indicator")); - assertThat(trip.getStop().getState(), is(1)); - assertThat(trip.getStop().getLatitude(), is(2.345)); - assertThat(trip.getStop().getLongitude(), is(6.789)); - assertThat(trip.getVisitID(), is(123)); - assertThat(trip.getLineID(), is("lineid")); - assertThat(trip.getLineName(), is("linename")); - assertThat(trip.getDirectionID(), is(0)); - assertThat(trip.getDestinationName(), is("destination name")); - assertThat(trip.getDestinationText(), is("destination text")); - assertThat(trip.getVehicleID(), is("vehicle")); - assertThat(trip.getId(), is("id")); - assertThat(trip.getEstimatedTime(), is(123456789123456789L)); + "name", + "indicator", + 1, + 2.345, + 6.789, + 123, + "lineid", + "linename", + 0, + "destination name", + "destination text", + "vehicle", + "id", + 123456789123456789L); + assertThat(trip.stop().id(), is("sid")); + assertThat(trip.stop().name(), is("name")); + assertThat(trip.stop().indicator(), is("indicator")); + assertThat(trip.stop().state(), is(1)); + assertThat(trip.stop().latitude(), is(2.345)); + assertThat(trip.stop().longitude(), is(6.789)); + assertThat(trip.visitID(), is(123)); + assertThat(trip.lineID(), is("lineid")); + assertThat(trip.lineName(), is("linename")); + assertThat(trip.directionID(), is(0)); + assertThat(trip.destinationName(), is("destination name")); + assertThat(trip.destinationText(), is("destination text")); + assertThat(trip.vehicleID(), is("vehicle")); + assertThat(trip.id(), is("id")); + assertThat(trip.estimatedTime(), is(123456789123456789L)); } @Test @@ -91,22 +91,22 @@ void listConstructorTest() { raw.add(123456789123456789L); try { - Trip trip = new Trip(raw); - assertThat(trip.getStop().getId(), is("stopId")); - assertThat(trip.getStop().getName(), is("stopName")); - assertThat(trip.getStop().getIndicator(), is("stopIndicator")); - assertThat(trip.getStop().getState(), is(9)); - assertThat(trip.getStop().getLatitude(), is(8.765)); - assertThat(trip.getStop().getLongitude(), is(43.21)); - assertThat(trip.getVisitID(), is(123)); - assertThat(trip.getLineID(), is("lineid")); - assertThat(trip.getLineName(), is("linename")); - assertThat(trip.getDirectionID(), is(0)); - assertThat(trip.getDestinationName(), is("destination name")); - assertThat(trip.getDestinationText(), is("destination text")); - assertThat(trip.getVehicleID(), is("vehicle")); - assertThat(trip.getId(), is("9876543210")); - assertThat(trip.getEstimatedTime(), is(123456789123456789L)); + Trip trip = Trip.of(raw); + assertThat(trip.stop().id(), is("stopId")); + assertThat(trip.stop().name(), is("stopName")); + assertThat(trip.stop().indicator(), is("stopIndicator")); + assertThat(trip.stop().state(), is(9)); + assertThat(trip.stop().latitude(), is(8.765)); + assertThat(trip.stop().longitude(), is(43.21)); + assertThat(trip.visitID(), is(123)); + assertThat(trip.lineID(), is("lineid")); + assertThat(trip.lineName(), is("linename")); + assertThat(trip.directionID(), is(0)); + assertThat(trip.destinationName(), is("destination name")); + assertThat(trip.destinationText(), is("destination text")); + assertThat(trip.vehicleID(), is("vehicle")); + assertThat(trip.id(), is("9876543210")); + assertThat(trip.estimatedTime(), is(123456789123456789L)); } catch (IOException e) { fail("Creation of Trip from valid list failed: " + e.getMessage()); } @@ -114,8 +114,8 @@ void listConstructorTest() { /* Test with V2 style list */ raw.set(14, "id"); try { - Trip trip = new Trip(raw, "2.0"); - assertThat(trip.getId(), is("id")); + Trip trip = Trip.of(raw, "2.0"); + assertThat(trip.id(), is("id")); } catch (IOException e) { fail("Creation of Trip from valid list failed: " + e.getMessage()); } @@ -124,7 +124,7 @@ void listConstructorTest() { /* Excess elements should be ignored */ raw.add("foo"); try { - Trip trip = new Trip(raw); + Trip trip = Trip.of(raw); assertThat(trip, is(notNullValue())); raw.remove(16); } catch (IOException e) { @@ -134,9 +134,9 @@ void listConstructorTest() { raw.remove(10); raw.add(10, 0L); // Long values are OK. try { - Trip trip = new Trip(raw); + Trip trip = Trip.of(raw); assertThat(trip, is(notNullValue())); - assertThat(trip.getDirectionID(), is(0)); + assertThat(trip.directionID(), is(0)); } catch (IOException e) { fail("Creation of Trip from valid list failed: " + e.getMessage()); } @@ -144,9 +144,9 @@ void listConstructorTest() { raw.remove(10); raw.add(10, "0"); // String values are OK. try { - Trip trip = new Trip(raw); + Trip trip = Trip.of(raw); assertThat(trip, is(notNullValue())); - assertThat(trip.getDirectionID(), is(0)); + assertThat(trip.directionID(), is(0)); } catch (IOException e) { fail("Creation of Trip from valid list failed: " + e.getMessage()); } @@ -156,7 +156,7 @@ void listConstructorTest() { invalid.remove(7); invalid.add(7, "123"); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid visitID field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -166,7 +166,7 @@ void listConstructorTest() { invalid.remove(8); invalid.add(8, 25); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid lineID field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -176,7 +176,7 @@ void listConstructorTest() { invalid.remove(9); invalid.add(9, 234L); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid line name field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -186,7 +186,7 @@ void listConstructorTest() { invalid.remove(10); invalid.add(10, "7"); // Strings are generally OK, but 7 is out of range (#2). try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid directionID field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -196,7 +196,7 @@ void listConstructorTest() { invalid.remove(11); invalid.add(11, 987); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid destinationName field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -206,7 +206,7 @@ void listConstructorTest() { invalid.remove(12); invalid.add(12, 456.78); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid destinationText field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -216,7 +216,7 @@ void listConstructorTest() { invalid.remove(13); invalid.add(13, 'x'); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid vehicleID field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -226,7 +226,7 @@ void listConstructorTest() { invalid.remove(14); invalid.add(14, 1.2); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid id field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -236,7 +236,7 @@ void listConstructorTest() { invalid.remove(15); invalid.add(15, 456); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with invalid estimatedTime field successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -245,7 +245,7 @@ void listConstructorTest() { invalid = new ArrayList<>(raw); invalid.remove(15); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with too short list successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); @@ -254,7 +254,7 @@ void listConstructorTest() { invalid = new ArrayList<>(raw); invalid.set(10, 3); try { - new Trip(invalid); + Trip.of(invalid); fail("Creation of Trip with direction ID 3 successful"); } catch (Exception e) { assertThat(e, is(instanceOf(IOException.class))); From c968730883284219c3c8f73f584c2089c1944bc3 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Thu, 14 May 2026 09:53:30 +0200 Subject: [PATCH 2/2] refactor: use records for client configuration (#94) --- .../de/stklcode/pubtrans/ura/UraClient.java | 12 +-- .../pubtrans/ura/UraClientConfiguration.java | 101 +++--------------- .../ura/reader/AsyncUraTripReader.java | 8 +- .../ura/UraClientConfigurationTest.java | 20 ++-- 4 files changed, 35 insertions(+), 106 deletions(-) diff --git a/src/main/java/de/stklcode/pubtrans/ura/UraClient.java b/src/main/java/de/stklcode/pubtrans/ura/UraClient.java index 0223bc7..9431988 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/UraClient.java +++ b/src/main/java/de/stklcode/pubtrans/ura/UraClient.java @@ -315,7 +315,7 @@ public AsyncUraTripReader getTripsStream(final Query query, final List getMessages(final Query query, final Integer limit) throws * @throws IOException on errors */ private InputStream requestInstant(final String[] returnList, final Query query) throws IOException { - return request(requestURL(config.getBaseURL() + config.getInstantPath(), returnList, query)); + return request(requestURL(config.baseURL() + config.instantPath(), returnList, query)); } /** @@ -497,13 +497,13 @@ private String requestURL(final String endpointURL, final String[] returnList, f private InputStream request(String url) throws IOException { try { var clientBuilder = HttpClient.newBuilder(); - if (config.getConnectTimeout() != null) { - clientBuilder.connectTimeout(config.getConnectTimeout()); + if (config.connectTimeout() != null) { + clientBuilder.connectTimeout(config.connectTimeout()); } var reqBuilder = HttpRequest.newBuilder(URI.create(url)).GET(); - if (config.getTimeout() != null) { - reqBuilder.timeout(config.getTimeout()); + if (config.timeout() != null) { + reqBuilder.timeout(config.timeout()); } return clientBuilder.build().send(reqBuilder.build(), HttpResponse.BodyHandlers.ofInputStream()).body(); diff --git a/src/main/java/de/stklcode/pubtrans/ura/UraClientConfiguration.java b/src/main/java/de/stklcode/pubtrans/ura/UraClientConfiguration.java index 0b91a1d..1c91a08 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/UraClientConfiguration.java +++ b/src/main/java/de/stklcode/pubtrans/ura/UraClientConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2024 Stefan Kalscheuer + * Copyright 2016-2026 Stefan Kalscheuer * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,40 +22,26 @@ /** * Configuration Object for the {@link UraClient}. * + * @param baseURL API base URL. + * @param instantPath Path to instant API endpoint. + * @param streamPath Path to stream API endpoint. + * @param connectTimeout Optional connection timeout. + * @param timeout Optional read timeout. * @author Stefan Kalscheuer * @since 2.0 + * @since 3.0 record */ -public class UraClientConfiguration implements Serializable { - private static final long serialVersionUID = 1L; +public record UraClientConfiguration( + String baseURL, + String instantPath, + String streamPath, + Duration connectTimeout, + Duration timeout +) implements Serializable { private static final String DEFAULT_INSTANT_PATH = "/interfaces/ura/instant_V1"; private static final String DEFAULT_STREAM_PATH = "/interfaces/ura/stream_V1"; - /** - * API base URL. - */ - private final String baseURL; - - /** - * Path to instant API endpoint. - */ - private final String instantPath; - - /** - * Path to stream API endpoint. - */ - private final String streamPath; - - /** - * Optional connection timeout. - */ - private final Duration connectTimeout; - - /** - * Optional read timeout. - */ - private final Duration timeout; - /** * Get new configuration {@link Builder} for given base URL. * This URL is the only option required. @@ -67,63 +53,6 @@ public static Builder forBaseURL(final String baseURL) { return new Builder(baseURL); } - /** - * Construct new configuration object from Builder. - * - * @param builder The builder instance. - */ - private UraClientConfiguration(Builder builder) { - this.baseURL = builder.baseURL; - this.instantPath = builder.instantPath; - this.streamPath = builder.streamPath; - this.connectTimeout = builder.connectTimeout; - this.timeout = builder.timeout; - } - - /** - * Get the API base URL. - * - * @return Base URL. - */ - public String getBaseURL() { - return baseURL; - } - - /** - * Get the API instant endpoint path. - * - * @return Instant endpoint path. - */ - public String getInstantPath() { - return this.instantPath; - } - - /** - * Get the API stream endpoint path. - * - * @return Stream endpoint path. - */ - public String getStreamPath() { - return this.streamPath; - } - - /** - * Get the connection timeout, if any. - * - * @return Timeout duration or {@code null} if none specified. - */ - public Duration getConnectTimeout() { - return this.connectTimeout; - } - - /** - * Get the response timeout, if any. - * - * @return Timeout duration or {@code null} if none specified. - */ - public Duration getTimeout() { - return this.timeout; - } /** * Builder for {@link UraClientConfiguration} objects. @@ -199,7 +128,7 @@ public Builder withTimeout(Duration timeout) { * @return The configuration. */ public UraClientConfiguration build() { - return new UraClientConfiguration(this); + return new UraClientConfiguration(baseURL, instantPath, streamPath, connectTimeout, timeout); } } } diff --git a/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java b/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java index 13b59c9..08bafc4 100644 --- a/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java +++ b/src/main/java/de/stklcode/pubtrans/ura/reader/AsyncUraTripReader.java @@ -99,13 +99,13 @@ public void open() { this.subscriber = new JsonLineSubscriber(); HttpClient.Builder clientBuilder = HttpClient.newBuilder(); - if (config != null && config.getConnectTimeout() != null) { - clientBuilder.connectTimeout(config.getConnectTimeout()); + if (config != null && config.connectTimeout() != null) { + clientBuilder.connectTimeout(config.connectTimeout()); } HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(uri).GET(); - if (config != null && config.getTimeout() != null) { - reqBuilder.timeout(config.getTimeout()); + if (config != null && config.timeout() != null) { + reqBuilder.timeout(config.timeout()); } clientBuilder.build().sendAsync( diff --git a/src/test/java/de/stklcode/pubtrans/ura/UraClientConfigurationTest.java b/src/test/java/de/stklcode/pubtrans/ura/UraClientConfigurationTest.java index 3ab0241..b28dd44 100644 --- a/src/test/java/de/stklcode/pubtrans/ura/UraClientConfigurationTest.java +++ b/src/test/java/de/stklcode/pubtrans/ura/UraClientConfigurationTest.java @@ -39,27 +39,27 @@ void configBuilderTest() { // With Base-URL only. UraClientConfiguration config = UraClientConfiguration.forBaseURL(baseURL).build(); - assertEquals(baseURL, config.getBaseURL(), "Unexpected base URL"); - assertEquals("/interfaces/ura/instant_V1", config.getInstantPath(), "Unexpected default instant path"); - assertEquals("/interfaces/ura/stream_V1", config.getStreamPath(), "Unexpected default stream path"); - assertNull(config.getConnectTimeout(), "No default connection timeout expected"); - assertNull(config.getTimeout(), "No default timeout expected"); + assertEquals(baseURL, config.baseURL(), "Unexpected base URL"); + assertEquals("/interfaces/ura/instant_V1", config.instantPath(), "Unexpected default instant path"); + assertEquals("/interfaces/ura/stream_V1", config.streamPath(), "Unexpected default stream path"); + assertNull(config.connectTimeout(), "No default connection timeout expected"); + assertNull(config.timeout(), "No default timeout expected"); // With custom paths. config = UraClientConfiguration.forBaseURL(baseURL) .withInstantPath(instantPath) .withStreamPath(streamPath) .build(); - assertEquals(baseURL, config.getBaseURL(), "Unexpected base URL"); - assertEquals(instantPath, config.getInstantPath(), "Unexpected custom instant path"); - assertEquals(streamPath, config.getStreamPath(), "Unexpected custom stream path"); + assertEquals(baseURL, config.baseURL(), "Unexpected base URL"); + assertEquals(instantPath, config.instantPath(), "Unexpected custom instant path"); + assertEquals(streamPath, config.streamPath(), "Unexpected custom stream path"); // With timeouts. (#14) config = UraClientConfiguration.forBaseURL(baseURL) .withConnectTimeout(conTimeout) .withTimeout(timeout) .build(); - assertEquals(conTimeout, config.getConnectTimeout(), "Unexpected connection timeout value"); - assertEquals(timeout, config.getTimeout(), "Unexpected timeout value"); + assertEquals(conTimeout, config.connectTimeout(), "Unexpected connection timeout value"); + assertEquals(timeout, config.timeout(), "Unexpected timeout value"); } }