[analysis_server]/[analyzer_plugin] Make all toJson/fromJson methods go through a central converstion for Path<->URI Strings

This change shouldn't change any current behaviour, but means all "FilePath" types in the legacy protocol spec will go through a (currently no-op) conversion. The server will be able to replace this conversion based on client capabilities in a future CL.

Because a lot of the generated classes are in analyzer_plugin, this also moves the ClientUriConverter class there.

`pkg\analysis_server\test\src\utilities\json_test.dart` contains tests that the toJson/fromJson methods go through the converter recursively (inc. map keys/values/etc.).

Change-Id: If5aec884070128eea594540fd25a9017ada86079
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349060
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index 3f2fada..82197fa 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -10,6 +10,8 @@
 
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/src/protocol/protocol_internal.dart';
+import 'package:analyzer_plugin/src/protocol/protocol_internal.dart'
+    show clientUriConverter;
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 
 /// analysis.analyzedFiles params
@@ -31,8 +33,11 @@
     if (json is Map) {
       List<String> directories;
       if (json.containsKey('directories')) {
-        directories = jsonDecoder.decodeList('$jsonPath.directories',
-            json['directories'], jsonDecoder.decodeString);
+        directories = jsonDecoder.decodeList(
+            '$jsonPath.directories',
+            json['directories'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'directories');
       }
@@ -52,7 +57,9 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['directories'] = directories;
+    result['directories'] = directories
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -105,7 +112,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -135,7 +143,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['labels'] =
         labels.map((ClosingLabel value) => value.toJson()).toList();
     return result;
@@ -262,7 +270,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -290,7 +299,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['errors'] =
         errors.map((AnalysisError value) => value.toJson()).toList();
     return result;
@@ -340,7 +349,10 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files',
+            json['files'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -360,7 +372,9 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['files'] = files;
+    result['files'] = files
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -406,7 +420,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -434,7 +449,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['regions'] =
         regions.map((FoldingRegion value) => value.toJson()).toList();
     return result;
@@ -483,7 +498,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -501,7 +517,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     return result;
   }
 
@@ -617,7 +633,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -641,7 +658,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     return result;
   }
@@ -769,7 +786,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -800,7 +818,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     return result;
@@ -949,7 +967,10 @@
       List<String> libraries;
       if (json.containsKey('libraries')) {
         libraries = jsonDecoder.decodeList(
-            '$jsonPath.libraries', json['libraries'], jsonDecoder.decodeString);
+            '$jsonPath.libraries',
+            json['libraries'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'libraries');
       }
@@ -959,8 +980,14 @@
             '$jsonPath.packageMap', json['packageMap'],
             valueDecoder: (String jsonPath, Object? json) =>
                 jsonDecoder.decodeMap(jsonPath, json,
-                    valueDecoder: (String jsonPath, Object? json) => jsonDecoder
-                        .decodeList(jsonPath, json, jsonDecoder.decodeString)));
+                    valueDecoder: (String jsonPath, Object? json) =>
+                        jsonDecoder.decodeList(
+                            jsonPath,
+                            json,
+                            (String jsonPath, Object? json) =>
+                                clientUriConverter.fromClientFilePath(
+                                    jsonDecoder.decodeString(
+                                        jsonPath, json)))));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'packageMap');
       }
@@ -981,8 +1008,15 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['libraries'] = libraries;
-    result['packageMap'] = packageMap;
+    result['libraries'] = libraries
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
+    result['packageMap'] = mapMap(packageMap,
+        valueCallback: (Map<String, List<String>> value) => mapMap(value,
+            valueCallback: (List<String> value) => value
+                .map((String value) =>
+                    clientUriConverter.toClientFilePath(value))
+                .toList()));
     return result;
   }
 
@@ -1048,7 +1082,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1079,7 +1114,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     return result;
@@ -1141,7 +1176,10 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files',
+            json['files'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -1182,7 +1220,9 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['files'] = files;
+    result['files'] = files
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     result['targets'] =
         targets.map((NavigationTarget value) => value.toJson()).toList();
     result['regions'] =
@@ -1237,7 +1277,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1256,7 +1297,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     return result;
   }
 
@@ -1379,7 +1420,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1404,7 +1446,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     return result;
   }
@@ -1564,7 +1606,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1592,7 +1635,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['regions'] =
         regions.map((HighlightRegion value) => value.toJson()).toList();
     return result;
@@ -1649,7 +1692,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1688,7 +1732,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['classes'] =
         classes.map((ImplementedClass value) => value.toJson()).toList();
     result['members'] =
@@ -1756,7 +1800,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1792,7 +1837,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     result['delta'] = delta;
@@ -1865,7 +1910,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -1892,7 +1938,10 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files',
+            json['files'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -1910,12 +1959,14 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['regions'] =
         regions.map((NavigationRegion value) => value.toJson()).toList();
     result['targets'] =
         targets.map((NavigationTarget value) => value.toJson()).toList();
-    result['files'] = files;
+    result['files'] = files
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -1971,7 +2022,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -2000,7 +2052,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['occurrences'] =
         occurrences.map((Occurrences value) => value.toJson()).toList();
     return result;
@@ -2239,7 +2291,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -2276,7 +2329,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['kind'] = kind.toJson();
     var libraryName = this.libraryName;
     if (libraryName != null) {
@@ -2336,7 +2389,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -2364,7 +2418,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['overrides'] =
         overrides.map((Override value) => value.toJson()).toList();
     return result;
@@ -2570,14 +2624,20 @@
       List<String> included;
       if (json.containsKey('included')) {
         included = jsonDecoder.decodeList(
-            '$jsonPath.included', json['included'], jsonDecoder.decodeString);
+            '$jsonPath.included',
+            json['included'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'included');
       }
       List<String> excluded;
       if (json.containsKey('excluded')) {
         excluded = jsonDecoder.decodeList(
-            '$jsonPath.excluded', json['excluded'], jsonDecoder.decodeString);
+            '$jsonPath.excluded',
+            json['excluded'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'excluded');
       }
@@ -2585,7 +2645,10 @@
       if (json.containsKey('packageRoots')) {
         packageRoots = jsonDecoder.decodeMap(
             '$jsonPath.packageRoots', json['packageRoots'],
-            valueDecoder: jsonDecoder.decodeString);
+            keyDecoder: (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)),
+            valueDecoder: (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       }
       return AnalysisSetAnalysisRootsParams(included, excluded,
           packageRoots: packageRoots);
@@ -2603,11 +2666,19 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['included'] = included;
-    result['excluded'] = excluded;
+    result['included'] = included
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
+    result['excluded'] = excluded
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     var packageRoots = this.packageRoots;
     if (packageRoots != null) {
-      result['packageRoots'] = packageRoots;
+      result['packageRoots'] = mapMap(packageRoots,
+          keyCallback: (String value) =>
+              clientUriConverter.toClientFilePath(value),
+          valueCallback: (String value) =>
+              clientUriConverter.toClientFilePath(value));
     }
     return result;
   }
@@ -2767,7 +2838,10 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files',
+            json['files'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -2786,7 +2860,9 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['files'] = files;
+    result['files'] = files
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -2853,8 +2929,13 @@
             '$jsonPath.subscriptions', json['subscriptions'],
             keyDecoder: (String jsonPath, Object? json) =>
                 AnalysisService.fromJson(jsonDecoder, jsonPath, json),
-            valueDecoder: (String jsonPath, Object? json) => jsonDecoder
-                .decodeList(jsonPath, json, jsonDecoder.decodeString));
+            valueDecoder: (String jsonPath, Object? json) =>
+                jsonDecoder.decodeList(
+                    jsonPath,
+                    json,
+                    (String jsonPath, Object? json) =>
+                        clientUriConverter.fromClientFilePath(
+                            jsonDecoder.decodeString(jsonPath, json))));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'subscriptions');
       }
