Jackson and JSON in Java, finally learn with a coding-first approach:
>> Download the eBookMocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Overview
In this tutorial, weβll go over how to use Jackson JSON Views to serialize/deserialize objects, customize the views and finally β how to start integrating with Spring.
2. Serialize Using JSON Views
First β letβs go through a simple example β serialize an object with @JsonView.
Here is our view:
public class Views {
public static class Public {
}
}
And the βUserβ entity:
public class User {
public int id;
@JsonView(Views.Public.class)
public String name;
}
Now letβs serialize a βUserβ instance using our view:
@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")));
}
Note how, because weβre serializing with a specific view active, weβre seeing only the right fields being serialized.
Itβs also important to understand, that β by default β all properties not explicitly marked as being part of a view, are serialized. We are disabling that behavior with the handy DEFAULT_VIEW_INCLUSION feature.
3. Use Multiple JSON Views
Next β letβs see how to use multiple JSON Views β each has different fields as in the following example:
Here we have to views where Internal extends Public, with the internal view extending the public one:
public class Views {
public static class Public {
}
public static class Internal extends Public {
}
}
And here is our entity βItemβ where only the fields id and name are included in the Public view:
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
If we use the Public view to serialize β only id and name will be serialized to 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")));
}
But if we use the Internal view to perform the serialization, all fields will be part of the JSON output:
@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. Deserialize Using JSON Views
Now β letβs see how to use JSON Views to deserialize objects β specifically, a User instance:
@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());
}
Note how weβre using the readerWithView() API to create an ObjectReader using the given view.
5. Customize JSON Views
Next β letβs see how to customize JSON Views. In the next example β we want to make the User βnameβ UpperCase in the serialization result.
We will use BeanPropertyWriter and BeanSerializerModifier to customize our JSON view. First β here is the BeanPropertyWriter UpperCasingWriter to transform the User name to upper case:
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);
}
}
And here is the BeanSerializerModifier to set the User name BeanPropertyWriter with our custom 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;
}
}
Now β letβs serialize a User instance using the modified Serializer:
@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. Using JSON Views With Spring
Finally β letβs take a quick look at using JSON views with the Spring Framework. We can leverage the @JsonView annotation to customize our JSON response at the API level.
In the following example β we used the Public view to respond:
@JsonView(Views.Public.class)
@RequestMapping("/items/{id}")
public Item getItemPublic(@PathVariable int id) {
return ItemManager.getById(id);
}
The response is:
{"id":2,"itemName":"book"}
And when we used the Internal view as follows:
@JsonView(Views.Internal.class)
@RequestMapping("/items/internal/{id}")
public Item getItemInternal(@PathVariable int id) {
return ItemManager.getById(id);
}
That was the response:
{"id":2,"itemName":"book","ownerName":"John"}
If you want to dive deeper into using the views with Spring 4.1, you should check out the Jackson improvements in Spring 4.1.
7. Conclusion
In this quick tutorial, we had a look at the Jackson JSON views and the @JsonView annotation. We showed how to use JSON Views to have fine-grained control over our serialize/deserialize process β using a single or multiple views.
