diff --git a/mapbuilder/Dockerfile b/mapbuilder/Dockerfile
index 7e5c62c60c36de9894fb8464329953aa31033a86..c425e1f22ca8352c7ead3f63d59bb9c18d6e50fb 100644
--- a/mapbuilder/Dockerfile
+++ b/mapbuilder/Dockerfile
@@ -1,10 +1,11 @@
-FROM eclipse-temurin:17-jdk-alpine
+FROM eclipse-temurin:19-jdk-alpine
 ADD target/*-jar-with-dependencies.jar app.jar
+COPY src/main/resources/config.properties /data/configuration/config.properties
 
 # Add the cron job
 # Calculate the map each day at 00:00
 # For testing: set it to * * * * * to run it each minute
-RUN echo "0 0 * * * java -jar /app.jar" >> /var/spool/cron/crontabs/root
+RUN echo "0 0 * * * java -jar -Xmx10g /app.jar" >> /var/spool/cron/crontabs/root
 
 # Start the cron deamon
 CMD crond -f
\ No newline at end of file
diff --git a/mapbuilder/pom.xml b/mapbuilder/pom.xml
index 5f81a98ff8d1755e5614d603be46d8889f0484d7..f046fbe6a24fdea8fbf5b1a147aa45f04a04d301 100644
--- a/mapbuilder/pom.xml
+++ b/mapbuilder/pom.xml
@@ -24,11 +24,6 @@
       <version>4.11</version>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>com.google.protobuf</groupId>
-      <artifactId>protobuf-java</artifactId>
-      
-    </dependency>
     <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-io</artifactId>
diff --git a/mapbuilder/src/main/java/map/builder/App.java b/mapbuilder/src/main/java/map/builder/App.java
index 7e73608eff0cf383d1210a48a91663e0f4db8674..cb773aa8823867387a29871121bb12e9b3ccbc84 100644
--- a/mapbuilder/src/main/java/map/builder/App.java
+++ b/mapbuilder/src/main/java/map/builder/App.java
@@ -1,20 +1,26 @@
 package map.builder;
 
+import static map.builder.utilities.Config.ROAD_NETWORK_OUTPUT_PATH;
+
 import java.io.IOException;
 import java.util.ArrayList;
-
-import org.json.JSONArray;
+import java.util.List;
 
 import de.fuberlin.navigator.protos.map_builder.RoadNetwork;
 import map.builder.osm.OSMConnectedComponentParser;
 import map.builder.osm.OSMFetcher;
 import map.builder.osm.OSMParser;
+import map.builder.osm.json.model.OSMJsonDto;
 import map.builder.utilities.BoundingBox;
+import map.builder.utilities.Config;
 import map.builder.utilities.ConnectedComponentGraph;
 import map.builder.utilities.FileHandler;
 
 public class App {
     public static void main(String[] args) throws IOException {
+        System.out.println("Map builder started!");
+        Config.load();
+
         RoadNetwork.Builder roadNetworkBuilder = RoadNetwork.newBuilder();
         OSMParser parser = new OSMParser();
 
@@ -42,12 +48,13 @@ public class App {
 
         BoundingBox bbox = new BoundingBox(minLat, minLon, maxLat, maxLon);
 
-        JSONArray restrictions = OSMFetcher.fetchTurnRestrictions(bbox);
-        JSONArray roads = OSMFetcher.fetchNodesAndWays(bbox);
-        OSMFetcher.dumpJsonData(roads, "test_data.json");
+        List<OSMJsonDto> restrictions = OSMFetcher.fetchTurnRestrictions(bbox);
+        List<OSMJsonDto> roads = OSMFetcher.fetchNodesAndWays(bbox);
 
+        System.out.println("Starting to parse.");
         parser.parseTurnRestrictions(restrictions);
         parser.parseRoads(roads);
+        System.out.println("Parsed road network.");
 
         // set it to 0 so that it can be collected by garbage collector
         restrictions = null;
@@ -70,6 +77,6 @@ public class App {
         System.out.println("Turn restrictions count: " + roadNetwork.getTurnRestrictionsCount());
         System.out.println("Nodes count: " + roadNetwork.getNodesCount());
         System.out.println("Segments count: " + roadNetwork.getSegmentsCount());
-        FileHandler.saveToFile(roadNetwork, "./roadnetwork_sample.proto");
+        FileHandler.saveToFile(roadNetwork, ROAD_NETWORK_OUTPUT_PATH);
     }
 }
diff --git a/mapbuilder/src/main/java/map/builder/osm/OSMFetcher.java b/mapbuilder/src/main/java/map/builder/osm/OSMFetcher.java
index 8634ebb1a23fc7c12d9eb0edceccce7acb7c5e69..a867735a15176fdc919889f34986b5ea98e938f6 100644
--- a/mapbuilder/src/main/java/map/builder/osm/OSMFetcher.java
+++ b/mapbuilder/src/main/java/map/builder/osm/OSMFetcher.java
@@ -9,12 +9,22 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.URL;
-
-import org.json.JSONArray;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.stream.JsonReader;
+import map.builder.osm.json.model.OSMJsonDto;
+import map.builder.osm.json.serialization.OSMJsonDtoDeserializer;
 import org.json.JSONObject;
 
 import map.builder.utilities.BoundingBox;
 
+import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.NODES_AND_WAYS;
+import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.TURN_RESTRICTIONS;
+
 public class OSMFetcher {
     private final static String OverpassURL = "https://overpass.kumi.systems/api/interpreter";
     private final static String nodeQuery = "[out:json];way[highway](%s);(._;>;);out;";
@@ -23,20 +33,51 @@ public class OSMFetcher {
     private OSMFetcher() {
     }
 
-    public static JSONArray fetchTurnRestrictions(BoundingBox boundingBox) throws IOException {
-        return OSMFetcher.runQueryForBBox(OSMFetcher.relationQuery, boundingBox);
+    public static List<OSMJsonDto> fetchTurnRestrictions(BoundingBox boundingBox) throws IOException {
+        System.out.println("Start to fetch turn restrictions.");
+        List<OSMJsonDto>  dtos = OSMFetcher.runQueryForBBox(OSMFetcher.relationQuery, boundingBox, TURN_RESTRICTIONS);
+        System.out.println("Turn restrictions fetched.");
+
+        return dtos;
     }
 
-    public static JSONArray fetchNodesAndWays(BoundingBox boundingBox) throws IOException {
-        return OSMFetcher.runQueryForBBox(OSMFetcher.nodeQuery, boundingBox);
+    public static List<OSMJsonDto> fetchNodesAndWays(BoundingBox boundingBox) throws IOException {
+        System.out.println("Start to fetch nodes and ways.");
+        List<OSMJsonDto> dtos = OSMFetcher.runQueryForBBox(OSMFetcher.nodeQuery, boundingBox, NODES_AND_WAYS);
+        System.out.println("Nodes and ways fetched.");
+
+        return dtos;
     }
 
-    private static JSONArray runQueryForBBox(String query, BoundingBox bbox) throws IOException {
+    private static List<OSMJsonDto> runQueryForBBox(String query, BoundingBox bbox, OSMJsonDtoDeserializer.Mode mode) throws IOException {
         InputStream response = requestData(query, bbox);
-        
-        JSONObject parsedResponse = getJSONObjectFromStream(response);
 
-        return parsedResponse.getJSONArray("elements");
+        JsonReader jsonReader = new JsonReader(new InputStreamReader(response));
+        List<OSMJsonDto> dtos = new ArrayList<>();
+
+        Gson gson = new GsonBuilder()
+                .registerTypeAdapter(OSMJsonDto.class, new OSMJsonDtoDeserializer(mode))
+                .create();
+
+        jsonReader.beginObject();
+        String key;
+        while ((key = jsonReader.nextName()) != null) {
+            if (key.equals("elements")) {
+                jsonReader.beginArray();
+                while (jsonReader.hasNext()) {
+                    OSMJsonDto dto = gson.fromJson(jsonReader, OSMJsonDto.class);
+
+                    if (dto != null) {
+                        dtos.add(dto);
+                    }
+                }
+
+                break;
+            }
+            jsonReader.skipValue();
+        }
+
+        return dtos;
     }
 
     private static InputStream requestData(String query, BoundingBox bbox) throws IOException {
@@ -57,26 +98,17 @@ public class OSMFetcher {
         return connection.getInputStream();
     }
 
-    private static JSONObject getJSONObjectFromStream(InputStream stream) throws IOException {
-        BufferedReader rd = new BufferedReader(new InputStreamReader(stream));
-        StringBuilder response = new StringBuilder(); // or StringBuffer if Java version 5+
-        String line;
-
-        while ((line = rd.readLine()) != null) {
-
-            response.append(line);
-            response.append('\n');
-        }
-        rd.close();
-
-        return new JSONObject(response.toString());
-    }
-
-    public static void dumpJsonData(JSONArray data, String path) throws IOException {
+    public static void dumpJsonData(List<OSMJsonDto> data, String path) throws IOException {
         File yourFile = new File(path);
         yourFile.createNewFile();
         FileWriter file = new FileWriter(path);
-        file.write(data.toString());
+        file.write(
+                "[" +
+                data.stream()
+                        .map(OSMJsonDto::toJson)
+                        .collect(Collectors.joining(", "))
+                + "]"
+        );
         file.close();
     }
 }
diff --git a/mapbuilder/src/main/java/map/builder/osm/OSMJSONUtils.java b/mapbuilder/src/main/java/map/builder/osm/OSMJSONUtils.java
deleted file mode 100644
index d97dc679053260249c5f52552c663cfd854025d7..0000000000000000000000000000000000000000
--- a/mapbuilder/src/main/java/map/builder/osm/OSMJSONUtils.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package map.builder.osm;
-
-import org.json.JSONObject;
-
-import java.util.List;
-import java.util.Objects;
-
-public class OSMJSONUtils {
-    private OSMJSONUtils() {}
-
-    public static boolean isNode(JSONObject element) {
-        return Objects.equals(OSMJSONUtils.getType(element), "node");
-    }
-    public static boolean isWay(JSONObject element) {
-        return Objects.equals(OSMJSONUtils.getType(element), "way");
-    }
-    public static boolean isRelation(JSONObject element) {
-        return Objects.equals(OSMJSONUtils.getType(element), "relation");
-    }
-
-    public static boolean isTRFrom(JSONObject turnRestriction) {
-        return Objects.equals(OSMJSONUtils.getTRType(turnRestriction), "from");
-    }
-
-    public static boolean isTRTo(JSONObject turnRestriction) {
-        return Objects.equals(OSMJSONUtils.getTRType(turnRestriction), "to");
-    }
-
-    public static boolean isTRVia(JSONObject turnRestriction) {
-        return Objects.equals(OSMJSONUtils.getTRType(turnRestriction), "via");
-    }
-
-    public static String getType(JSONObject element) {
-        return element.getString(OSMKey.type.name());
-    }
-
-    public static String getTRType(JSONObject turnRestriction) {
-        return turnRestriction.getString(OSMKey.role.name());
-    }
-
-    public static boolean hasTag(JSONObject element, String tag) {
-        if (!element.has("tags")) {
-            return false;
-        }
-
-        JSONObject tags = element.getJSONObject("tags");
-
-        return tags.has(tag);
-    }
-
-    public static String getTag(JSONObject element, String tag) {
-        if (!OSMJSONUtils.hasTag(element, tag)) {
-            return null;
-        }
-
-        JSONObject tags = element.getJSONObject("tags");
-        return tags.getString(tag);
-    }
-
-    public static boolean isTagValueOneOf(JSONObject element, String tag, List<String> values) {
-        String tagValue = OSMJSONUtils.getTag(element, tag);
-
-        return values.contains(tagValue);
-    }
-
-    public static boolean isTagValueEqualTo(JSONObject element, String tag, String value) {
-        String tagValue = OSMJSONUtils.getTag(element, tag);
-
-        return Objects.equals(tagValue, value);
-    }
-}
diff --git a/mapbuilder/src/main/java/map/builder/osm/OSMJsonUtils.java b/mapbuilder/src/main/java/map/builder/osm/OSMJsonUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..56a94a9e722f59e87444ca295986923eb5042f78
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/OSMJsonUtils.java
@@ -0,0 +1,60 @@
+package map.builder.osm;
+
+import map.builder.osm.json.model.*;
+import org.json.JSONObject;
+
+import java.util.List;
+import java.util.Objects;
+
+public class OSMJsonUtils {
+    private OSMJsonUtils() {}
+
+    public static boolean isNode(OSMJsonDto dto) {
+        return Objects.equals(OSMJsonUtils.getType(dto), "node") && dto instanceof OSMJsonNodeDto;
+    }
+    public static boolean isWay(OSMJsonDto dto) {
+        return Objects.equals(OSMJsonUtils.getType(dto), "way") && dto instanceof OSMJsonWayDto;
+    }
+    public static boolean isRelation(OSMJsonDto dto) {
+        return Objects.equals(OSMJsonUtils.getType(dto), "relation") && dto instanceof OSMJsonTurnRestrictionDto;
+    }
+
+    public static boolean isTRFrom(OSMJsonMemberDto dto) {
+        return Objects.equals(OSMJsonUtils.getTRType(dto), "from");
+    }
+
+    public static boolean isTRTo(OSMJsonMemberDto dto) {
+        return Objects.equals(OSMJsonUtils.getTRType(dto), "to");
+    }
+
+    public static boolean isTRVia(OSMJsonMemberDto dto) {
+        return Objects.equals(OSMJsonUtils.getTRType(dto), "via");
+    }
+
+    public static String getType(OSMJsonDto dto) {
+        return dto.getType();
+    }
+
+    public static String getTRType(OSMJsonMemberDto dto) {
+        return dto.getRole();
+    }
+
+    public static boolean hasTag(OSMJsonWayDto dto, String tag) {
+        return getTag(dto, tag) != null;
+    }
+
+    public static String getTag(OSMJsonWayDto dto, String tag) {
+        return switch (tag) {
+            case "highway" -> dto.getHighway();
+            case "junction" -> dto.getJunction();
+
+            default -> null;
+        };
+    }
+
+    public static boolean isTagValueEqualTo(OSMJsonWayDto dto, String tag, String value) {
+        String tagValue = getTag(dto, tag);
+
+        return Objects.equals(tagValue, value);
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/OSMKey.java b/mapbuilder/src/main/java/map/builder/osm/OSMKey.java
deleted file mode 100644
index 352c9c3f908831f6a00e16133cadcba9f6408df0..0000000000000000000000000000000000000000
--- a/mapbuilder/src/main/java/map/builder/osm/OSMKey.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package map.builder.osm;
-
-public enum OSMKey {
-    type, tags, nodes, id, uid, lon, lat, element, role, members, ref
-}
diff --git a/mapbuilder/src/main/java/map/builder/osm/OSMParser.java b/mapbuilder/src/main/java/map/builder/osm/OSMParser.java
index 9621b071513ce7b42900638531a4f7ca8e27e0f1..b8bc958a985d8bc8e1277d8c0b9c84efaf76a7e6 100644
--- a/mapbuilder/src/main/java/map/builder/osm/OSMParser.java
+++ b/mapbuilder/src/main/java/map/builder/osm/OSMParser.java
@@ -2,14 +2,17 @@ package map.builder.osm;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
+import java.util.List;
 
 import de.fuberlin.navigator.protos.map_builder.Coordinates;
 import de.fuberlin.navigator.protos.map_builder.Node;
 import de.fuberlin.navigator.protos.map_builder.Restriction;
 import de.fuberlin.navigator.protos.map_builder.Segment;
+import map.builder.osm.json.model.OSMJsonDto;
+import map.builder.osm.json.model.OSMJsonMemberDto;
+import map.builder.osm.json.model.OSMJsonNodeDto;
+import map.builder.osm.json.model.OSMJsonTurnRestrictionDto;
+import map.builder.osm.json.model.OSMJsonWayDto;
 import map.builder.utilities.ComputationalUtils;
 
 public class OSMParser {
@@ -27,34 +30,36 @@ public class OSMParser {
         this.nodesDump = new HashMap<>();
     }
 
-    public void parseRoads(JSONArray elements) {
-        for (int i = 0; i < elements.length(); i++) {
-            JSONObject element = elements.getJSONObject(i);
-
-            if (OSMJSONUtils.isNode(element)) {
-                this.createNode(element);
+    public void parseRoads(List<OSMJsonDto> elements) {
+        for (OSMJsonDto dto : elements) {
+            if (OSMJsonUtils.isNode(dto)) {
+                this.createNode((OSMJsonNodeDto) dto);
             }
         }
 
-        for (int i = 0; i < elements.length(); i++) {
-            JSONObject element = elements.getJSONObject(i);
-            if (OSMJSONUtils.isWay(element) && SegmentUtils.isSegmentDrivable(element)) {
-                SegmentUtils.markEndNodes(element);
+        for (OSMJsonDto dto : elements) {
+            if (OSMJsonUtils.isWay(dto)) {
+                OSMJsonWayDto wayDto = (OSMJsonWayDto) dto;
+                if (SegmentUtils.isSegmentDrivable(wayDto)) {
+                    SegmentUtils.markEndNodes(wayDto);
+                }
             }
         }
 
-        for (int i = 0; i < elements.length(); i++) {
-            JSONObject element = elements.getJSONObject(i);
-            if (OSMJSONUtils.isWay(element) && SegmentUtils.isSegmentDrivable(element)) {
-                this.splitSegment(element);
+        for (OSMJsonDto dto : elements) {
+            if (OSMJsonUtils.isWay(dto)) {
+                OSMJsonWayDto wayDto = (OSMJsonWayDto) dto;
+                if (SegmentUtils.isSegmentDrivable(wayDto)) {
+                    this.splitSegment(wayDto);
+                }
             }
         }
 
     }
 
-    private void splitSegment(JSONObject element) {
-        JSONArray nodes = element.getJSONArray(OSMKey.nodes.name());
-        long osmId = element.getLong(OSMKey.id.name());
+    private void splitSegment(OSMJsonWayDto dto) {
+        long[] nodes = dto.getNodes();
+        long osmId = dto.getOsmId();
 
         ArrayList<ArrayList<Long>> geometry = SegmentUtils.splitGeometry(nodes);
 
@@ -63,12 +68,12 @@ public class OSMParser {
         }
 
         for (int i = 0; i < geometry.size(); i++) {
-            this.createSegment(element, geometry.get(i));
+            this.createSegment(dto, geometry.get(i));
         }
     }
 
-    private void createSegment(JSONObject element, ArrayList<Long> geometry) {
-        long osmId = element.getLong(OSMKey.id.name());
+    private void createSegment(OSMJsonWayDto dto, ArrayList<Long> geometry) {
+        long osmId = dto.getOsmId();
         ArrayList<Coordinates> line = null;
 
         try {
@@ -82,8 +87,8 @@ public class OSMParser {
         long startNodeId = geometry.get(0);
         long endNodeId = geometry.get(geometry.size() - 1);
 
-        boolean oneWay = this.isOneWay(element);
-        int maxSpeed = SegmentUtils.getMaxSpeed(element);
+        boolean oneWay = SegmentUtils.isSegmentOneway(dto);
+        int maxSpeed = SegmentUtils.getMaxSpeed(dto);
 
         System.out.printf("Max speed: %d \n", maxSpeed);
         System.out.printf("Way id: %d, Start node id : %d, End node id: %d \n", osmId,
@@ -98,7 +103,7 @@ public class OSMParser {
                 .setOneWay(oneWay)
                 .setMaxSpeed(maxSpeed)
                 .setId(internalId)
-                .setCategory(SegmentUtils.parseRoadType(element))
+                .setCategory(SegmentUtils.parseRoadType(dto))
                 .setStartNode(startNodeId)
                 .setEndNode(endNodeId)
                 .setLength(this.computeSegmentLength(line))
@@ -107,28 +112,21 @@ public class OSMParser {
         this.segments.put(internalId, segment);
     }
 
-    private boolean isOneWay(JSONObject element) {
-        return OSMJSONUtils.isTagValueEqualTo(element, "oneway", "yes") ||
-                OSMJSONUtils.isTagValueEqualTo(element, "highway", "motorway") ||
-                OSMJSONUtils.isTagValueEqualTo(element, "junction", "roundabout");
-    }
-
     private void moveNodeToProto(Node node) {
         long osmId = node.getOsmId();
         this.nodes.put(osmId, node);
     }
 
-    private void createNode(JSONObject element) {
-        Coordinates position = this.createLocationFromElement(element);
-        long osmId = element.getLong(OSMKey.id.name());
+    private void createNode(OSMJsonNodeDto dto) {
+        Coordinates position = this.createLocationFromElement(dto.getLon(), dto.getLat());
 
         Node node = Node.newBuilder()
                 .setId(this.nodes.size() + this.nodesDump.size())
-                .setOsmId(osmId)
+                .setOsmId(dto.getOsmId())
                 .setPosition(position)
                 .build();
 
-        this.nodesDump.put(osmId, node);
+        this.nodesDump.put(dto.getOsmId(), node);
     }
 
     private double computeSegmentLength(ArrayList<Coordinates> line) {
@@ -165,6 +163,7 @@ public class OSMParser {
             }
 
             if (i == 0 || i == nodeIds.size() - 1) {
+
                 // if it is the first or last node, we need to save it to the proto
                 moveNodeToProto(currentNode);
             }
@@ -190,18 +189,17 @@ public class OSMParser {
         throw new NullPointerException("Node with id " + osmId + " not found!");
     }
 
-    private Coordinates createLocationFromElement(JSONObject element) {
+    private Coordinates createLocationFromElement(float lon, float lat) {
         return coordinatesBuilder
-                .setLon(element.getFloat(OSMKey.lon.name()))
-                .setLat(element.getFloat(OSMKey.lat.name()))
+                .setLon(lon)
+                .setLat(lat)
                 .build();
     }
 
-    public void parseTurnRestrictions(JSONArray elements) {
-        for (int i = 0; i < elements.length(); i++) {
-            JSONObject element = elements.getJSONObject(i);
-            if (OSMJSONUtils.isRelation(element)) {
-                JSONArray members = element.getJSONArray(OSMKey.members.name());
+    public void parseTurnRestrictions(List<OSMJsonDto> elements) {
+        for (OSMJsonDto dto : elements) {
+            if (OSMJsonUtils.isRelation(dto)) {
+                OSMJsonMemberDto[] members = ((OSMJsonTurnRestrictionDto) dto).getMembers();
                 if (!hasWayVia(members)) {
                     parseFromTo(members);
                 }
@@ -209,17 +207,16 @@ public class OSMParser {
         }
     }
 
-    private void parseFromTo(JSONArray elements) {
-        if (!hasWayVia(elements)) {
+    private void parseFromTo(OSMJsonMemberDto[] members) {
+        if (!hasWayVia(members)) {
             int from = 0;
             int to = 0;
-            for (int i = 0; i < elements.length(); i++) {
-                JSONObject element = elements.getJSONObject(i);
-                if (OSMJSONUtils.isTRFrom(element)) {
-                    from = element.getInt(OSMKey.ref.name());
+            for (OSMJsonMemberDto member : members) {
+                if (OSMJsonUtils.isTRFrom(member)) {
+                    from = (int) member.getOsmId();
                 }
-                if (OSMJSONUtils.isTRTo(element)) {
-                    to = element.getInt(OSMKey.ref.name());
+                if (OSMJsonUtils.isTRTo(member)) {
+                    to = (int) member.getOsmId();
                 }
             }
             Restriction restriction = Restriction.newBuilder().setFromId(from).setToId(to).build();
@@ -227,14 +224,13 @@ public class OSMParser {
         }
     }
 
-    private boolean hasWayVia(JSONArray members) {
-        if (members.length() < 3) {
+    private boolean hasWayVia(OSMJsonMemberDto[] members) {
+        if (members.length < 3) {
             return false;
         }
-        for (int i = 0; i < members.length(); i++) {
-            JSONObject element = members.getJSONObject(i);
-            if (OSMJSONUtils.isTRVia(element)) {
-                if (OSMJSONUtils.isWay(element)) {
+        for (OSMJsonMemberDto member : members) {
+            if (OSMJsonUtils.isTRVia(member)) {
+                if (OSMJsonUtils.isWay(member)) {
                     return true;
                 }
                 return false;
diff --git a/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java b/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java
index f328df785a570d8d983542f47d5ab8b55cc677cf..98ad594dd91291e0dc93e962f1faf1943aacdf99 100644
--- a/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java
+++ b/mapbuilder/src/main/java/map/builder/osm/SegmentUtils.java
@@ -1,17 +1,13 @@
 package map.builder.osm;
 
 import de.fuberlin.navigator.protos.map_builder.RoadCategory;
-import org.json.JSONObject;
-import org.json.JSONArray;
-
-import java.util.HashMap;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import map.builder.osm.json.model.OSMJsonWayDto;
+
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static de.fuberlin.navigator.protos.map_builder.RoadCategory.*;
 
 public class SegmentUtils {
     // this is a hash-map to allow us to check if a node is a start/end node in linear time
@@ -37,21 +33,33 @@ public class SegmentUtils {
     private static final Map<RoadCategory, Integer> speedMap = Map.ofEntries(
             Map.entry(RoadCategory.ROAD_CATEGORY_HIGHWAY, 120),
             Map.entry(RoadCategory.ROAD_CATEGORY_MAIN, 90),
-            Map.entry(RoadCategory.ROAD_CATEGORY_LOCAL, 50),
-            Map.entry(RoadCategory.ROAD_CATEGORY_RESIDENTIAL, 30),
-            Map.entry(RoadCategory.ROAD_CATEGORY_INVALID, 0));
-    private static final Pattern patternMaxSpeed = Pattern
-            .compile("^([0-9][\\.0-9]+?)(?:[ ]?(?:km/h|kmh|kph|mph|knots))?$");
-
-    public static boolean isSegmentDrivable(JSONObject element) {
-        return OSMJSONUtils.isTagValueOneOf(element, "highway", drivableRoads);
+            Map.entry(ROAD_CATEGORY_LOCAL, 50),
+            Map.entry(ROAD_CATEGORY_RESIDENTIAL, 30),
+            Map.entry(ROAD_CATEGORY_INVALID, 0)
+    );
+    private static final Pattern patternMaxSpeed = Pattern.compile("^([0-9][\\.0-9]+?)(?:[ ]?(?:km/h|kmh|kph|mph|knots))?$");
+
+    public static boolean isSegmentDrivable(OSMJsonWayDto dto) {
+        if (dto.getHighway() == null) {
+            return false;
+        }
+
+        return drivableRoads.contains(dto.getHighway());
     }
 
-    public static RoadCategory parseRoadType(JSONObject element) {
-        String roadTypeTag = OSMJSONUtils.getTag(element, OSMTag.highway.name());
+    public static boolean isSegmentOneway(OSMJsonWayDto dto) {
+        return dto.isOneway()
+                || OSMJsonUtils.isTagValueEqualTo(dto, "highway", "motorway")
+                || OSMJsonUtils.isTagValueEqualTo(dto, "junction", "roundabout");
+    }
 
-        return switch (roadTypeTag) {
-            case "motorway", "highway" -> RoadCategory.ROAD_CATEGORY_HIGHWAY;
+    public static RoadCategory parseRoadType(OSMJsonWayDto dto) {
+        if (dto.getHighway() == null) {
+            return ROAD_CATEGORY_INVALID;
+        }
+
+        return switch (dto.getHighway()) {
+            case "motorway", "highway" -> ROAD_CATEGORY_HIGHWAY;
             case "trunk", "primary", "secondary", "motorway_link", "trunk_link", "primary_link", "secondary_link" ->
                 RoadCategory.ROAD_CATEGORY_MAIN;
             case "unclassified", "tertiary", "tertiary_link", "track", "road" ->
@@ -61,13 +69,11 @@ public class SegmentUtils {
         };
     }
 
-    public static int getMaxSpeed(JSONObject element) {
-        String maxSpeedTag = OSMTag.maxspeed.name();
+    public static int getMaxSpeed(OSMJsonWayDto dto) {
 
         // if there's a max speed tag, use it
-        if (OSMJSONUtils.hasTag(element, maxSpeedTag)) {
-            String maxspeed = OSMJSONUtils.getTag(element, maxSpeedTag);
-            Matcher matcherMaxSpeed = SegmentUtils.patternMaxSpeed.matcher(maxspeed);
+        if (dto.getMaxspeed() != null) {
+            Matcher matcherMaxSpeed = SegmentUtils.patternMaxSpeed.matcher(dto.getMaxspeed());
 
             if (matcherMaxSpeed.find()) {
                 return Integer.parseInt(matcherMaxSpeed.group(1));
@@ -75,15 +81,15 @@ public class SegmentUtils {
         }
 
         // if no tag is available, parse the max speed based on road category
-        RoadCategory roadCategory = SegmentUtils.parseRoadType(element);
+        RoadCategory roadCategory = SegmentUtils.parseRoadType(dto);
         return SegmentUtils.speedMap.get(roadCategory);
     }
 
-    public static void markEndNodes(JSONObject element) {
-        JSONArray nodes = element.getJSONArray(OSMKey.nodes.name());
+    public static void markEndNodes(OSMJsonWayDto element) {
+        long[] nodes = element.getNodes();
 
-        long startNodeId = nodes.getLong(0);
-        long endNodeId = nodes.getLong(nodes.length() - 1);
+        long startNodeId = nodes[0];
+        long endNodeId = nodes[nodes.length - 1];
 
         System.out.println("marking " + startNodeId + " and " + endNodeId);
 
@@ -91,23 +97,17 @@ public class SegmentUtils {
         SegmentUtils.endNodes.put(endNodeId, true);
     }
 
-    public static boolean isNodeAnEndNode(JSONObject element) {
-        long osmId = element.getLong(OSMKey.id.name());
-
-        return isNodeAnEndNode(osmId);
-    }
-
     public static boolean isNodeAnEndNode(long osmId) {
         return SegmentUtils.endNodes.containsKey(osmId);
     }
 
-    public static ArrayList<ArrayList<Long>> splitGeometry(JSONArray nodes) {
+    public static ArrayList<ArrayList<Long>> splitGeometry(long[] nodes) {
         ArrayList<ArrayList<Long>> geometry = new ArrayList<>();
 
         int from = -1;
 
-        for (int i = 0; i<nodes.length(); i++) {
-            long nodeId = nodes.getLong(i);
+        for (int i = 0; i < nodes.length; i++) {
+            long nodeId = nodes[i];
 
             if (isNodeAnEndNode(nodeId)) {
                 if (from == -1) {
@@ -130,14 +130,14 @@ public class SegmentUtils {
         return geometry;
     }
 
-    private static ArrayList<Long> extractIdsFromTo(JSONArray nodes, int from, int to) {
+    private static ArrayList<Long> extractIdsFromTo(long[] nodes, int from, int to) {
         ArrayList<Long> extractedIds = new ArrayList<>();
 
-        for (int i = from; i<=to; i++) {
-            long nodeId = nodes.getLong(i);
+        for (int i = from; i <= to; i++) {
+            long nodeId = nodes[i];
             extractedIds.add(nodeId);
         }
 
         return extractedIds;
     }
-}
+}
\ No newline at end of file
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonDto.java b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..676fe51bc7fd8491727fdf647f18b98515aeba78
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonDto.java
@@ -0,0 +1,16 @@
+package map.builder.osm.json.model;
+
+public abstract class OSMJsonDto {
+
+    protected String type;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public abstract String toJson();
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonMemberDto.java b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonMemberDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ce8930b92ffba462e945edde8389fff9eb86209
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonMemberDto.java
@@ -0,0 +1,39 @@
+package map.builder.osm.json.model;
+
+public class OSMJsonMemberDto extends OSMJsonDto {
+
+    private String type;
+    private String role;
+    private long osmId;
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public long getOsmId() {
+        return osmId;
+    }
+
+    public void setOsmId(long osmId) {
+        this.osmId = osmId;
+    }
+
+    @Override
+    public String toJson() {
+        return "{ type: " + type + ", role: " + role + ", osmId:" + osmId + " }";
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonNodeDto.java b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonNodeDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a9b99c2d03915cbddfa74fe7bc3010f94771f01
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonNodeDto.java
@@ -0,0 +1,41 @@
+package map.builder.osm.json.model;
+
+public class OSMJsonNodeDto extends OSMJsonDto {
+
+    private long osmId;
+    private float lon;
+    private float lat;
+
+    public OSMJsonNodeDto() {
+        this.type = "node";
+    }
+
+    public long getOsmId() {
+        return osmId;
+    }
+
+    public void setOsmId(long osmId) {
+        this.osmId = osmId;
+    }
+
+    public float getLon() {
+        return lon;
+    }
+
+    public void setLon(float lon) {
+        this.lon = lon;
+    }
+
+    public float getLat() {
+        return lat;
+    }
+
+    public void setLat(float lat) {
+        this.lat = lat;
+    }
+
+    @Override
+    public String toJson() {
+        return "{ type: node, osmId: " + osmId + ", lon: " + lon + ", lat: " + lat + " }";
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonTurnRestrictionDto.java b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonTurnRestrictionDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..6289df4ab13856d63d8c1422a487bb16db987383
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonTurnRestrictionDto.java
@@ -0,0 +1,30 @@
+package map.builder.osm.json.model;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+public class OSMJsonTurnRestrictionDto extends OSMJsonDto {
+
+    private OSMJsonMemberDto[] members;
+
+    public OSMJsonTurnRestrictionDto() {
+        this.type = "relation";
+    }
+
+    public OSMJsonMemberDto[] getMembers() {
+        return members;
+    }
+
+    public void setMembers(OSMJsonMemberDto[] members) {
+        this.members = members;
+    }
+
+    @Override
+    public String toJson() {
+        String members = Arrays.asList(getMembers())
+                .stream()
+                .map(OSMJsonMemberDto::toJson)
+                .collect(Collectors.joining(", "));
+        return "{ type: relation, members: " + members + " }";
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonWayDto.java b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonWayDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a750400a872cf0b0dd85ba47f61b17d7b8fda0c
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/model/OSMJsonWayDto.java
@@ -0,0 +1,75 @@
+package map.builder.osm.json.model;
+
+public class OSMJsonWayDto extends OSMJsonDto {
+
+    private long[] nodes;
+    private long osmId;
+
+    private String highway;
+    private boolean oneway;
+    private String junction;
+    private String maxspeed;
+
+    public OSMJsonWayDto() {
+        this.type = "way";
+    }
+
+    public long[] getNodes() {
+        return nodes;
+    }
+
+    public void setNodes(long[] nodes) {
+        this.nodes = nodes;
+    }
+
+    public long getOsmId() {
+        return osmId;
+    }
+
+    public void setOsmId(long osmId) {
+        this.osmId = osmId;
+    }
+
+    public String getHighway() {
+        return highway;
+    }
+
+    public void setHighway(String highway) {
+        this.highway = highway;
+    }
+
+    public boolean isOneway() {
+        return oneway;
+    }
+
+    public void setOneway(boolean oneway) {
+        this.oneway = oneway;
+    }
+
+    public String getJunction() {
+        return junction;
+    }
+
+    public void setJunction(String junction) {
+        this.junction = junction;
+    }
+
+    public String getMaxspeed() {
+        return maxspeed;
+    }
+
+    public void setMaxspeed(String maxspeed) {
+        this.maxspeed = maxspeed;
+    }
+
+    @Override
+    public String toJson() {
+        String nodes = "";
+        for (long node : this.nodes) {
+            nodes = nodes + node + ",";
+        }
+
+        return "{ type: way, nodes: [" + nodes + "], osmId: " + osmId + ", highway: " + highway + ", oneway: " + oneway + ", junction: "
+                + junction + ", maxspeed: " + maxspeed + "}";
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonDtoDeserializer.java b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonDtoDeserializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5dd1986113f267a55baf465c911a50cebb0ae59
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonDtoDeserializer.java
@@ -0,0 +1,33 @@
+package map.builder.osm.json.serialization;
+
+import com.google.gson.*;
+import map.builder.osm.json.model.OSMJsonDto;
+
+import java.lang.reflect.Type;
+
+public class OSMJsonDtoDeserializer implements JsonDeserializer<OSMJsonDto> {
+
+    public enum Mode {
+        TURN_RESTRICTIONS, NODES_AND_WAYS;
+    }
+
+    private Mode mode;
+
+    public OSMJsonDtoDeserializer(Mode mode) {
+        this.mode = mode;
+    }
+
+    @Override
+    public OSMJsonDto deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
+        JsonObject object = jsonElement.getAsJsonObject();
+        OSMJsonDto dto = switch (object.get("type").getAsString()) {
+            case "relation" -> new OSMJsonTurnRestrictionDtoDeserializer().deserialize(object, mode);
+            case "node"     -> new OSMJsonNodeDtoDeserializer().deserialize(object, mode);
+            case "way"      -> new OSMJsonWayDtoDeserializer().deserialize(object, mode);
+
+            default -> null;
+        };
+
+        return dto;
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonNodeDtoDeserializer.java b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonNodeDtoDeserializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..3dcb25dc079e4aa8fb3b9cea29184ba8b27378f2
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonNodeDtoDeserializer.java
@@ -0,0 +1,27 @@
+package map.builder.osm.json.serialization;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import map.builder.osm.json.model.OSMJsonNodeDto;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.NODES_AND_WAYS;
+
+public class OSMJsonNodeDtoDeserializer {
+
+    public OSMJsonNodeDto deserialize(JsonObject obj, OSMJsonDtoDeserializer.Mode mode) throws JsonParseException {
+        if (!mode.equals(NODES_AND_WAYS)) {
+            return null;
+        }
+
+        OSMJsonNodeDto dto = new OSMJsonNodeDto();
+        dto.setOsmId(obj.get("id").getAsLong());
+        dto.setLat(obj.get("lat").getAsFloat());
+        dto.setLon(obj.get("lon").getAsFloat());
+
+        return dto;
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonTurnRestrictionDtoDeserializer.java b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonTurnRestrictionDtoDeserializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..17e6e48e8e14c0605b59cd93de7317cb800f2579
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonTurnRestrictionDtoDeserializer.java
@@ -0,0 +1,43 @@
+package map.builder.osm.json.serialization;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import map.builder.osm.json.model.OSMJsonMemberDto;
+import map.builder.osm.json.model.OSMJsonTurnRestrictionDto;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.TURN_RESTRICTIONS;
+
+public  class OSMJsonTurnRestrictionDtoDeserializer {
+
+    public OSMJsonTurnRestrictionDto deserialize(JsonObject obj, OSMJsonDtoDeserializer.Mode mode) throws JsonParseException {
+        if (!mode.equals(TURN_RESTRICTIONS)) {
+            return null;
+        }
+
+        OSMJsonTurnRestrictionDto dto = new OSMJsonTurnRestrictionDto();
+        setMembers(obj.getAsJsonArray("members"), dto);
+
+        return dto;
+    }
+
+    public void setMembers(JsonArray elements, OSMJsonTurnRestrictionDto dto) {
+        OSMJsonMemberDto[] members = new OSMJsonMemberDto[elements.size()];
+        for (int i = 0; i < elements.size(); i++) {
+            JsonObject obj = elements.get(i).getAsJsonObject();
+
+            OSMJsonMemberDto member = new OSMJsonMemberDto();
+            member.setType(obj.get("type").getAsString());
+            member.setRole(obj.get("role").getAsString());
+            member.setOsmId(obj.get("ref").getAsLong());
+
+            members[i] = member;
+        }
+
+        dto.setMembers(members);
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonWayDtoDeserializer.java b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonWayDtoDeserializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..f384d169d95c5fa4200c5f066ca6fe7a9fbfbaa7
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/osm/json/serialization/OSMJsonWayDtoDeserializer.java
@@ -0,0 +1,50 @@
+package map.builder.osm.json.serialization;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import map.builder.osm.json.model.OSMJsonWayDto;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static map.builder.osm.json.serialization.OSMJsonDtoDeserializer.Mode.NODES_AND_WAYS;
+
+public class OSMJsonWayDtoDeserializer {
+
+    public OSMJsonWayDto deserialize(JsonObject obj, OSMJsonDtoDeserializer.Mode mode) throws JsonParseException {
+        if (!mode.equals(NODES_AND_WAYS)) {
+            return null;
+        }
+
+        OSMJsonWayDto dto = new OSMJsonWayDto();
+        dto.setOsmId(obj.get("id").getAsLong());
+        setNodes(obj.getAsJsonArray("nodes"), dto);
+        resolveTags(obj.getAsJsonObject("tags"), dto);
+
+        return dto;
+    }
+
+    private void setNodes(JsonArray arr, OSMJsonWayDto dto) {
+        long[] nodes = new long[arr.size()];
+        for (int i = 0; i < arr.size(); i++) {
+            nodes[i] = arr.get(i).getAsLong();
+        }
+
+        dto.setNodes(nodes);
+    }
+
+    private void resolveTags(JsonObject obj, OSMJsonWayDto dto) {
+        Iterator<Map.Entry<String, JsonElement>> iterator = obj.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<String, JsonElement> entry = iterator.next();
+            switch (entry.getKey()) {
+                case "highway" -> dto.setHighway(entry.getValue().getAsString());
+                case "oneway" -> dto.setOneway(entry.getValue().getAsString().equals("yes"));
+                case "junction" -> dto.setJunction(entry.getValue().getAsString());
+                case "maxspeed" -> dto.setMaxspeed(entry.getValue().getAsString());
+            }
+        }
+    }
+}
diff --git a/mapbuilder/src/main/java/map/builder/utilities/Config.java b/mapbuilder/src/main/java/map/builder/utilities/Config.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8bfe433f1c99260abbdfff19a81d4b72f0d353b
--- /dev/null
+++ b/mapbuilder/src/main/java/map/builder/utilities/Config.java
@@ -0,0 +1,37 @@
+package map.builder.utilities;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Properties;
+
+public class Config {
+
+    private Config() {
+    }
+
+    private static Properties props = new Properties();
+
+    public static String ROAD_NETWORK_OUTPUT_PATH = "roadnetwork.proto";
+
+    public static void load() {
+        //The config is used for running the application in a Docker container
+        String configFilePath = "/data/configuration/config.properties";
+
+        try (FileInputStream is = new FileInputStream(configFilePath)){
+            props.load(is);
+
+            ROAD_NETWORK_OUTPUT_PATH = props.getProperty("ROAD_NETWORK_OUTPUT_PATH", ROAD_NETWORK_OUTPUT_PATH);
+            System.out.println("Config loaded.");
+        } catch (FileNotFoundException e) {
+            // Either way the Docker image was build wrong or this is not
+            // run in a Docker environment
+            System.out.println("No config file found. Using default settings!");
+        } catch (IOException e) {
+            // Something else went wrong, but we will
+            // not let this escalate
+            e.printStackTrace();
+        }
+
+    }
+}
diff --git a/mapbuilder/src/main/resources/config.properties b/mapbuilder/src/main/resources/config.properties
new file mode 100644
index 0000000000000000000000000000000000000000..639d82dd25eeb130babc43a9f4e0bc455c39cdcd
--- /dev/null
+++ b/mapbuilder/src/main/resources/config.properties
@@ -0,0 +1,2 @@
+# Standard config for Docker
+ROAD_NETWORK_OUTPUT_PATH = /data/road_network/roadnetwork.proto
\ No newline at end of file