@@ -2874,7 +2955,10 @@
   Map<String, Object> toJson() {
     var result = <String, Object>{};
     result['subscriptions'] = mapMap(subscriptions,
-        keyCallback: (AnalysisService value) => value.toJson());
+        keyCallback: (AnalysisService value) => value.toJson(),
+        valueCallback: (List<String> value) => value
+            .map((String value) => clientUriConverter.toClientFilePath(value))
+            .toList());
     return result;
   }
 
@@ -3013,6 +3097,8 @@
       Map<String, Object> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeMap('$jsonPath.files', json['files'],
+            keyDecoder: (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)),
             valueDecoder: (String jsonPath, Object? json) =>
                 jsonDecoder.decodeUnion(jsonPath, json, 'type', {
                   'add': (String jsonPath, Object? json) =>
@@ -3042,6 +3128,8 @@
   Map<String, Object> toJson() {
     var result = <String, Object>{};
     result['files'] = mapMap(files,
+        keyCallback: (String value) =>
+            clientUriConverter.toClientFilePath(value),
         valueCallback: (Object value) => (value as dynamic).toJson());
     return result;
   }
@@ -3560,7 +3648,8 @@
     if (json is Map) {
       String path;
       if (json.containsKey('path')) {
-        path = jsonDecoder.decodeString('$jsonPath.path', json['path']);
+        path = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.path', json['path']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'path');
       }
@@ -3583,7 +3672,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['path'] = path;
+    result['path'] = clientUriConverter.toClientFilePath(path);
     result['fixes'] =
         fixes.map((BulkFixDetail value) => value.toJson()).toList();
     return result;
@@ -3841,7 +3930,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -3868,7 +3958,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['imports'] = imports.toJson();
     return result;
   }
@@ -3931,7 +4021,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -3971,7 +4062,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['completion'] = completion;
     result['libraryUri'] = libraryUri;
@@ -4144,7 +4235,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -4201,7 +4293,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['maxResults'] = maxResults;
     var completionCaseMatchingMode = this.completionCaseMatchingMode;
@@ -4918,7 +5010,10 @@
       List<String> included;
       if (json.containsKey('included')) {
         included = jsonDecoder.decodeList(
-            '$jsonPath.included', json['included'], jsonDecoder.decodeString);
+            '$jsonPath.included',
+            json['included'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'included');
       }
@@ -4952,7 +5047,9 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['included'] = included;
+    result['included'] = included
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     var inTestMode = this.inTestMode;
     if (inTestMode != null) {
       result['inTestMode'] = inTestMode;
@@ -5118,8 +5215,11 @@
     if (json is Map) {
       List<String> directories;
       if (json.containsKey('directories')) {
-        directories = jsonDecoder.decodeList('$jsonPath.directories',
-            json['directories'], jsonDecoder.decodeString);
+        directories = jsonDecoder.decodeList(
+            '$jsonPath.directories',
+            json['directories'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'directories');
       }
@@ -5137,7 +5237,9 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['directories'] = directories;
+    result['directories'] = directories
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -5265,7 +5367,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -5303,7 +5406,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['selectionOffset'] = selectionOffset;
     result['selectionLength'] = selectionLength;
     var lineLength = this.lineLength;
@@ -5467,7 +5570,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -5497,7 +5601,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     return result;
@@ -5625,7 +5729,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -5656,7 +5761,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     return result;
@@ -5781,7 +5886,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -5805,7 +5911,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     return result;
   }
@@ -5930,7 +6036,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -5961,7 +6068,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['key'] = key;
     result['offset'] = offset;
     return result;
@@ -6109,7 +6216,8 @@
       }
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -6155,7 +6263,7 @@
   Map<String, Object> toJson() {
     var result = <String, Object>{};
     result['kind'] = kind.toJson();
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     result['validateOnly'] = validateOnly;
@@ -6401,7 +6509,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -6426,7 +6535,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     return result;
   }
@@ -6565,7 +6674,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -6597,7 +6707,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['elements'] =
         elements.map((ImportedElements value) => value.toJson()).toList();
     var offset = this.offset;
@@ -6732,7 +6842,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -6763,7 +6874,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['key'] = key;
     result['offset'] = offset;
     return result;
@@ -6969,7 +7080,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -6988,7 +7100,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     return result;
   }
 
@@ -7097,7 +7209,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -7115,7 +7228,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     return result;
   }
 
@@ -7431,7 +7544,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -7451,7 +7565,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['kind'] = kind.toJson();
     return result;
   }
