001/* 002 * Copyright (C) Photon Vision. 003 * 004 * This program is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package org.photonvision.common.util.file; 019 020import com.fasterxml.jackson.core.json.JsonReadFeature; 021import com.fasterxml.jackson.databind.DeserializationFeature; 022import com.fasterxml.jackson.databind.ObjectMapper; 023import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 024import com.fasterxml.jackson.databind.json.JsonMapper; 025import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; 026import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; 027import com.fasterxml.jackson.databind.module.SimpleModule; 028import com.fasterxml.jackson.databind.ser.std.StdSerializer; 029import java.io.File; 030import java.io.FileDescriptor; 031import java.io.FileOutputStream; 032import java.io.IOException; 033import java.nio.file.Path; 034import java.util.HashMap; 035import java.util.Map; 036import org.eclipse.jetty.io.EofException; 037 038public class JacksonUtils { 039 public static class UIMap extends HashMap<String, Object> {} 040 041 public static <T> void serialize(Path path, T object) throws IOException { 042 serialize(path, object, true); 043 } 044 045 public static <T> String serializeToString(T object) throws IOException { 046 PolymorphicTypeValidator ptv = 047 BasicPolymorphicTypeValidator.builder().allowIfBaseType(object.getClass()).build(); 048 ObjectMapper objectMapper = 049 JsonMapper.builder() 050 .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT) 051 .build(); 052 return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); 053 } 054 055 public static <T> void serialize(Path path, T object, boolean forceSync) throws IOException { 056 PolymorphicTypeValidator ptv = 057 BasicPolymorphicTypeValidator.builder().allowIfBaseType(object.getClass()).build(); 058 ObjectMapper objectMapper = 059 JsonMapper.builder() 060 .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT) 061 .build(); 062 String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); 063 saveJsonString(json, path, forceSync); 064 } 065 066 public static <T> T deserialize(Map<?, ?> s, Class<T> ref) throws IOException { 067 PolymorphicTypeValidator ptv = 068 BasicPolymorphicTypeValidator.builder().allowIfBaseType(ref).build(); 069 ObjectMapper objectMapper = 070 JsonMapper.builder() 071 .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true) 072 .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 073 .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT) 074 .build(); 075 076 return objectMapper.convertValue(s, ref); 077 } 078 079 public static <T> T deserialize(String s, Class<T> ref) throws IOException { 080 if (s.length() == 0) { 081 throw new EofException("Provided empty string for class " + ref.getName()); 082 } 083 084 PolymorphicTypeValidator ptv = 085 BasicPolymorphicTypeValidator.builder().allowIfBaseType(ref).build(); 086 ObjectMapper objectMapper = 087 JsonMapper.builder() 088 .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true) 089 .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 090 .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL) 091 .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT) 092 .build(); 093 094 return objectMapper.readValue(s, ref); 095 } 096 097 public static <T> T deserialize(Path path, Class<T> ref) throws IOException { 098 PolymorphicTypeValidator ptv = 099 BasicPolymorphicTypeValidator.builder().allowIfBaseType(ref).build(); 100 ObjectMapper objectMapper = 101 JsonMapper.builder() 102 .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true) 103 .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 104 .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT) 105 .build(); 106 File jsonFile = new File(path.toString()); 107 if (jsonFile.exists() && jsonFile.length() > 0) { 108 return objectMapper.readValue(jsonFile, ref); 109 } 110 return null; 111 } 112 113 public static <T> T deserialize(Path path, Class<T> ref, StdDeserializer<T> deserializer) 114 throws IOException { 115 ObjectMapper objectMapper = new ObjectMapper(); 116 SimpleModule module = new SimpleModule(); 117 module.addDeserializer(ref, deserializer); 118 objectMapper.registerModule(module); 119 120 File jsonFile = new File(path.toString()); 121 if (jsonFile.exists() && jsonFile.length() > 0) { 122 return objectMapper.readValue(jsonFile, ref); 123 } 124 return null; 125 } 126 127 public static <T> void serialize(Path path, T object, Class<T> ref, StdSerializer<T> serializer) 128 throws IOException { 129 serialize(path, object, ref, serializer, true); 130 } 131 132 public static <T> void serialize( 133 Path path, T object, Class<T> ref, StdSerializer<T> serializer, boolean forceSync) 134 throws IOException { 135 ObjectMapper objectMapper = new ObjectMapper(); 136 SimpleModule module = new SimpleModule(); 137 module.addSerializer(ref, serializer); 138 objectMapper.registerModule(module); 139 String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); 140 saveJsonString(json, path, forceSync); 141 } 142 143 private static void saveJsonString(String json, Path path, boolean forceSync) throws IOException { 144 var file = path.toFile(); 145 if (file.getParentFile() != null && !file.getParentFile().exists()) { 146 file.getParentFile().mkdirs(); 147 } 148 if (!file.exists()) { 149 if (!file.canWrite()) { 150 file.setWritable(true); 151 } 152 file.createNewFile(); 153 } 154 FileOutputStream fileOutputStream = new FileOutputStream(file); 155 fileOutputStream.write(json.getBytes()); 156 fileOutputStream.flush(); 157 if (forceSync) { 158 FileDescriptor fileDescriptor = fileOutputStream.getFD(); 159 fileDescriptor.sync(); 160 } 161 fileOutputStream.close(); 162 } 163}