diff --git a/photon-client/src/components/settings/ObjectDetectionCard.vue b/photon-client/src/components/settings/ObjectDetectionCard.vue
index 7b9a2b9877..db6e9d419e 100644
--- a/photon-client/src/components/settings/ObjectDetectionCard.vue
+++ b/photon-client/src/components/settings/ObjectDetectionCard.vue
@@ -86,7 +86,7 @@ const renameModel = async (model: ObjectDetectionModelProperties, newName: strin
});
axiosPost("/objectdetection/rename", "rename an object detection model", {
- modelPath: model.modelPath.replace("file:", ""),
+ modelPath: model.modelPath,
newName: newName
});
showRenameDialog.value.show = false;
@@ -418,7 +418,7 @@ const handleBulkImport = () => {
diff --git a/photon-core/src/main/java/org/photonvision/common/util/file/JacksonUtils.java b/photon-core/src/main/java/org/photonvision/common/util/file/JacksonUtils.java
index d979060311..40d8e6a4ff 100644
--- a/photon-core/src/main/java/org/photonvision/common/util/file/JacksonUtils.java
+++ b/photon-core/src/main/java/org/photonvision/common/util/file/JacksonUtils.java
@@ -17,15 +17,9 @@
package org.photonvision.common.util.file;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.json.JsonReadFeature;
-import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
@@ -37,7 +31,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.io.EofException;
@@ -45,89 +38,41 @@
public class JacksonUtils {
public static class UIMap extends HashMap {}
- // Custom Path serializer that outputs just the path string without file:/ prefix
- public static class PathSerializer extends JsonSerializer {
- @Override
- public void serialize(Path value, JsonGenerator gen, SerializerProvider serializers)
- throws IOException {
- if (value == null) {
- gen.writeNull();
- } else {
- gen.writeString(value.toString());
- }
- }
- }
-
- // Custom Path deserializer that reads path strings
- public static class PathDeserializer extends JsonDeserializer {
- @Override
- public Path deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
- String pathString = p.getValueAsString();
- if (pathString == null || pathString.isEmpty()) {
- return null;
- }
-
- // Handle case where old serialized data might still have file:/ prefix
- if (pathString.startsWith("file:/")) {
- pathString = pathString.substring(6); // Remove "file:/" prefix
- }
-
- return Paths.get(pathString);
- }
- }
-
- // Custom Path key deserializer for Maps with Path keys
- public static class PathKeyDeserializer extends com.fasterxml.jackson.databind.KeyDeserializer {
- @Override
- public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
- if (key == null || key.isEmpty()) {
- return null;
- }
-
- // Handle case where old serialized data might still have file:/ prefix
- if (key.startsWith("file:/")) {
- key = key.substring(6); // Remove "file:/" prefix
- }
-
- return Paths.get(key);
- }
- }
-
- // Helper method to create ObjectMapper with Path serialization support
- private static ObjectMapper createObjectMapperWithPathSupport(Class> baseType) {
- PolymorphicTypeValidator ptv =
- BasicPolymorphicTypeValidator.builder().allowIfBaseType(baseType).build();
-
- SimpleModule pathModule = new SimpleModule();
- pathModule.addSerializer(Path.class, new PathSerializer());
- pathModule.addDeserializer(Path.class, new PathDeserializer());
- pathModule.addKeyDeserializer(Path.class, new PathKeyDeserializer());
-
- return JsonMapper.builder()
- .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true)
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
- .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
- .addModule(pathModule)
- .build();
- }
-
public static void serialize(Path path, T object) throws IOException {
serialize(path, object, true);
}
public static String serializeToString(T object) throws IOException {
- ObjectMapper objectMapper = createObjectMapperWithPathSupport(object.getClass());
+ PolymorphicTypeValidator ptv =
+ BasicPolymorphicTypeValidator.builder().allowIfBaseType(object.getClass()).build();
+ ObjectMapper objectMapper =
+ JsonMapper.builder()
+ .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
+ .build();
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
}
public static void serialize(Path path, T object, boolean forceSync) throws IOException {
- ObjectMapper objectMapper = createObjectMapperWithPathSupport(object.getClass());
+ PolymorphicTypeValidator ptv =
+ BasicPolymorphicTypeValidator.builder().allowIfBaseType(object.getClass()).build();
+ ObjectMapper objectMapper =
+ JsonMapper.builder()
+ .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
+ .build();
String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
saveJsonString(json, path, forceSync);
}
public static T deserialize(Map, ?> s, Class ref) throws IOException {
- ObjectMapper objectMapper = createObjectMapperWithPathSupport(ref);
+ PolymorphicTypeValidator ptv =
+ BasicPolymorphicTypeValidator.builder().allowIfBaseType(ref).build();
+ ObjectMapper objectMapper =
+ JsonMapper.builder()
+ .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
+ .build();
+
return objectMapper.convertValue(s, ref);
}
@@ -136,14 +81,28 @@ public static T deserialize(String s, Class ref) throws IOException {
throw new EofException("Provided empty string for class " + ref.getName());
}
- ObjectMapper objectMapper = createObjectMapperWithPathSupport(ref);
- objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
+ PolymorphicTypeValidator ptv =
+ BasicPolymorphicTypeValidator.builder().allowIfBaseType(ref).build();
+ ObjectMapper objectMapper =
+ JsonMapper.builder()
+ .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
+ .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
+ .build();
return objectMapper.readValue(s, ref);
}
public static T deserialize(Path path, Class ref) throws IOException {
- ObjectMapper objectMapper = createObjectMapperWithPathSupport(ref);
+ PolymorphicTypeValidator ptv =
+ BasicPolymorphicTypeValidator.builder().allowIfBaseType(ref).build();
+ ObjectMapper objectMapper =
+ JsonMapper.builder()
+ .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
+ .build();
File jsonFile = new File(path.toString());
if (jsonFile.exists() && jsonFile.length() > 0) {
return objectMapper.readValue(jsonFile, ref);
@@ -156,12 +115,6 @@ public static T deserialize(Path path, Class ref, StdDeserializer dese
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(ref, deserializer);
-
- // Add Path support to custom deserializer case as well
- module.addSerializer(Path.class, new PathSerializer());
- module.addDeserializer(Path.class, new PathDeserializer());
- module.addKeyDeserializer(Path.class, new PathKeyDeserializer());
-
objectMapper.registerModule(module);
File jsonFile = new File(path.toString());
@@ -182,12 +135,6 @@ public static void serialize(
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(ref, serializer);
-
- // Add Path support to custom serializer case as well
- module.addSerializer(Path.class, new PathSerializer());
- module.addDeserializer(Path.class, new PathDeserializer());
- module.addKeyDeserializer(Path.class, new PathKeyDeserializer());
-
objectMapper.registerModule(module);
String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
saveJsonString(json, path, forceSync);
diff --git a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java
index b655cb6566..a462154625 100644
--- a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java
+++ b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java
@@ -850,33 +850,30 @@ public static void onBulkImportObjectDetectionModelRequest(Context ctx) {
}
}
- private record DeleteObjectDetectionModelRequest(String modelPath) {}
+ private record DeleteObjectDetectionModelRequest(Path modelPath) {}
public static void onDeleteObjectDetectionModelRequest(Context ctx) {
logger.info("Deleting object detection model");
- Path modelPath;
try {
DeleteObjectDetectionModelRequest request =
JacksonUtils.deserialize(ctx.body(), DeleteObjectDetectionModelRequest.class);
- modelPath = Path.of(request.modelPath.substring(7));
-
- if (modelPath == null) {
+ if (request.modelPath == null) {
ctx.status(400);
ctx.result("The provided model path was malformed");
logger.error("The provided model path was malformed");
return;
}
- if (!modelPath.toFile().exists()) {
+ if (!request.modelPath.toFile().exists()) {
ctx.status(400);
ctx.result("The provided model path does not exist");
logger.error("The provided model path does not exist");
return;
}
- if (!modelPath.toFile().delete()) {
+ if (!request.modelPath.toFile().delete()) {
ctx.status(500);
ctx.result("Unable to delete the model file");
logger.error("Unable to delete the model file");
@@ -886,7 +883,7 @@ public static void onDeleteObjectDetectionModelRequest(Context ctx) {
if (!ConfigManager.getInstance()
.getConfig()
.neuralNetworkPropertyManager()
- .removeModel(modelPath)) {
+ .removeModel(request.modelPath)) {
ctx.status(400);
ctx.result("The model's information was not found in the config");
logger.error("The model's information was not found in the config");
@@ -910,26 +907,24 @@ public static void onDeleteObjectDetectionModelRequest(Context ctx) {
UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig())));
}
- private record RenameObjectDetectionModelRequest(String modelPath, String newName) {}
+ private record RenameObjectDetectionModelRequest(Path modelPath, String newName) {}
public static void onRenameObjectDetectionModelRequest(Context ctx) {
try {
RenameObjectDetectionModelRequest request =
JacksonUtils.deserialize(ctx.body(), RenameObjectDetectionModelRequest.class);
- Path modelPath = Path.of(request.modelPath);
-
- if (modelPath == null) {
+ if (request.modelPath == null) {
ctx.status(400);
ctx.result("The provided model path was malformed");
logger.error("The provided model path was malformed");
return;
}
- if (!modelPath.toFile().exists()) {
+ if (!request.modelPath.toFile().exists()) {
ctx.status(400);
ctx.result("The provided model path does not exist");
- logger.error("The model path: " + modelPath + " does not exist");
+ logger.error("The model path: " + request.modelPath + " does not exist");
return;
}
@@ -943,7 +938,7 @@ public static void onRenameObjectDetectionModelRequest(Context ctx) {
if (!ConfigManager.getInstance()
.getConfig()
.neuralNetworkPropertyManager()
- .renameModel(modelPath, request.newName)) {
+ .renameModel(request.modelPath, request.newName)) {
ctx.status(400);
ctx.result("The model's information was not found in the config");
logger.error("The model's information was not found in the config");