@@ -7559,8 +7673,8 @@
     if (json is Map) {
       String contextRoot;
       if (json.containsKey('contextRoot')) {
-        contextRoot = jsonDecoder.decodeString(
-            '$jsonPath.contextRoot', json['contextRoot']);
+        contextRoot = clientUriConverter.fromClientFilePath(jsonDecoder
+            .decodeString('$jsonPath.contextRoot', json['contextRoot']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'contextRoot');
       }
@@ -7579,7 +7693,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['contextRoot'] = contextRoot;
+    result['contextRoot'] = clientUriConverter.toClientFilePath(contextRoot);
     return result;
   }
 
@@ -7814,8 +7928,8 @@
       }
       String contextFile;
       if (json.containsKey('contextFile')) {
-        contextFile = jsonDecoder.decodeString(
-            '$jsonPath.contextFile', json['contextFile']);
+        contextFile = clientUriConverter.fromClientFilePath(jsonDecoder
+            .decodeString('$jsonPath.contextFile', json['contextFile']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'contextFile');
       }
@@ -7865,7 +7979,7 @@
     var result = <String, Object>{};
     result['code'] = code;
     result['offset'] = offset;
-    result['contextFile'] = contextFile;
+    result['contextFile'] = clientUriConverter.toClientFilePath(contextFile);
     result['contextOffset'] = contextOffset;
     result['variables'] = variables
         .map((RuntimeCompletionVariable value) => value.toJson())
@@ -8059,7 +8173,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -8070,8 +8185,11 @@
       }
       List<String>? referencedFiles;
       if (json.containsKey('referencedFiles')) {
-        referencedFiles = jsonDecoder.decodeList('$jsonPath.referencedFiles',
-            json['referencedFiles'], jsonDecoder.decodeString);
+        referencedFiles = jsonDecoder.decodeList(
+            '$jsonPath.referencedFiles',
+            json['referencedFiles'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       }
       return ExecutionLaunchDataParams(file,
           kind: kind, referencedFiles: referencedFiles);
@@ -8089,14 +8207,16 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     var kind = this.kind;
     if (kind != null) {
       result['kind'] = kind.toJson();
     }
     var referencedFiles = this.referencedFiles;
     if (referencedFiles != null) {
-      result['referencedFiles'] = referencedFiles;
+      result['referencedFiles'] = referencedFiles
+          .map((String value) => clientUriConverter.toClientFilePath(value))
+          .toList();
     }
     return result;
   }
@@ -8160,7 +8280,8 @@
       }
       String? file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       }
       String? uri;
       if (json.containsKey('uri')) {
@@ -8183,7 +8304,7 @@
     result['id'] = id;
     var file = this.file;
     if (file != null) {
-      result['file'] = file;
+      result['file'] = clientUriConverter.toClientFilePath(file);
     }
     var uri = this.uri;
     if (uri != null) {
@@ -8241,7 +8362,8 @@
     if (json is Map) {
       String? file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       }
       String? uri;
       if (json.containsKey('uri')) {
@@ -8265,7 +8387,7 @@
     var result = <String, Object>{};
     var file = this.file;
     if (file != null) {
-      result['file'] = file;
+      result['file'] = clientUriConverter.toClientFilePath(file);
     }
     var uri = this.uri;
     if (uri != null) {
@@ -9250,7 +9372,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -9275,7 +9398,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     return result;
   }
@@ -9899,7 +10022,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -9924,7 +10048,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['outline'] = outline.toJson();
     return result;
   }
@@ -10019,8 +10143,13 @@
             '$jsonPath.subscriptions', json['subscriptions'],
             keyDecoder: (String jsonPath, Object? json) =>
                 FlutterService.fromJson(jsonDecoder, jsonPath, json),
-            valueDecoder: (String jsonPath, Object? json) => jsonDecoder
-                .decodeList(jsonPath, json, jsonDecoder.decodeString));
+            valueDecoder: (String jsonPath, Object? json) =>
+                jsonDecoder.decodeList(
+                    jsonPath,
+                    json,
+                    (String jsonPath, Object? json) =>
+                        clientUriConverter.fromClientFilePath(
+                            jsonDecoder.decodeString(jsonPath, json))));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'subscriptions');
       }
@@ -10040,7 +10169,10 @@
   Map<String, Object> toJson() {
     var result = <String, Object>{};
     result['subscriptions'] = mapMap(subscriptions,
-        keyCallback: (FlutterService value) => value.toJson());
+        keyCallback: (FlutterService value) => value.toJson(),
+        valueCallback: (List<String> value) => value
+            .map((String value) => clientUriConverter.toClientFilePath(value))
+            .toList());
     return result;
   }
 
