forked from nus-cs2103-AY1920S1/addressbook-level3
-
Notifications
You must be signed in to change notification settings - Fork 5
/
JsonUtil.java
201 lines (167 loc) · 7.98 KB
/
JsonUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package seedu.address.commons.util;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.exceptions.DataConversionException;
/**
* Converts a Java object instance to JSON and vice versa
*/
public class JsonUtil {
private static final Logger logger = LogsCenter.getLogger(JsonUtil.class);
private static ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules()
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.registerModule(new SimpleModule("SimpleModule")
.addSerializer(Level.class, new ToStringSerializer())
.addDeserializer(Level.class, new LevelDeserializer(Level.class)));
static <T> void serializeObjectToEncryptedJsonFile(Path jsonFile, T objectToSerialize, String password)
throws IOException {
FileUtil.writeToEncryptedFile(jsonFile, toJsonString(objectToSerialize), password);
}
static <T> T deserializeObjectFromEncryptedJsonFile(Path jsonFile,
Class<T> classOfObjectToDeserialize,
String password)
throws IOException {
return fromJsonString(FileUtil.readFromEncryptedFile(jsonFile, password), classOfObjectToDeserialize);
}
static <T> void serializeObjectToJsonFile(Path jsonFile, T objectToSerialize) throws IOException {
FileUtil.writeToFile(jsonFile, toJsonString(objectToSerialize));
}
static <T> T deserializeObjectFromJsonFile(Path jsonFile, Class<T> classOfObjectToDeserialize)
throws IOException {
return fromJsonString(FileUtil.readFromFile(jsonFile), classOfObjectToDeserialize);
}
/**
* Returns the Json object from the given encrypted file or {@code Optional.empty()} object if the file is not
* found. If any values are missing from the file, default values will be used, as long as the file is a valid
* json file.
* @param filePath cannot be null.
* @param classOfObjectToDeserialize Json file has to correspond to the structure in the class given here.
* @param password used to decrypt the Json file.
* @throws DataConversionException if the file format is not as expected.
*/
public static <T> Optional<T> readEncryptedJsonFile(
Path filePath, Class<T> classOfObjectToDeserialize, String password) throws DataConversionException {
requireNonNull(filePath);
if (!Files.exists(filePath)) {
logger.info("Json file " + filePath + " not found");
return Optional.empty();
}
T jsonFile;
try {
jsonFile = deserializeObjectFromEncryptedJsonFile(filePath, classOfObjectToDeserialize, password);
} catch (IOException e) {
logger.warning("Error reading from jsonFile file " + filePath + ": " + e);
throw new DataConversionException(e);
}
return Optional.of(jsonFile);
}
/**
* Returns the Json object from the given file or {@code Optional.empty()} object if the file is not found.
* If any values are missing from the file, default values will be used, as long as the file is a valid json file.
* @param filePath cannot be null.
* @param classOfObjectToDeserialize Json file has to correspond to the structure in the class given here.
* @throws DataConversionException if the file format is not as expected.
*/
public static <T> Optional<T> readJsonFile(
Path filePath, Class<T> classOfObjectToDeserialize) throws DataConversionException {
requireNonNull(filePath);
if (!Files.exists(filePath)) {
logger.info("Json file " + filePath + " not found");
return Optional.empty();
}
T jsonFile;
try {
jsonFile = deserializeObjectFromJsonFile(filePath, classOfObjectToDeserialize);
} catch (IOException e) {
logger.warning("Error reading from jsonFile file " + filePath + ": " + e);
throw new DataConversionException(e);
}
return Optional.of(jsonFile);
}
/**
* Encrypts and saves the Json object to the specified file.
* Overwrites existing file if it exists, creates a new file if it doesn't.
* @param jsonFile cannot be null
* @param filePath cannot be null
* @param password used to encrypt the file
* @throws IOException if there was an error during writing to the file
*/
public static <T> void saveEncryptedJsonFile(T jsonFile, Path filePath, String password) throws IOException {
requireNonNull(filePath);
requireNonNull(jsonFile);
requireNonNull(password);
serializeObjectToEncryptedJsonFile(filePath, jsonFile, password);
}
/**
* Saves the Json object to the specified file.
* Overwrites existing file if it exists, creates a new file if it doesn't.
* @param jsonFile cannot be null
* @param filePath cannot be null
* @throws IOException if there was an error during writing to the file
*/
public static <T> void saveJsonFile(T jsonFile, Path filePath) throws IOException {
requireNonNull(filePath);
requireNonNull(jsonFile);
serializeObjectToJsonFile(filePath, jsonFile);
}
/**
* Converts a given string representation of a JSON data to instance of a class
* @param <T> The generic type to create an instance of
* @return The instance of T with the specified values in the JSON string
*/
public static <T> T fromJsonString(String json, Class<T> instanceClass) throws IOException {
return objectMapper.readValue(json, instanceClass);
}
/**
* Converts a given instance of a class into its JSON data string representation
* @param instance The T object to be converted into the JSON string
* @param <T> The generic type to create an instance of
* @return JSON data representation of the given class instance, in string
*/
public static <T> String toJsonString(T instance) throws JsonProcessingException {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(instance);
}
/**
* Contains methods that retrieve logging level from serialized string.
*/
private static class LevelDeserializer extends FromStringDeserializer<Level> {
protected LevelDeserializer(Class<?> vc) {
super(vc);
}
@Override
protected Level _deserialize(String value, DeserializationContext ctxt) {
return getLoggingLevel(value);
}
/**
* Gets the logging level that matches loggingLevelString
* <p>
* Returns null if there are no matches
*
*/
private Level getLoggingLevel(String loggingLevelString) {
return Level.parse(loggingLevelString);
}
@Override
public Class<Level> handledType() {
return Level.class;
}
}
}