Hammerbot
Hammerbot

Reputation: 16364

Write a semi-custom deserializer

I would like to write a Custom Deserialization component that would still use some of the default capabilities:

Imagine those classes:

class Category {
    private Long id;
    private String name;
}

class Article {
    private Long id;
    private String title;
    private Category category;
}

And this JSON payload:

{
  "id": 1,
  "title": "Pray for Notre Dame",
  "category_id": 5
}

With my understanding of the various articles I read online, I should write a custom deserializer to handle my category_id field:

@JsonComponent
public class ArticleJsonDeserializer extends JsonDeserializer<Article> {

    @Override
    public Article deserialize(JsonParser jsonParser, 
      DeserializationContext deserializationContext) throws IOException, 
      JsonProcessingException {

        TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
        TextNode category = this.entityManager.getReference(Category.class, treeNode.get("category_id"));

        // The following lines bother me
        String title = treeNode.get("title");
        Long id = treeNode.get("id");

        return new Article(id, title, category);
    }
}

However, in reality, I would love to use the default deserializer capabilities for the title and id fields without rewriting this logic.

How can I do that?

Upvotes: 1

Views: 85

Answers (1)

cassiomolin
cassiomolin

Reputation: 131117

Short answer

Assuming that you have a default constructor in the Article class, the following should work:

Article article = jsonParser.getCodec().treeToValue(treeNode, Article.class);

Then set the category in the article.

A bit longer answer

Well... I think you are cutting corners and going beyond of what custom deserializers are meant for. You probably don't want to create couplings like that.

Alternatively, you could use @JsonIdentityInfo along with an ObjectIdResolver. You could get some ideas from the approach described in this answer.

Instead of exposing your JPA entities in your web API, you could using consider DTOs. See the reasons I described in my previous answer for reference. And then you could have a mapping layer to map your entities to your DTOs and vice versa. If you are using MapStruct, for example, the documentation shows an example on how to resolve entities by their id.

Upvotes: 1

Related Questions