Jackson JSON 視圖

Data,Jackson,Spring
Remote
1
12:57 AM · Dec 01 ,2025

1. 概述

在本教程中,我們將介紹如何使用 Jackson JSON Views 來序列化/反序列化對象、自定義視圖,以及最後 – 如何與 Spring 集成。

2. 使用 JSON Views 進行序列化

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

這是我們的視圖:

public class Views {
    public static class Public {
    }
}

以及“User”實體:

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")));
}

但是,如果我們使用Internal視圖進行序列化,則所有字段都將包含在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,用於將 Username 與我們的自定義 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"}

當使用 Internal 視圖時,如下所示:

@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.