我有两个主要的模型类:Customer
和 Product
public class Customer {
String name;
String surname;
int age;
BigDecimal cash;
}
public class Product {
String name;
Category category;
BigDecimal price;
}
我想用 json
构建 Map<Customer, List<Product>>
文件
当我使用我的方法正确写入 json
文件数据时 - 我确信这一点 - json
文件显示了这种语法
{
"Customer{name\u003d\u0027Custo1\u0027, surname\u003d\u0027Surname\u0027, age\u003d18, cash\u003d1200}": [
{
"name": "prod1",
"category": "CLOTHES",
"price": 12000
},
{
"name": "prod2",
"category": "ELECTRONIC",
"price": 15000
}
]
}
然后当我想读取这个文件时,出现错误 Exception in thread "main" java.util.NoSuchElementException: No value present
所以我认为 json 文件中的 Customer
语法无法识别。
因此,我尝试使用以下语法自行将数据写入 json
文件,但它不起作用
[
{
"name": "Abc",
"surname": "Def",
"age": 14,
"cash": "2000"
}
:
[
{
"name": "prod1",
"category": "CLOTHES",
"price": 12000
},
{
"name": "prod2",
"category": "ELECTRONIC",
"price": 15000
}
]
]
json 转换器方法:
public void toJson(final T item) {
try (FileWriter fileWriter = new FileWriter(jsonFilename)) {
fileWriter.write(gson.toJson(item));
} catch (Exception e) {
throw new ValidatorException(e.getMessage());
}
}
答案 0 :(得分:2)
@Tom 对您所面临的问题是正确的。我会解释原因并建议另一种解决方案。
您的第一个 JSON 在技术上是有效的 JSON,但无法反序列化,因为映射键是 Gson 默认使用的 Customer.toString()
方法的结果。这就是为什么它看起来很奇怪,就像一个调试字符串,并且不能反序列化:几乎总是无法从 toString()
结果中恢复对象(toString
主要用于调试/记录目的提供基本有关特定对象状态的信息,根本不需要公开其所有内部结构)。
您的第二个 JSON 是 invalid JSON。期间。
Tom 建议将产品列表作为客户类别的一部分是完全正确的。像这样实现它可以让您将所有内容序列化为这样的列表:
[
{
"name": "john",
"products": [
{"name": "prod1"},
{"name": "prod2"}
]
}
]
提示:分离域对象(Customer
和 Product
)和数据传输的表示对象(CustomerDto
和 ProductDto
)通常也是一个好主意,因为它允许为任何具体的表示实现创建表示(一个用于各种 JSON 实现库,两个用于面向其他格式的工具,第三个用于持久性,四个用于 UI 视图等),因此它的实现方式可能类似于将 Map<Customer, List<Product>>
转换为 { {1}} 并返回(可能使用 MapStruct 等映射器生成器)。
如果由于某种原因无法重新组织您的域类或创建 Gson 友好的 DTO 映射,或者您可以保持它尽可能简单并且您没有那种微不足道的 JSON 结构(只要您了解此解决方案中格式的含义:进化、分布等),那么您就可以启用特殊的 Gson 模式来支持这种地图。它生成可以序列化和反序列化的有效 JSON,但它的实现方式在我看来有点反模式,因为使用数组作为数据容器会丢失语义。
List<CustomerDto>
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class Customer {
final String name;
}
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class Product {
final String name;
}
注意它生成这样的 JSON(索引 public final class MapTest {
private static final Gson gson = new GsonBuilder()
.enableComplexMapKeySerialization()
.create();
private static final TypeToken<Map<Customer, List<Product>>> customerToProducts = new TypeToken<Map<Customer, List<Product>>>() {};
@Test
public void test() {
final Map<Customer, List<Product>> ordersBefore = ImmutableMap.of(
new Customer("john"), ImmutableList.of(new Product("prod1"), new Product("prod2"))
);
final String json = gson.toJson(ordersBefore, customerToProducts.getType());
Assertions.assertEquals("[[{\"name\":\"john\"},[{\"name\":\"prod1\"},{\"name\":\"prod2\"}]]]", json);
final Map<Customer, List<Product>> ordersAfter = gson.fromJson(json, customerToProducts.getType());
Assertions.assertEquals(ordersBefore, ordersAfter);
}
}
表示键,索引 0
表示值):
1