Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

Jackson Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
NPI – Spring Top – Temp – Non-Geo (Lightrun)

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING
NPI – Lightrun – Spring (partner)

We rely on other people’s code in our own work. Every day. It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.

The problem is, of course, when things fall apart in production - debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky. It’s difficult to understand what talks to what and, specifically, which part of the underlying library is at fault.

Lightrun is a new kind of debugger.

It's one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics. No hotfixes, redeployments, or restarts required.

Learn more in this quick, 5-minute Lightrun tutorial:

>> The Essential List of Spring Boot Annotations and Their Use Cases

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 Username” 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.
The complete code for this tutorial can be found over on GitHub.

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Jackson bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Jackson footer banner
Comments are closed on this article!