JSON (JavaScript Object Notation) — это легкий текстовый формат для обмена данными, который является простым для чтения и записи как человеком, так и машиной. Формат базируется на структуре объектов JavaScript и широко используется для передачи данных между клиентом и сервером в веб-приложениях. Его простота делает его одним из наиболее популярных форматов для хранения и передачи структурированной информации.
В процессе написания кода часто возникает необходимость обновления данных, хранящихся в формате JSON. Например, обновление конфигураций, добавление новых настроек, изменение пользовательских данных или сохранение результатов работы приложения.
Для работы с JSON в Java существует несколько популярных библиотек, среди которых чаще всего используются следующие: Jackson, Gson, Json.
В этой статье мы рассмотрим, как работать с JSON-файлами в Java, используя эти три библиотеки. Для этого мы будем читать JSON-файл, вносить в него изменения и записывать обновленные данные обратно в файл. Мы продемонстрируем два подхода: первый — это преобразование JSON в Java-класс, второй — внесение изменений непосредственно в JSON, без преобразования в классы. Независимо от выбранного подхода, все три библиотеки будут повторять эти основные шаги, но каждая из них будет использовать свои собственные методы.
Прежде чем перейти к практической части, рассмотрим пример JSON-файла, находящегося в директории resources/files, который мы будем использовать для демонстрации работы с данными.
{
"products": [
{
"productName": "Wireless Mouse",
"price": 25.99,
"features": [
{
"featureName": "Ergonomic Design",
"isAvailable": true
},
{
"featureName": "Rechargeable Battery",
"isAvailable": false
}
],
"brand": "TechCo",
"inStock": true
},
{
"productName": "Mechanical Keyboard",
"price": 79.99,
"features": [
{
"featureName": "RGB Backlight",
"isAvailable": true
},
{
"featureName": "Programmable Keys",
"isAvailable": true
}
],
"brand": "KeyMaster",
"inStock": false
}
]
}
Класс ProductCatalog
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductCatalog {
private List<Product> products;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Product {
private String productName;
private double price;
private List<Discount> discounts;
private String brand;
private boolean inStock;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Discount {
private String discountDescription;
private String expiryDate;
}
}
}
Gson
Основные методы, которые мы используем в работе с Gson, включают fromJson() для преобразования JSON в Java-объекты и toJson() для преобразования Java-объектов обратно в JSON. В первом примере мы покажем, как использовать Gson для преобразования JSON-файла в Java-класс и внесения изменений в него.
public class Main {
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/files/products.json";
Gson gson = new Gson();
// Чтение JSON-файла и преобразование его в Java-класс ProductCatalog
JsonObject jsonObject = gson.fromJson(new FileReader(filePath), JsonObject.class);
ProductCatalog productCatalog = gson.fromJson(jsonObject, ProductCatalog.class);
// Добавление новой скидки ко второму продукту
productCatalog.getProducts().get(1).getDiscounts().add(
new ProductCatalog.Product.Discount("Buy 1 Get 1 Free", "2024-12-15"));
// Запись обновленного Java-объекта обратно в JSON-файл
try (FileWriter writer = new FileWriter(filePath)) {
gson.toJson(productCatalog, writer);
}
}
}
Однако Gson также позволяет работать с JSON напрямую, без преобразования в Java-классы. Давайте рассмотрим, как это можно сделать.
public class Main {
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/files/products.json";
// Чтение JSON-файла с помощью Gson с помощью Gson
JsonElement jsonElement = JsonParser.parseReader(new FileReader(filePath));
JsonObject jsonObject = jsonElement.getAsJsonObject();
// Обновление данных
JsonArray productsArray = jsonObject.getAsJsonArray("products");
JsonObject secondProduct = productsArray.get(1).getAsJsonObject();
JsonArray discountsArray = secondProduct.getAsJsonArray("discounts");
JsonObject newDiscount = new JsonObject();
newDiscount.addProperty("discountDescription", "Buy 1 Get 1 Free");
newDiscount.addProperty("expiryDate", "2024-12-15");
discountsArray.add(newDiscount);
// Запись обновленного JSON обратно в файл
try (FileWriter writer = new FileWriter(filePath)) {
writer.write(jsonObject.toString());
}
}
}
Jackson
ObjectMapper это главный класс для работы с JSON в библиотеке Kackson, который предоставляет все необходимые методы для преобразования между JSON и Java-объектами и наоборот.
- readTree: Метод, позволяющий преобразовывать JSON в структуру JsonNode, которая предоставляет возможность гибко работать с JSON, не преобразуя его сразу в объект.
- treeToValue: Используется для преобразования структуры JsonNode в Java-объект.
- writeValue: Метод, позволяющий сериализировать Java-объект в JSON.
- readValue: Используется для десериализации JSON в Java-объект.
- writeValueAsString: Метод для преобразования Java-объекта в JSON-строку.
Эти методы позволяют легко работать с различными форматами данных, в частности JSON, и удобно преобразовывать их в объекты или наоборот.
Пример использования Jackson для считывания JSON-файла, преобразования его в Java-класс и внесения изменений:
public class Main {
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/files/products.json";
ObjectMapper mapper = new ObjectMapper();
// Чтение JSON-файла и преобразование его в Java-класс ProductCatalog
JsonNode rootNode = mapper.readTree(new File(filePath));
ProductCatalog productCatalog = mapper.treeToValue(rootNode, ProductCatalog.class);
// Внесение изменений в названии бренда первого продукта
productCatalog.getProducts().get(0).setBrand("New Brand Name");
// Запись обновленного Java-объекта обратно в JSON-файл
mapper.writeValue(new File(filePath), productCatalog);
}
}
Jackson также предоставляет возможность работать с JSON-данными напрямую, не преобразуя их в Java-классы. Рассмотрим пример, где мы работаем непосредственно с JSON-структурой, вносим необходимые изменения и записываем обновленные данные обратно в файл.
public class Main {
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/files/products.json";
ObjectMapper mapper = new ObjectMapper();
// Чтение JSON-файла и преобразование его в дерево JSON-объектов
JsonNode rootNode = mapper.readTree(new File(filePath));
// Получение массива продуктов из дерева JSON
ArrayNode productsArray = (ArrayNode) rootNode.get("products");
// Обновление названия бренда первого продукта
ObjectNode firstProduct = (ObjectNode) productsArray.get(0);
firstProduct.put("brand", "New Brand Name");
// Запись обновленного JSON обратно в файл
mapper.writeValue(new File(filePath), rootNode);
}
}
Json
Библиотека org.json не предоставляет возможностей автоматической сериализации и десериализации Java-объектов, как это делают Jackson или Gson. Поэтому при использовании org.json вам придется работать с данными вручную, что делает процесс менее удобным, но в то же время более контролируемым. В этом разделе мы рассмотрим два подхода: преобразование JSON-данных в Java-классы и работа с JSON напрямую.
При использовании org.json для преобразования JSON в Java-класс, вы должны вручную считывать JSON-данные, создавать соответствующие объекты и задавать их значения. Например, если мы хотим изменить значение поля price в нашем JSON, это может выглядеть следующим образом:
public class Main {
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/files/products.json";
// Чтение JSON-данных из файла
Path path = Path.of(filePath);
String jsonString = new String(Files.readAllBytes(path));
JSONObject jsonObject = new JSONObject(jsonString);
// Создание объекта ProductCatalog
ProductCatalog productCatalog = new ProductCatalog();
// Получение массива продуктов из JSON
JSONArray productsArray = jsonObject.getJSONArray("products");
// Цикл для преобразования каждого продукта из JSON в объект Product
for (int i = 0; i < productsArray.length(); i++) {
JSONObject productJson = productsArray.getJSONObject(i);
ProductCatalog.Product product = new ProductCatalog.Product();
product.setProductName(productJson.getString("productName"));
product.setPrice(productJson.getDouble("price"));
product.setBrand(productJson.getString("brand"));
// сеты других полей
// Добавление продукта в каталог
productCatalog.getProducts().add(product);
}
// Внесение изменений в поле price для первого продукта
if (!productCatalog.getProducts().isEmpty()) {
productCatalog.getProducts().get(0).setPrice(46.99);
}
// Запись обновленного JSON обратно в файл
for (int i = 0; i < productsArray.length(); i++) {
JSONObject productJson = productsArray.getJSONObject(i);
ProductCatalog.Product product = productCatalog.getProducts().get(i);
productJson.put("price", product.getPrice());
}
Files.write(path, jsonObject.toString(4).getBytes());
}
}
Другой подход — работать с JSON-данными напрямую, не преобразуя их в Java-классы. Это может быть полезно, когда вам нужно внести простые изменения в структуру JSON, например, изменить значение поля без создания дополнительных объектов:
public class Main {
public static void main(String[] args) throws IOException {
String filePath = "src/main/resources/files/products.json";
// Считывание JSON-данных из файла
String jsonString = new String(Files.readAllBytes(Paths.get(filePath)));
JSONObject jsonObject = new JSONObject(jsonString);
// Прямое внесение изменений в поле price для первого продукта
jsonObject.getJSONArray("products").getJSONObject(0).put("price", 35.99);
// Запись обновленного JSON обратно в файл
Files.write(Paths.get(filePath), jsonObject.toString(4).getBytes());
}
}
Заключение
Мы рассмотрели два основных подхода к работе с JSON-данными в Java. Первый подход заключается в преобразовании JSON в Java-объекты, а второй — в работе с JSON непосредственно, без использования объектов. Каждый из этих подходов имеет свои преимущества и недостатки, и выбор между ними зависит от конкретных требований вашего проекта.
Преобразование JSON в Java-объекты является более структурированным подходом, который особенно хорошо подходит для сложных проектов со стабильной структурой данных. Этот подход позволяет вам работать с JSON-данными как с типичными Java-объектами, что делает код более читабельным и удобным для поддержки.
С другой стороны, работа с JSON напрямую, без преобразования его в Java-объекты, может быть более гибкой и быстрой для реализации, особенно если речь идет о простых задачах или динамических JSON-структурах. Это уменьшает объем кода, поскольку вам не нужно создавать дополнительные классы. Однако, когда структура JSON становится сложной или имеет много уровней вложенности, код может стать менее понятным и трудным для поддержки. Кроме того, отсутствие типизации в этом подходе может привести к большему количеству ошибок, которые будет трудно обнаружить на этапе компиляции.
Выбор между Jackson, Gson и Json зависит от специфики вашего проекта. Если вам нужна максимальная гибкость и возможность работы со сложными структурами, Jackson будет лучшим выбором. Для быстрой и простой работы с JSON лучше подходит Gson. А для самых простых задач с минимальными требованиями к функциональности, Json может быть достаточно. В каждом случае, выбор инструмента зависит от ваших конкретных потребностей и требований проекта.
🤔 Остались вопросы о том, как обновить json-файл в Java? - смело задавайте ниже! 💬