How to map JSON collections using JPA and Hibernate

(Last Updated On: February 2, 2018)
Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly. Hypersistence Optimizer is that tool!


The open-source hibernate-types project allows you to map Java objects or Jackson JsonNode as JPA or Hibernate entity properties, and, thanks to our awesome contributors, we have added support for storing type-safe JSON collections.

In this article, you are going to see how to achieve this goal.

Maven dependency

First of all, you need to set up the following Maven dependency in your project pom.xml configuration file:


If you’re using older versions of Hibernate, check out the hibernate-types GitHub repository for more info about the matching dependency for your current Hibernate version.

Domain Model

Let’s assume we have the following Location Java object type.

public class Location implements Serializable {

    private String country;

    private String city;

    //Getters and setters omitted for brevity

    public String toString() {
        return "Location{" +
                "country='" + country + ''' +
                ", city='" + city + ''' +

And, one Event entity:

@Entity(name = "Event")
@Table(name = "event")
public class Event extends BaseEntity {

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private Location location;

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private List<Location> alternativeLocations = new ArrayList<Location>();

    //Getters and setters omitted for brevity

The BaseEntity defines some basic properties (e.g. @Id, @Version) and several custom Hibernate types, among which, we are interested in the JsonBinaryType one.

    @TypeDef(name = "string-array", typeClass = StringArrayType.class),
    @TypeDef(name = "int-array", typeClass = IntArrayType.class),
    @TypeDef(name = "json", typeClass = JsonStringType.class),
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
    @TypeDef(name = "jsonb-node", typeClass = JsonNodeBinaryType.class),
    @TypeDef(name = "json-node", typeClass = JsonNodeStringType.class),
public class BaseEntity {

    private Long id;

    private Integer version;

    //Getters and setters omitted for brevity

For more details about using @MappedSuperclass, check out this article.

To store both the Location object or the List<Location> in a jsonb PostgreSQL column, we just need to annotate the location property with @Type(type = "jsonb").

That’s it!

Testing time

When saving the following Event entity:

Location cluj = new Location();

Location newYork = new Location();

Location london = new Location();

Event event = new Event();
    Arrays.asList(newYork, london)


Hibernate will generate the following SQL INSERT statement:


Also, when retrieving back the Event entity, both the location and thealternativeLocations` properties are properly fetched:

Event event = entityManager.find(Event.class, eventId);


assertEquals(2, event.getAlternativeLocations().size());


Cool, right?

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.


The hibernate-types project supports more than JSON types. You can map PostgreSQL ARRAY types or PostgreSQL-specific Enums, nullable Character, or even provide your own immutable Hibernate custom Types.

Download free ebook sample

Newsletter logo
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence,
  • a 10% discount coupon for my book.

38 Comments on “How to map JSON collections using JPA and Hibernate

  1. Hi Vlad,
    Some questions.
    Is it possible to use @OneToMany instead of @Column for List alternativeLocations?
    Can I write HQL query for fields within the Locations? Say pull all events held in specific city?

    • The answer is no and no. Associations and entity queries are one thing while basic properties and DB-specific querying capabilities are another thing.

  2. How might this work with nested Json objects? Do you create more than one object for serialization? For example:
    “item”: {
    “thing”: [“something”],
    “thing2”: [“something”, “something else”]
    “item2”: {



    • If the JSON is valid, it work any way you want to map it on the Java side. Use String or JsonNode if you have a flexible JSON schema.

    • It’s a DTO that you might want to transfer between systems, hence it’s good practice to make it Serializable. But it’s not mandatory.

  3. Hi Vlad,

    It works great and thanks for starting this initiative.
    Is it possible to do away with hibernate specific annotations and use only JPA specific ones instead? Thanks!

    • No, that’s not possible. But why would you do that? Did you ever heard of anyone switching from Hibernate to some other JPA provider? I personally never heard of it.

      • I agree to some extent, but then why does JPA exists ? 🙂

      • For the same reason the SQL standard exists. However, that does not prevent you from using database-specific query features when dealing with performance issues.

  4. Hi vlad,

    I think there might be an issue when using this with envers. When i retrieve my entity using the entitymanager it maps the jsonb list to an ArrayList of the generic type. But when i retrieve my audit entity by using the AuditReader class (created from the same entitymanager), my jsonb list suddenly becomes an ArrayList.

    The only cause for this i can think of is that the name of the versions entity is the same as the name of the entity being audited, but it ends with _AUD.

    This issue occurs for met with hibernate 5.2 and version 2.3.5 of hibernate-types-52

    • The hibernate-types framework is designed for Hibernate ORM only. If it does not work with Envers, then a Jira issue has to be created for the Hibernate Envers project.

      • I looked into this a bit deeper, and this worked with version 1.2.0, where I was able to define a type reference factory class using the parameter “com.vladmihalcea.hibernate.type.json.TypeReferenceFactory.class”.

        For envers it seems that the “org.hibernate.type.ParameterType.xproperty” parameter is not passed to the JsonTypeDescriptor setParameterValues method. I was wondering if this was something that I could work around, or if this is a bug in envers that should be reported and fixed?

      • The TypeReferenceFactory was too complicated for generic usage, so version 2.x of the hibernate-types project simplified that via XProperty. You need to investigate it further and see why it does not work, and provide a Pull Request with a fix. Looking forward to your contribution.

  5. Using same above flow i created a project,

    Its giving me this error:
    “java.util.ArrayList cannot be cast to com.fasterxml.jackson.databind.JsonNode”

    for this column: private List alternativeLocations = new ArrayList()

    on save method call.

    Anything which i may be missing ? (or done wrong)

  6. Hello vlad, thanks for the excellent article. I am able to insert json objects but not an array of json objects. The entity class is as below :-

    public class Sales extends BaseEntity implements Serializable {
    @Type(type = “jsonb”)
    @Column(columnDefinition = “jsonb”, name = “sales_target”)
    private List salesTargetList = new ArrayList();

    The SalesTarget entity is as below:-

    public class SalesTarget implements Serializable {
    private static final long serialVersionUID = 1L;

    private String teamLeader;
    private int salesVolume;


    Only blank data is getting submitted. The structure of json array should be as follows :-

    {teamLeader: “Rick”, salesVolume: 530 } , {teamLeader: “Jeff”, salesVolume: 640 } ,

  7. “message”: “Property: ‘notificationTypes’ not found in Class: class$EventVoBuilder”,

    getting this error while trying to insert in postgres via postman..followed the steps in this article..
    but record is getting inserted in the table..

  8. I solved it! Wildfly(or jboss) provide hibernate. And I don’t know why, he search hibernate in the deployed ear, where doesn’t can be.

    I changed my ear’s pom in the “maven-ear-plugin.configuration.archive” section.



    • Great! so did you included all the Hibernate libraries in the EAR ? or just the org.hibernate.commons-annotations jar ?

    • No! Just wildfly searched it there.

      I changed my ear’s pom in the “maven-ear-plugin.configuration.archive” section.


    • What exactly did you change in your EAR pom.xml? I’m having this exact same problem with Wildfly.

    • Nevermind! I was able to solve the problem by changing my jboss-deployment-structure.xml to the following:

    • Ahh yes, can’t post XML. Anyways, I added “org.hibernate.commons-annotations” as a module dependency to jboss-deployment-structure.xml

  9. Hi Vlad, I’m experiencing the same problem of Joao and André when deploying on JBoss EAP 7, which ships the following Hibernate versions:


    In my pom I just added the dependency:


    but at deployment time it complains about a missing class from hibernate-commons-annotations:

    Caused by: java.lang.NoClassDefFoundError: org/hibernate/annotations/common/reflection/XProperty
    at com.vladmihalcea.hibernate.type.json.internal.JsonTypeDescriptor.setParameterValues(
    at com.vladmihalcea.hibernate.type.json.JsonBinaryType.setParameterValues(
    at org.hibernate.type.TypeFactory.injectParameters(

    The class is indeed present in the jar provided by JBoss but it looks like the ModuleClassLoader is not able to find it.

    Can you give me some hint about how to overcome this problem?

    Thanks al ot

    • I’m not familiar with JBoss and Wildfly modules, so you need to ask the question on the JBoss forum. They will surely know how to sort it out.

  10. I’m having the same problem.
    And having hibernate-commons-annotations on classpath resulted in
    java.lang.ClassCastException: cannot be cast to org.hibernate.annotations.common.reflection.XProperty

  11. Is it possible to store the JSon column value as “String”? I am getting error

    Schema-validation: wrong column type encountered in column [VALIDATION_ADDITIONAL_ATTRIBUTES] in table [FI_FILE_VALIDATION_T]; found [json (Types#OTHER)], but expecting [varchar(255) (Types#VARCHAR)]

    My Entity is like followoing

    @Table(name=”FI_FILE_VALIDATION_T”, schema=”XXX”)

    @TypeDef(name = “json”, typeClass = JsonStringType.class),
    @TypeDef(name = “jsonb”, typeClass = JsonBinaryType.class),
    @TypeDef(name = “jsonb-node”, typeClass = JsonNodeBinaryType.class),
    @TypeDef(name = “json-node”, typeClass = JsonNodeStringType.class),
    public class FIFileValidation implements Serializable{

    private Map<String,String> validationAdditionalAttributes;



    • The json and jsob types are for storing data in JSON column types. If you need to store the JSON in a VARCHAR, just use a String entity property and it will work even without the hibernate-types project.

  12. Hi Vlad,

    I’m trying your library (hibernate-types) and faced with the issue. Can you please help.
    Project details:
    Spring 4.3.10, Hibernate 5.2.5, hibernate-types-52 2.2.3, connection pool – c3p0, jackson 2.3.2.
    Jboss 7, MsSql, jdk8

    Java model:
    BaseEntity – copy from the article.

    @Table(name = “B_BOOK”)
    public class Book extends BaseEntity {
    private String title;
    private String author;

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    private Details details;


    public class Details implements Serializable {
    private String details;
    public String toString() { return “Details{details=’” + details + “\’}”; }

    With GET request I get properly created Book with Details.
    With POST request without Details object I get Book saved in DB.
    With POST request with Details object I get exception: The conversion from UNKNOWN to OTHER is unsupported.

    What was done wrongly?

    Thanks in advance,

    • I never tested it with SQL Server. You need to see if String or Binary work better, and supply a Pull Request with a new type if the existing ones don’t work. Looking forward to your contribution.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Want to run your data access layer at warp speed?