知識庫 / Spring RSS 訂閱

Jackson JSON Views

Data,Jackson,Spring
HongKong
15
10:03 PM · Dec 05 ,2025

1. 概述

在本教程中,我們將介紹如何使用 Jackson JSON Views 對對象進行序列化/反序列化,自定義視圖,以及最終如何將其集成到 Spring 中。

2. 使用 JSON 視圖進行序列化

首先,我們通過一個簡單的例子來演示 – 使用 @JsonView 序列化一個對象。

以下是我們的視圖:

public class Views {
    public static class Public {
    }
}

以及“”實體:

public class User {
    public int id;

    @JsonView(Views.Public.class)
    public String name;
}

現在讓我們使用我們的視圖序列化一個“User”實例:

@Test
public void whenUseJsonViewToSerialize_thenCorrect() 
  throws JsonProcessingException {
 
    User user = new User(1, "John");

    ObjectMapper mapper = new ObjectMapper();
    mapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);

    String result = mapper
      .writerWithView(Views.Public.class)
      .writeValueAsString(user);

    assertThat(result, containsString("John"));
    assertThat(result, not(containsString("1")));
}

請注意,由於我們採用特定視圖進行序列化,因此我們只看到僅序列化正確的字段

此外,還應理解,默認情況下,未明確標記為視圖的一部分的所有屬性都會被序列化。我們使用便捷的DEFAULT_VIEW_INCLUSION功能來禁用此行為。

3. 使用多個JSON視圖

接下來,讓我們看看如何使用多個JSON視圖,每個視圖都有不同的字段,如以下示例所示:

這裏有兩個視圖,Internal 擴展了 Public,內部視圖擴展了公共視圖:

public class Views {
    public static class Public {
    }

    public static class Internal extends Public {
    }
}

以下是我們的實體“Item”,僅包含 idname 字段在 Public 視圖中:

public class Item {
 
    @JsonView(Views.Public.class)
    public int id;

    @JsonView(Views.Public.class)
    public String itemName;

    @JsonView(Views.Internal.class)
    public String ownerName;
}

如果使用 Public 視圖進行序列化,則只會將 idname 序列化到 JSON 中:

@Test
public void whenUsePublicView_thenOnlyPublicSerialized() 
  throws JsonProcessingException {
 
    Item item = new Item(2, "book", "John");

    ObjectMapper mapper = new ObjectMapper();
    String result = mapper
      .writerWithView(Views.Public.class)
      .writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("2"));

    assertThat(result, not(containsString("John")));
}

如果使用 內部視圖進行序列化,則所有字段都將包含在 JSON 輸出中:

@Test
public void whenUseInternalView_thenAllSerialized() 
  throws JsonProcessingException {
 
    Item item = new Item(2, "book", "John");

    ObjectMapper mapper = new ObjectMapper();
    String result = mapper
      .writerWithView(Views.Internal.class)
      .writeValueAsString(item);

    assertThat(result, containsString("book"));
    assertThat(result, containsString("2"));

    assertThat(result, containsString("John"));
}

4. 使用 JSON 視圖進行反序列化

現在,讓我們看看如何使用 JSON 視圖來反序列化對象——特別是,一個 User 實例:

@Test
public void whenUseJsonViewToDeserialize_thenCorrect() 
  throws IOException {
    String json = "{"id":1,"name":"John"}";

    ObjectMapper mapper = new ObjectMapper();
    User user = mapper
      .readerWithView(Views.Public.class)
      .forType(User.class)
      .readValue(json);

    assertEquals(1, user.getId());
    assertEquals("John", user.getName());
}

請注意我們如何使用 readerWithView() API 創建一個 ObjectReader,並使用提供的視圖。

5. 定製 JSON 視圖

接下來,讓我們看看如何定製 JSON 視圖。在下一個示例中,我們希望在序列化結果中將 User 的 “name” 轉換為大寫。

我們將使用 BeanPropertyWriterBeanSerializerModifier 來定製我們的 JSON 視圖。首先,這裏是 BeanPropertyWriterUpperCasingWriter,用於將 Username 轉換為大寫:

public class UpperCasingWriter extends BeanPropertyWriter {
    BeanPropertyWriter _writer;

    public UpperCasingWriter(BeanPropertyWriter w) {
        super(w);
        _writer = w;
    }

    @Override
    public void serializeAsField(Object bean, JsonGenerator gen, 
      SerializerProvider prov) throws Exception {
        String value = ((User) bean).name;
        value = (value == null) ? "" : value.toUpperCase();
        gen.writeStringField("name", value);
    }
}

以下是 BeanSerializerModifier,用於將 User 名稱設置為 BeanPropertyWriter,並使用自定義的 UpperCasingWriter

public class MyBeanSerializerModifier extends BeanSerializerModifier{

    @Override
    public List<BeanPropertyWriter> changeProperties(
      SerializationConfig config, BeanDescription beanDesc, 
      List<BeanPropertyWriter> beanProperties) {
        for (int i = 0; i < beanProperties.size(); i++) {
            BeanPropertyWriter writer = beanProperties.get(i);
            if (writer.getName() == "name") {
                beanProperties.set(i, new UpperCasingWriter(writer));
            }
        }
        return beanProperties;
    }
}

現在,讓我們使用修改後的序列化器序列化一個 User 實例:

@Test
public void whenUseCustomJsonViewToSerialize_thenCorrect() 
  throws JsonProcessingException {
    User user = new User(1, "John");
    SerializerFactory serializerFactory = BeanSerializerFactory.instance
      .withSerializerModifier(new MyBeanSerializerModifier());

    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializerFactory(serializerFactory);

    String result = mapper
      .writerWithView(Views.Public.class)
      .writeValueAsString(user);

    assertThat(result, containsString("JOHN"));
    assertThat(result, containsString("1"));
}

6. 使用 JSON 視圖與 Spring

最後,讓我們快速瞭解一下如何使用 JSON 視圖與 Spring Framework 結合使用。我們可以利用 @JsonView 註解在 API 級別自定義 JSON 響應。

在下面的示例中,我們使用了 Public 視圖來響應:

@JsonView(Views.Public.class)
@RequestMapping("/items/{id}")
public Item getItemPublic(@PathVariable int id) {
    return ItemManager.getById(id);
}

響應如下:

{"id":2,"itemName":"book"}

當我們使用內部視圖如下所示:

@JsonView(Views.Internal.class)
@RequestMapping("/items/internal/{id}")
public Item getItemInternal(@PathVariable int id) {
    return ItemManager.getById(id);
}

這是響應:

{"id":2,"itemName":"book","ownerName":"John"}

如果您想更深入地瞭解使用 Spring 4.1 中的視圖,您應該查看 Spring 4.1 中 Jackson 改進

7. 結論

在本快速教程中,我們探討了 Jackson JSON 視圖以及 @JsonView 註解。我們演示瞭如何使用 JSON 視圖對我們的序列化/反序列化過程進行精細控制——通過單個或多個視圖。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.