【问题标题】:Serializing List<Item> to JSON with custom fields使用自定义字段将 List<Item> 序列化为 JSON
【发布时间】:2014-03-21 14:55:10
【问题描述】:

我正在尝试使用 Spring MVC 创建一个简单的 REST API,它以 JSON 格式返回数据。

我正在研究一种返回作者列表的方法,该方法可从 example.com/api/authors?find=somename 访问

我有一个名为 Authors 的 JPA 实体。我有一个 @Service 获取 List&lt;Author&gt; 集合。 Author 实体具有属性,例如 id, firstName, lastName, birthDate

我想要实现的是我的 JSON 结果类似于:

{
    "data": [
        {
            "id": 1,
            "name": "Leo Tolstoi",
            "age": 49
        },
        {
            "id": 2,
            "name": "Billy Shakespeare",
            "age": 32
        }
    ]
}

如您所见,结果有 2 个字段不是直接来自实体,而是应该从 Author 实体的值生成。 name 字段是 author.getFirstName() + " " + author.getLastName()agesomeUtilityClass.calcAge(author.getBirthDate())

我正在尝试弄清楚如何使用 GSON 获得这种输出。

我能做的,是从服务类中获取数据并对其进行迭代,将每个迭代行保存到一个 Map(或其他东西,也许只是将每一行保存到像 List&lt;AuthorJson&gt; 实体这样的东西,它有像 @987654332 这样的字段@)。但是这种方法似乎不是很干净。

你们能提出任何解决方案吗?

【问题讨论】:

  • DTO 方法是合适的。否则使用TypeAdapter,但在这种情况下,您将业务逻辑放入序列化程序中,这是没有意义的,imo。
  • 那么好的方法是什么?将数据库结果 1:1 转换为 JSON 是一个非常糟糕的主意。它可能会破坏客户端的应用程序,因为字段名称可能会波动。并且数据库可能包含不适合公开曝光的值。例如。密码哈希、个人信息等
  • 编写一个 DTO 转换器并序列化生成的 DTO。
  • 那么按照我最初的方法进行吗?我查看了 DTO 的含义,似乎我提议的 AuthorJson 实体就是这样。它包含返回给定结果所需的属性。
  • 我就是这样做的。

标签: java json spring-mvc gson


【解决方案1】:

您应该为作者使用自定义序列化程序。

Documentation

由于您只需要一个序列化程序,因此这里有一个示例说明您可以做什么。请注意,大多数情况下年龄会相差一倍。

public static void main(String[] args) {
    GsonBuilder gBuild = new GsonBuilder();
    gBuild.registerTypeAdapter(Author.class, new AuthorSerializer());

    Author author = new Author();
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, 1988);
    cal.set(Calendar.MONTH, 1);
    cal.set(Calendar.DAY_OF_MONTH, 1);
    author.setBirthDate(cal);
    author.setFirstName("John");
    author.setLastName("Smith");

    Gson gson = gBuild.setPrettyPrinting().create();
    System.out.println(gson.toJson(author));
}

private static class AuthorSerializer implements JsonSerializer<Author> {
    @Override
    public JsonElement serialize(Author src, Type typeOfSrc, JsonSerializationContext context) {
        Calendar today = Calendar.getInstance();
        int age = today.get(Calendar.YEAR) - src.getBirthDate().get(Calendar.YEAR);
        String fullName = src.getFirstName() + " " + src.getLastName();
        JsonObject obj = new JsonObject();
        obj.addProperty("fullName", fullName);
        obj.addProperty("age", age);
        return obj;
    }
}

【讨论】:

  • 但我不需要反序列化我自己的 JSON 输出,它是为消费而制作的
  • 那你只做一个连载就可以了。通常你会同时制作一个序列化器和反序列化器。在内部,GSON 可能需要反序列化器或实例创建器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-19
  • 1970-01-01
相关资源
最近更新 更多