@@ -11401,7 +11533,8 @@
     if (json is Map) {
       String path;
       if (json.containsKey('path')) {
-        path = jsonDecoder.decodeString('$jsonPath.path', json['path']);
+        path = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.path', json['path']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'path');
       }
@@ -11427,7 +11560,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['path'] = path;
+    result['path'] = clientUriConverter.toClientFilePath(path);
     result['prefix'] = prefix;
     result['elements'] = elements;
     return result;
@@ -11720,14 +11853,18 @@
     if (json is Map) {
       String scope;
       if (json.containsKey('scope')) {
-        scope = jsonDecoder.decodeString('$jsonPath.scope', json['scope']);
+        scope = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.scope', json['scope']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'scope');
       }
       List<String> libraryPaths;
       if (json.containsKey('libraryPaths')) {
-        libraryPaths = jsonDecoder.decodeList('$jsonPath.libraryPaths',
-            json['libraryPaths'], jsonDecoder.decodeString);
+        libraryPaths = jsonDecoder.decodeList(
+            '$jsonPath.libraryPaths',
+            json['libraryPaths'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'libraryPaths');
       }
@@ -11740,8 +11877,10 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['scope'] = scope;
-    result['libraryPaths'] = libraryPaths;
+    result['scope'] = clientUriConverter.toClientFilePath(scope);
+    result['libraryPaths'] = libraryPaths
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -12039,8 +12178,8 @@
     if (json is Map) {
       String newFile;
       if (json.containsKey('newFile')) {
-        newFile =
-            jsonDecoder.decodeString('$jsonPath.newFile', json['newFile']);
+        newFile = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.newFile', json['newFile']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'newFile');
       }
@@ -12059,7 +12198,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['newFile'] = newFile;
+    result['newFile'] = clientUriConverter.toClientFilePath(newFile);
     return result;
   }
 
@@ -13176,8 +13315,8 @@
     if (json is Map) {
       String? libraryPath;
       if (json.containsKey('libraryPath')) {
-        libraryPath = jsonDecoder.decodeString(
-            '$jsonPath.libraryPath', json['libraryPath']);
+        libraryPath = clientUriConverter.fromClientFilePath(jsonDecoder
+            .decodeString('$jsonPath.libraryPath', json['libraryPath']));
       }
       RuntimeCompletionExpressionTypeKind kind;
       if (json.containsKey('kind')) {
@@ -13236,7 +13375,7 @@
     var result = <String, Object>{};
     var libraryPath = this.libraryPath;
     if (libraryPath != null) {
-      result['libraryPath'] = libraryPath;
+      result['libraryPath'] = clientUriConverter.toClientFilePath(libraryPath);
     }
     result['kind'] = kind.toJson();
     var name = this.name;
@@ -13463,7 +13602,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -13495,7 +13635,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['includePotential'] = includePotential;
     return result;
@@ -14025,7 +14165,8 @@
     if (json is Map) {
       String? file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       }
       String? pattern;
       if (json.containsKey('pattern')) {
@@ -14055,7 +14196,7 @@
     var result = <String, Object>{};
     var file = this.file;
     if (file != null) {
-      result['file'] = file;
+      result['file'] = clientUriConverter.toClientFilePath(file);
     }
     var pattern = this.pattern;
     if (pattern != null) {
@@ -14128,7 +14269,10 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files',
+            json['files'],
+            (String jsonPath, Object? json) => clientUriConverter
+                .fromClientFilePath(jsonDecoder.decodeString(jsonPath, json)));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -14151,7 +14295,9 @@
     var result = <String, Object>{};
     result['declarations'] =
         declarations.map((ElementDeclaration value) => value.toJson()).toList();
-    result['files'] = files;
+    result['files'] = files
+        .map((String value) => clientUriConverter.toClientFilePath(value))
+        .toList();
     return result;
   }
 
@@ -14209,7 +14355,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -14239,7 +14386,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     var superOnly = this.superOnly;
     if (superOnly != null) {
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index fc7fc0b..df80cec 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -38,7 +38,6 @@
 import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
 import 'package:analysis_server/src/services/user_prompts/survey_manager.dart';
 import 'package:analysis_server/src/services/user_prompts/user_prompts.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analysis_server/src/utilities/file_string_sink.dart';
 import 'package:analysis_server/src/utilities/null_string_sink.dart';
 import 'package:analysis_server/src/utilities/process.dart';
@@ -76,6 +75,7 @@
 import 'package:analyzer/src/utilities/extensions/analysis_session.dart';
 import 'package:analyzer_plugin/protocol/protocol.dart';
 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:collection/collection.dart';
 import 'package:http/http.dart' as http;
 import 'package:meta/meta.dart';
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index 8ba3931..9380717 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -12,13 +12,13 @@
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/progress.dart';
 import 'package:analysis_server/src/request_handler_mixin.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 import 'package:analyzer/src/utilities/cancellation.dart';
 import 'package:analyzer_plugin/protocol/protocol.dart';
 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:language_server_protocol/json_parsing.dart';
 import 'package:path/path.dart' as path;
 
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index fb9fe14..15d673b 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -29,7 +29,6 @@
 import 'package:analysis_server/src/server/error_notifier.dart';
 import 'package:analysis_server/src/server/performance.dart';
 import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analysis_server/src/utilities/flutter.dart';
 import 'package:analysis_server/src/utilities/process.dart';
 import 'package:analyzer/dart/analysis/context_locator.dart';
@@ -46,6 +45,7 @@
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:collection/collection.dart';
 import 'package:http/http.dart' as http;
 import 'package:meta/meta.dart';
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 8d5ae9d..d903aad 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -18,7 +18,6 @@
     hide AnalysisError;
 import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
 import 'package:analysis_server/src/services/snippets/snippet.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analysis_server/src/utilities/extensions/string.dart';
 import 'package:analyzer/dart/analysis/results.dart' as server;
 import 'package:analyzer/error/error.dart' as server;
@@ -30,6 +29,7 @@
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/utilities/extensions/collection.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:collection/collection.dart';
 
 const languageSourceName = 'dart';
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index 51407e6..3bd06e3 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -316,7 +316,13 @@
       clientCapabilities: _server.lspClientCapabilities!,
       clientConfiguration: _server.lspClientConfiguration,
       customDartSchemes: _server.uriConverter.supportedNonFileSchemes,
-      dartFilters: _server.uriConverter.filters,
+      dartFilters: [
+        for (var scheme in {
+          'file',
+          ..._server.uriConverter.supportedNonFileSchemes
+        })
+          TextDocumentFilterWithScheme(language: 'dart', scheme: scheme)
+      ],
       pluginTypes: pluginTypes,
     );
   }
diff --git a/pkg/analysis_server/test/lsp/dart_text_document_content_provider_test.dart b/pkg/analysis_server/test/lsp/dart_text_document_content_provider_test.dart
index d42dbbf..0d9f87b 100644
--- a/pkg/analysis_server/test/lsp/dart_text_document_content_provider_test.dart
+++ b/pkg/analysis_server/test/lsp/dart_text_document_content_provider_test.dart
@@ -4,8 +4,8 @@
 
 import 'package:analysis_server/src/legacy_analysis_server.dart';
 import 'package:analysis_server/src/lsp/test_macros.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:language_server_protocol/protocol_generated.dart';
 import 'package:test/expect.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/lsp/request_helpers_mixin.dart b/pkg/analysis_server/test/lsp/request_helpers_mixin.dart
index e5a057d..8827de6 100644
--- a/pkg/analysis_server/test/lsp/request_helpers_mixin.dart
+++ b/pkg/analysis_server/test/lsp/request_helpers_mixin.dart
@@ -8,8 +8,8 @@
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:collection/collection.dart';
 import 'package:language_server_protocol/json_parsing.dart';
 import 'package:path/path.dart' as path;
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 42b0c28..e4020ff 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -13,7 +13,6 @@
 import 'package:analysis_server/src/plugin/plugin_manager.dart';
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
 import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk.dart';
@@ -23,6 +22,7 @@
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:collection/collection.dart';
 import 'package:language_server_protocol/json_parsing.dart';
 import 'package:path/path.dart' as path;
diff --git a/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart b/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart
index d583abe..fccc076 100644
--- a/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart
+++ b/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart
@@ -7,7 +7,7 @@
 import 'package:analysis_server/lsp_protocol/protocol.dart';
 import 'package:analysis_server/src/protocol/protocol_internal.dart';
 import 'package:analysis_server/src/protocol_server.dart';
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
diff --git a/pkg/analysis_server/test/src/computer/color_computer_test.dart b/pkg/analysis_server/test/src/computer/color_computer_test.dart
index dc24362..4a91634 100644
--- a/pkg/analysis_server/test/src/computer/color_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/color_computer_test.dart
@@ -8,7 +8,6 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../../tool/codebase/failing_tests.dart';
 import '../../abstract_context.dart';
 
 void main() {
diff --git a/pkg/analysis_server/test/src/utilities/json_test.dart b/pkg/analysis_server/test/src/utilities/json_test.dart
new file mode 100644
index 0000000..492f4281
--- /dev/null
+++ b/pkg/analysis_server/test/src/utilities/json_test.dart
@@ -0,0 +1,230 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/protocol/protocol_internal.dart';
+import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer_plugin/src/protocol/protocol_internal.dart'
+    show clientUriConverter;
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(JsonTest);
+    defineReflectiveTests(JsonWithConvertedFilePathsTest);
+  });
+}
+
+@reflectiveTest
+class JsonTest {
+  final decoder = ResponseDecoder(null);
+
+  void test_fromJson() {
+    var json = {
+      'offset': 0,
+      'length': 1,
+      'label': 'x',
+    };
+    var label = ClosingLabel.fromJson(decoder, '', json);
+    expect(label.label, 'x');
+    expect(label.offset, 0);
+    expect(label.length, 1);
+  }
+
+  void test_toJson() {
+    var closingLabel = ClosingLabel(0, 1, 'x');
+    var json = closingLabel.toJson();
+
+    expect(json, {
+      'offset': 0,
+      'length': 1,
+      'label': 'x',
+    });
+  }
+}
+
+@reflectiveTest
+class JsonWithConvertedFilePathsTest with ResourceProviderMixin {
+  final decoder = ResponseDecoder(null);
+
+  void setUp() {
+    // These tests use a dummy encoder that just prefixes the FilePaths with
+    // "Encoded" and "Decoded" to simplify testing. The real implementation will
+    // convert between file paths and URI strings.
+    clientUriConverter = _PrefixingUriConverter();
+  }
+
+  void tearDown() {
+    // Because this is currently global, restore after the tests.
+    clientUriConverter = ClientUriConverter.noop(pathContext);
+  }
+
+  void test_fromJson_filePath_list() {
+    var json = {
+      'files': ['/my/file/1', '/my/file/2']
+    };
+    var params = AnalysisFlushResultsParams.fromJson(decoder, '', json);
+    expect(params.files, ['Decoded /my/file/1', 'Decoded /my/file/2']);
+  }
+
+  void test_fromJson_filePath_map_keyValue() {
+    var json = {
+      'included': [],
+      'excluded': [],
+      'packageRoots': {
+        '/my/file/key': '/my/file/value',
+      }
+    };
+    var params = AnalysisSetAnalysisRootsParams.fromJson(decoder, '', json);
+    expect(params.packageRoots, {
+      'Decoded /my/file/key': 'Decoded /my/file/value',
+    });
+  }
+
+  void test_fromJson_filePath_map_value_list() {
+    var json = {
+      'subscriptions': {
+        'CLOSING_LABELS': ['/my/file/value']
+      }
+    };
+    var params = AnalysisSetSubscriptionsParams.fromJson(decoder, '', json);
+    expect(params.subscriptions, {
+      AnalysisService.CLOSING_LABELS: ['Decoded /my/file/value'],
+    });
+  }
+
+  void test_fromJson_filePath_nested() {
+    var json = {
+      'fixes': [
+        {
+          'error': {
+            'severity': 'INFO',
+            'type': 'LINT',
+            'location': {
+              'file': '/my/file',
+              'offset': 0,
+              'length': 1,
+              'startLine': 2,
+              'startColumn': 3
+            },
+            'message': 'x',
+            'code': 'y'
+          },
+          'fixes': []
+        }
+      ]
+    };
+    var result = EditGetFixesResult.fromJson(decoder, '', json);
+    expect(result.fixes.single.error.location.file, 'Decoded /my/file');
+  }
+
+  void test_fromJson_filePath_topLevel() {
+    var json = {'file': '/my/file', 'labels': []};
+    var params = AnalysisClosingLabelsParams.fromJson(decoder, '', json);
+    expect(params.file, 'Decoded /my/file');
+  }
+
+  void test_toJson_list() {
+    var params = AnalysisFlushResultsParams(['/my/file/1', '/my/file/2']);
+    var json = params.toJson();
+
+    expect(
+      json,
+      {
+        'files': ['Encoded /my/file/1', 'Encoded /my/file/2']
+      },
+    );
+  }
+
+  void test_toJson_map_keyValue() {
+    var params = AnalysisSetAnalysisRootsParams(
+      [],
+      [],
+      packageRoots: {
+        '/my/file/key': '/my/file/value',
+      },
+    );
+    var json = params.toJson();
+    expect(json, {
+      'included': [],
+      'excluded': [],
+      'packageRoots': {
+        'Encoded /my/file/key': 'Encoded /my/file/value',
+      }
+    });
+  }
+
+  void test_toJson_map_value_list() {
+    var params = AnalysisSetSubscriptionsParams(
+      {
+        AnalysisService.CLOSING_LABELS: ['/my/file/value'],
+      },
+    );
+    var json = params.toJson();
+    expect(json, {
+      'subscriptions': {
+        'CLOSING_LABELS': ['Encoded /my/file/value']
+      }
+    });
+  }
+
+  void test_toJson_nested() {
+    var result = EditGetFixesResult([
+      AnalysisErrorFixes(
+        AnalysisError(
+          AnalysisErrorSeverity.INFO,
+          AnalysisErrorType.LINT,
+          Location('/my/file', 0, 1, 2, 3),
+          'x',
+          'y',
+        ),
+      )
+    ]);
+    var json = result.toJson();
+    expect(json, {
+      'fixes': [
+        {
+          'error': {
+            'severity': 'INFO',
+            'type': 'LINT',
+            'location': {
+              'file': 'Encoded /my/file',
+              'offset': 0,
+              'length': 1,
+              'startLine': 2,
+              'startColumn': 3
+            },
+            'message': 'x',
+            'code': 'y'
+          },
+          'fixes': []
+        }
+      ]
+    });
+  }
+
+  void test_toJson_topLevel() {
+    var closingLabelParams = AnalysisClosingLabelsParams('/my/file', []);
+    var json = closingLabelParams.toJson();
+
+    expect(
+      json,
+      {'file': 'Encoded /my/file', 'labels': []},
+    );
+  }
+}
+
+/// A [ClientUriConverter] that just prefixes the input string for testing.
+class _PrefixingUriConverter implements ClientUriConverter {
+  @override
+  String fromClientFilePath(String filePathOrUri) => 'Decoded $filePathOrUri';
+
+  @override
+  dynamic noSuchMethod(Invocation invocation) => throw UnimplementedError();
+
+  @override
+  String toClientFilePath(String filePath) => 'Encoded $filePath';
+}
diff --git a/pkg/analysis_server/test/src/utilities/test_all.dart b/pkg/analysis_server/test/src/utilities/test_all.dart
index 48acc60..e506364 100644
--- a/pkg/analysis_server/test/src/utilities/test_all.dart
+++ b/pkg/analysis_server/test/src/utilities/test_all.dart
@@ -4,10 +4,10 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'client_uri_converter_test.dart' as client_uri_converter;
 import 'extensions/test_all.dart' as extensions;
 import 'flutter_test.dart' as flutter;
 import 'import_analyzer_test.dart' as import_analyzer;
+import 'json_test.dart' as json;
 import 'profiling_test.dart' as profiling;
 import 'selection_coverage_test.dart' as selection_coverage;
 import 'selection_test.dart' as selection;
@@ -16,9 +16,9 @@
 
 void main() {
   defineReflectiveSuite(() {
-    client_uri_converter.main();
     extensions.main();
     flutter.main();
+    json.main();
     import_analyzer.main();
     profiling.main();
     selection_coverage.main();
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index 81415aa..1212c8a 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -25,21 +25,31 @@
   'deprecated': '0x20'
 };
 
-GeneratedFile clientTarget(bool responseRequiresRequestTime) {
+GeneratedFile clientTarget(
+    bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) {
   return GeneratedFile(
       '../analysis_server_client/lib/src/protocol/protocol_generated.dart',
       (String pkgPath) async {
-    var visitor = CodegenProtocolVisitor('analysis_server_client',
-        responseRequiresRequestTime, false, readApi(pkgPath));
+    var visitor = CodegenProtocolVisitor(
+        'analysis_server_client',
+        responseRequiresRequestTime,
+        requiresProtocolJsonMethods,
+        false,
+        readApi(pkgPath));
     return visitor.collectCode(visitor.visitApi);
   });
 }
 
-GeneratedFile serverTarget(bool responseRequiresRequestTime) {
+GeneratedFile serverTarget(
+    bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) {
   return GeneratedFile('lib/protocol/protocol_generated.dart',
       (String pkgPath) async {
-    var visitor = CodegenProtocolVisitor(path.basename(pkgPath),
-        responseRequiresRequestTime, true, readApi(pkgPath));
+    var visitor = CodegenProtocolVisitor(
+        path.basename(pkgPath),
+        responseRequiresRequestTime,
+        requiresProtocolJsonMethods,
+        true,
+        readApi(pkgPath));
     return visitor.collectCode(visitor.visitApi);
   });
 }
@@ -75,6 +85,10 @@
   /// parameter.
   final bool responseRequiresRequestTime;
 
+  /// A flag indicating whether the classes should have `toProtocolJson` and
+  /// `fromProtocolJson` methods that can handle converting client URIs.
+  final bool requiresProtocolJsonMethods;
+
   /// A flag indicating whether this generated code is for the server
   /// (analysis_server) or for the client (analysis_server_client).
   final bool isServer;
@@ -88,7 +102,7 @@
   final Map<String, ImpliedType> impliedTypes;
 
   CodegenProtocolVisitor(this.packageName, this.responseRequiresRequestTime,
-      this.isServer, Api api)
+      this.requiresProtocolJsonMethods, this.isServer, Api api)
       : toHtmlVisitor = ToHtmlVisitor(api),
         impliedTypes = computeImpliedTypes(api),
         super(api) {
@@ -383,6 +397,8 @@
       writeln("import 'package:$packageName/protocol/protocol.dart';");
       writeln(
           "import 'package:$packageName/src/protocol/protocol_internal.dart';");
+      writeln(
+          "import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' show clientUriConverter;");
       for (var uri in api.types.importUris) {
         write("import '");
         write(uri);
@@ -943,6 +959,12 @@
               return '$typeName.fromJson(jsonDecoder, $jsonPath, $json)';
             }
           });
+        } else if (requiresProtocolJsonMethods &&
+            referencedDefinition.name == 'FilePath') {
+          // TODO(dantup): Ensure if the client sends us filepaths instead of
+          //  URIs that we generate good error responses.
+          return FromJsonSnippet((jsonPath, json) =>
+              'clientUriConverter.fromClientFilePath(jsonDecoder.decodeString($jsonPath, $json))');
         } else {
           return fromJsonCode(referencedType);
         }
@@ -966,7 +988,10 @@
       }
     } else if (type is TypeMap) {
       FromJsonCode keyCode;
-      if (dartType(type.keyType) != 'String') {
+      var referencedDefinition = api.types[type.keyType.typeName];
+      if (dartType(type.keyType) != 'String' ||
+          (requiresProtocolJsonMethods &&
+              referencedDefinition?.name == 'FilePath')) {
         keyCode = fromJsonCode(type.keyType);
       } else {
         keyCode = FromJsonIdentity();
@@ -1060,7 +1085,14 @@
   /// Compute the code necessary to convert [type] to JSON.
   ToJsonCode toJsonCode(TypeDecl type) {
     var resolvedType = resolveTypeReferenceChain(type);
-    if (resolvedType is TypeReference) {
+    if (type is TypeReference &&
+        requiresProtocolJsonMethods &&
+        type.typeName == 'FilePath') {
+      return ToJsonSnippet(
+        dartType(type),
+        (String value) => 'clientUriConverter.toClientFilePath($value)',
+      );
+    } else if (resolvedType is TypeReference) {
       return ToJsonIdentity(dartType(type));
     } else if (resolvedType is TypeList) {
       var itemCode = toJsonCode(resolvedType.itemType);
@@ -1072,7 +1104,10 @@
       }
     } else if (resolvedType is TypeMap) {
       ToJsonCode keyCode;
-      if (dartType(resolvedType.keyType) != 'String') {
+      var referencedDefinition = api.types[resolvedType.keyType.typeName];
+      if (dartType(resolvedType.keyType) != 'String' ||
+          (requiresProtocolJsonMethods &&
+              referencedDefinition?.name == 'FilePath')) {
         keyCode = toJsonCode(resolvedType.keyType);
       } else {
         keyCode = ToJsonIdentity(dartType(resolvedType.keyType));
diff --git a/pkg/analysis_server/tool/spec/generate_all.dart b/pkg/analysis_server/tool/spec/generate_all.dart
index f6f43af..f31cbfa 100644
--- a/pkg/analysis_server/tool/spec/generate_all.dart
+++ b/pkg/analysis_server/tool/spec/generate_all.dart
@@ -29,8 +29,8 @@
   var targets = <GeneratedContent>[];
   targets.add(codegen_analysis_server.target);
   targets.add(codegen_dart_notification_handler.clientTarget());
-  targets.add(codegen_dart_protocol.clientTarget(false));
-  targets.add(codegen_dart_protocol.serverTarget(false));
+  targets.add(codegen_dart_protocol.clientTarget(false, false));
+  targets.add(codegen_dart_protocol.serverTarget(false, true));
   targets.add(codegen_java_types.targetDir);
   targets.add(codegen_inttest_methods.target);
   targets.add(codegen_matchers.target);
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart
index 5cb6980..6f171bf 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart
@@ -9,6 +9,8 @@
 import 'package:analysis_server_client/src/protocol/protocol_common.dart';
 import 'package:analysis_server_client/src/protocol/protocol_generated.dart';
 
+final clientUriConverter = _ClientUriConverter();
+
 final Map<String, RefactoringKind> REQUEST_ID_REFACTORING_KINDS =
     HashMap<String, RefactoringKind>();
 
@@ -462,3 +464,14 @@
   /// given [id].
   Response toResponse(String id);
 }
+
+/// A dummy converter with the required API for the copy of protocol classes
+/// in analysis_server_client.
+class _ClientUriConverter {
+  // TODO(dantup): Determine whether analysis_server_client needs to support
+  //  macro mappings.
+
+  String fromClientFilePath(String filePath) => filePath;
+
+  String toClientFilePath(String filePath) => filePath;
+}
diff --git a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
index 7d4370b..d213847 100644
--- a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
+++ b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
@@ -24,6 +24,8 @@
           ? MemoryResourceProvider(context: path.windows)
           : MemoryResourceProvider();
 
+  path.Context get pathContext => resourceProvider.pathContext;
+
   String convertPath(String path) => resourceProvider.convertPath(path);
 
   void deleteAnalysisOptionsYamlFile(String directoryPath) {
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index 3f30a99..2ce5165 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -2798,7 +2798,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -2847,7 +2848,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     result['length'] = length;
     result['startLine'] = startLine;
@@ -3538,7 +3539,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -3557,7 +3559,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['offset'] = offset;
     return result;
   }
@@ -4390,7 +4392,8 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
+        file = clientUriConverter.fromClientFilePath(
+            jsonDecoder.decodeString('$jsonPath.file', json['file']));
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -4420,7 +4423,7 @@
   @override
   Map<String, Object> toJson() {
     var result = <String, Object>{};
-    result['file'] = file;
+    result['file'] = clientUriConverter.toClientFilePath(file);
     result['fileStamp'] = fileStamp;
     result['edits'] = edits.map((SourceEdit value) => value.toJson()).toList();
     return result;
diff --git a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
index 5185ebc..fc01678 100644
--- a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
@@ -8,7 +8,16 @@
 import 'package:analyzer_plugin/protocol/protocol.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
+import 'package:path/path.dart' as path;
+
+/// This can be set by server (or tests) to change into URI mode for all legacy
+/// protocol JSON.
+///
+// TODO(dantup): Consider replacing this global with encoders being passed to
+//  toJson/fromJson methods.
+var clientUriConverter = ClientUriConverter.noop(path.context);
 
 final Map<String, RefactoringKind> REQUEST_ID_REFACTORING_KINDS =
     HashMap<String, RefactoringKind>();
diff --git a/pkg/analysis_server/lib/src/utilities/client_uri_converter.dart b/pkg/analyzer_plugin/lib/src/utilities/client_uri_converter.dart
similarity index 63%
rename from pkg/analysis_server/lib/src/utilities/client_uri_converter.dart
rename to pkg/analyzer_plugin/lib/src/utilities/client_uri_converter.dart
index 3396d23..4260e23 100644
--- a/pkg/analysis_server/lib/src/utilities/client_uri_converter.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/client_uri_converter.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analysis_server/lsp_protocol/protocol.dart';
 import 'package:path/path.dart' as path;
 
 /// The file suffix used for virtual macro files in the analyzer.
@@ -17,7 +16,7 @@
 /// The simplest form of this class simple translates between file paths and
 /// `file://` URIs but depending on client capabilities some paths/URIs may be
 /// re-written to support features like virtual files for macros.
-class ClientUriConverter {
+abstract class ClientUriConverter {
   final path.Context _context;
 
   /// The URI schemes that are supported by this converter.
@@ -29,27 +28,69 @@
   /// The URI schemes that are supported by this converter except 'file'.
   final Set<String> supportedNonFileSchemes;
 
-  /// A set of document filters for Dart files in the supported schemes.
-  final List<TextDocumentFilterWithScheme> filters;
-
   /// Creates a converter that does nothing besides translation between file
   /// paths and `file://` URIs.
-  ClientUriConverter.noop(path.Context context) : this._(context);
+  factory ClientUriConverter.noop(path.Context context) =>
+      _NoOpConverter(context);
 
   /// Creates a converter that translates paths/URIs for virtual files such as
   /// those created by macros.
-  ClientUriConverter.withVirtualFileSupport(path.Context context)
-      : this._(context, {macroClientUriScheme});
+  factory ClientUriConverter.withVirtualFileSupport(path.Context context) =>
+      _VirtualFileClientUriConverter(context);
 
   ClientUriConverter._(this._context, [this.supportedNonFileSchemes = const {}])
-      : supportedSchemes = {'file', ...supportedNonFileSchemes},
-        filters = [
-          for (var scheme in {'file', ...supportedNonFileSchemes})
-            TextDocumentFilterWithScheme(language: 'dart', scheme: scheme)
-        ];
+      : supportedSchemes = {'file', ...supportedNonFileSchemes};
+
+  /// Converts client FilePath (which may be a URI or a file path depending on
+  /// client capbilities) into a file path/reference from the analyzer.
+  ///
+  /// This is the legacy protocol equiv of [fromClientUri].
+  String fromClientFilePath(String filePathOrUri);
 
   /// Converts a URI provided by the client into a file path/reference that can
   /// be used by the analyzer.
+  ///
+  /// This is the LSP equiv of [fromClientFilePath].
+  String fromClientUri(Uri uri);
+
+  /// Converts a file path/reference from the analyzer into a client FilePath
+  /// (which may be a URI or a file path depending on client capbilities).
+  ///
+  /// This is the legacy protocol equiv of [toClientUri].
+  String toClientFilePath(String filePath);
+
+  /// Converts a file path/reference from the analyzer into a URI to be sent to
+  /// the client.
+  ///
+  /// This is the LSP equiv of [toClientFilePath].
+  Uri toClientUri(String filePath);
+}
+
+class _NoOpConverter extends ClientUriConverter {
+  _NoOpConverter(super.context) : super._();
+
+  @override
+  String fromClientFilePath(String filePathOrUri) => filePathOrUri;
+
+  @override
+  String fromClientUri(Uri uri) => _context.fromUri(uri);
+
+  @override
+  String toClientFilePath(String filePath) => filePath;
+
+  @override
+  Uri toClientUri(String filePath) => _context.toUri(filePath);
+}
+
+class _VirtualFileClientUriConverter extends ClientUriConverter {
+  _VirtualFileClientUriConverter(path.Context context)
+      : super._(context, {macroClientUriScheme});
+
+  @override
+  String fromClientFilePath(String filePathOrUri) =>
+      fromClientUri(Uri.parse(filePathOrUri));
+
+  @override
   String fromClientUri(Uri uri) {
     // For URIs with no scheme, assume it was a relative path and provide a
     // better message than "scheme '' is not supported".
@@ -81,8 +122,10 @@
     }
   }
 
-  /// Converts a file path/reference from the analyzer into a URI to be sent to
-  /// the client.
+  @override
+  String toClientFilePath(String filePath) => toClientUri(filePath).toString();
+
+  @override
   Uri toClientUri(String filePath) {
     // Map '/.../x.macro.dart' onto macro scheme.
     if (filePath.endsWith(macroClientFileSuffix) &&
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 54cb041..08dd5bd 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -12,6 +12,7 @@
   dart_style: ^2.2.1
   pub_semver: ^2.1.0
   yaml: ^3.1.0
+  path: ^1.9.0
 
 # We use 'any' version constraints here as we get our package versions from
 # the dart-lang/sdk repo's DEPS file. Note that this is a special case; the
@@ -22,6 +23,5 @@
   lints: any
   linter: any
   meta: any
-  path: any
   test_reflective_loader: any
   test: any
diff --git a/pkg/analysis_server/test/src/utilities/client_uri_converter_test.dart b/pkg/analyzer_plugin/test/src/utilities/client_uri_converter_test.dart
similarity index 86%
rename from pkg/analysis_server/test/src/utilities/client_uri_converter_test.dart
rename to pkg/analyzer_plugin/test/src/utilities/client_uri_converter_test.dart
index 3842d70..14f6e52 100644
--- a/pkg/analysis_server/test/src/utilities/client_uri_converter_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/client_uri_converter_test.dart
@@ -2,13 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analysis_server/src/utilities/client_uri_converter.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer_plugin/src/utilities/client_uri_converter.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../../tool/codebase/failing_tests.dart';
-import '../../abstract_single_unit.dart';
-
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ClientUriConverterTest);
@@ -16,7 +14,7 @@
 }
 
 @reflectiveTest
-class ClientUriConverterTest extends AbstractSingleUnitTest {
+class ClientUriConverterTest with ResourceProviderMixin {
   Future<void> test_noop_fromUri() async {
     var converter = ClientUriConverter.noop(pathContext);
 
diff --git a/pkg/analyzer_plugin/test/src/utilities/test_all.dart b/pkg/analyzer_plugin/test/src/utilities/test_all.dart
index ba180de..fb88ce8 100644
--- a/pkg/analyzer_plugin/test/src/utilities/test_all.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/test_all.dart
@@ -5,6 +5,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'change_builder/test_all.dart' as change_builder;
+import 'client_uri_converter_test.dart' as client_uri_converter;
 import 'completion/test_all.dart' as completion;
 import 'navigation/test_all.dart' as navigation;
 import 'string_utilities_test.dart' as string_utilities;
@@ -13,6 +14,7 @@
 void main() {
   defineReflectiveSuite(() {
     change_builder.main();
+    client_uri_converter.main();
     completion.main();
     navigation.main();
     string_utilities.main();
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
index ddaf543..68c735c 100644
--- a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
@@ -25,11 +25,15 @@
   'deprecated': '0x20'
 };
 
-GeneratedFile target(bool responseRequiresRequestTime) {
+GeneratedFile target(
+    bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) {
   return GeneratedFile('lib/protocol/protocol_generated.dart',
       (String pkgPath) async {
     var visitor = CodegenProtocolVisitor(
-        path.basename(pkgPath), responseRequiresRequestTime, readApi(pkgPath));
+        path.basename(pkgPath),
+        responseRequiresRequestTime,
+        requiresProtocolJsonMethods,
+        readApi(pkgPath));
     return visitor.collectCode(visitor.visitApi);
   });
 }
@@ -65,6 +69,10 @@
   /// parameter.
   final bool responseRequiresRequestTime;
 
+  /// A flag indicating whether the classes should have `toProtocolJson` and
+  /// `fromProtocolJson` methods that can handle converting client URIs.
+  final bool requiresProtocolJsonMethods;
+
   /// Visitor used to produce doc comments.
   final ToHtmlVisitor toHtmlVisitor;
 
@@ -73,8 +81,8 @@
   /// notifications, etc.
   final Map<String, ImpliedType> impliedTypes;
 
-  CodegenProtocolVisitor(
-      this.packageName, this.responseRequiresRequestTime, Api api)
+  CodegenProtocolVisitor(this.packageName, this.responseRequiresRequestTime,
+      this.requiresProtocolJsonMethods, Api api)
       : toHtmlVisitor = ToHtmlVisitor(api),
         impliedTypes = computeImpliedTypes(api),
         super(api) {
@@ -957,6 +965,10 @@
               return '$typeName.fromJson(jsonDecoder, $jsonPath, $json)';
             }
           });
+        } else if (requiresProtocolJsonMethods &&
+            referencedDefinition.name == 'FilePath') {
+          return FromJsonSnippet((jsonPath, json) =>
+              'clientUriConverter.fromClientFilePath(jsonDecoder.decodeString($jsonPath, $json))');
         } else {
           return fromJsonCode(referencedType);
         }
@@ -977,7 +989,10 @@
       }
     } else if (type is TypeMap) {
       FromJsonCode keyCode;
-      if (dartType(type.keyType) != 'String') {
+      var referencedDefinition = api.types[type.keyType.typeName];
+      if (dartType(type.keyType) != 'String' ||
+          (requiresProtocolJsonMethods &&
+              referencedDefinition?.name == 'FilePath')) {
         keyCode = fromJsonCode(type.keyType);
       } else {
         keyCode = FromJsonIdentity();
@@ -1071,7 +1086,14 @@
   /// Compute the code necessary to convert [type] to JSON.
   ToJsonCode toJsonCode(TypeDecl type) {
     var resolvedType = resolveTypeReferenceChain(type);
-    if (resolvedType is TypeReference) {
+    if (type is TypeReference &&
+        requiresProtocolJsonMethods &&
+        type.typeName == 'FilePath') {
+      return ToJsonSnippet(
+        dartType(type),
+        (String value) => 'clientUriConverter.toClientFilePath($value)',
+      );
+    } else if (resolvedType is TypeReference) {
       return ToJsonIdentity(dartType(type));
     } else if (resolvedType is TypeList) {
       var itemCode = toJsonCode(resolvedType.itemType);
@@ -1083,7 +1105,10 @@
       }
     } else if (resolvedType is TypeMap) {
       ToJsonCode keyCode;
-      if (dartType(resolvedType.keyType) != 'String') {
+      var referencedDefinition = api.types[resolvedType.keyType.typeName];
+      if (dartType(resolvedType.keyType) != 'String' ||
+          (requiresProtocolJsonMethods &&
+              referencedDefinition?.name == 'FilePath')) {
         keyCode = toJsonCode(resolvedType.keyType);
       } else {
         keyCode = ToJsonIdentity(dartType(resolvedType.keyType));
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_protocol_common.dart b/pkg/analyzer_plugin/tool/spec/codegen_protocol_common.dart
index 01389b7..78bd981 100644
--- a/pkg/analyzer_plugin/tool/spec/codegen_protocol_common.dart
+++ b/pkg/analyzer_plugin/tool/spec/codegen_protocol_common.dart
@@ -10,19 +10,28 @@
 import 'from_html.dart';
 import 'implied_types.dart';
 
-GeneratedFile clientTarget(bool responseRequiresRequestTime) => GeneratedFile(
+GeneratedFile clientTarget(
+        bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) =>
+    GeneratedFile(
         '../analysis_server_client/lib/src/protocol/protocol_common.dart',
         (String pkgPath) async {
       var visitor = CodegenCommonVisitor(
-          path.basename(pkgPath), responseRequiresRequestTime, readApi(pkgPath),
+          path.basename(pkgPath),
+          responseRequiresRequestTime,
+          requiresProtocolJsonMethods,
+          readApi(pkgPath),
           forClient: true);
       return visitor.collectCode(visitor.visitApi);
     });
 
-GeneratedFile pluginTarget(bool responseRequiresRequestTime) =>
+GeneratedFile pluginTarget(
+        bool responseRequiresRequestTime, bool requiresProtocolJsonMethods) =>
     GeneratedFile('lib/protocol/protocol_common.dart', (String pkgPath) async {
-      var visitor = CodegenCommonVisitor(path.basename(pkgPath),
-          responseRequiresRequestTime, readApi(pkgPath));
+      var visitor = CodegenCommonVisitor(
+          path.basename(pkgPath),
+          responseRequiresRequestTime,
+          requiresProtocolJsonMethods,
+          readApi(pkgPath));
       return visitor.collectCode(visitor.visitApi);
     });
 
@@ -34,8 +43,8 @@
   /// Initialize a newly created visitor to generate code in the package with
   /// the given [packageName] corresponding to the types in the given [api] that
   /// are common to multiple protocols.
-  CodegenCommonVisitor(
-      super.packageName, super.responseRequiresRequestTime, super.api,
+  CodegenCommonVisitor(super.packageName, super.responseRequiresRequestTime,
+      super.requiresProtocolJsonMethods, super.api,
       {this.forClient = false});
 
   @override
diff --git a/pkg/analyzer_plugin/tool/spec/generate_all.dart b/pkg/analyzer_plugin/tool/spec/generate_all.dart
index 6507475..2b69df5 100644
--- a/pkg/analyzer_plugin/tool/spec/generate_all.dart
+++ b/pkg/analyzer_plugin/tool/spec/generate_all.dart
@@ -24,11 +24,11 @@
 /// Get a list of all generated targets.
 List<GeneratedContent> get allTargets {
   var targets = <GeneratedContent>[];
-  targets.add(codegen_dart_protocol.target(true));
+  targets.add(codegen_dart_protocol.target(true, false));
   targets.add(codegen_inttest_methods.target);
   targets.add(codegen_matchers.target);
-  targets.add(codegen_protocol_common.pluginTarget(true));
-  targets.add(codegen_protocol_common.clientTarget(true));
+  targets.add(codegen_protocol_common.pluginTarget(true, true));
+  targets.add(codegen_protocol_common.clientTarget(true, false));
   targets.add(codegen_protocol_constants.target);
   targets.add(to_html.target);
   return targets;