sandeep
sandeep

Reputation: 3345

How to map Postgres JSON data type in DTO and Aggentity class using Springboot and Hibernate

I have a ResponseDto class which looks like as below:

public static class HealthGoalsHighlight {

    @ApiModelProperty(value = "Total number of eligible users")
    private Long totalEligibleUsers;
    @ApiModelProperty(value = "Total number of registered users")
    private Long totalRegisteredUsers;
    @ApiModelProperty(value = "Total number of users with atleast one goal count")
    private Long totalUsersWithGoal;
    @ApiModelProperty(value = "Top goal name selected by user")
    private String topGoal;
    @ApiModelProperty(value = "Bottom goal name selected by user")
    private String bottomGoal;
  }

This DTO was made based upon below table structure:

health_goals
(
  uid BIGSERIAL NOT NULL CONSTRAINT health_goals_pkey primary key,
  employer_key bigint not null,
  total_eligible_users bigint not null,
  total_registered_users bigint not null,
  total_users_with_goal bigint not null,
  top_goal_name varchar(255),
  bottom_goal_name varchar(255),
  created_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  created_by varchar(255),
  updated_by varchar(255)
);

Now the table structure has been changed to as below:

health_goals
(
  uid BIGSERIAL NOT NULL CONSTRAINT health_goals_pkey primary key,
  employer_key bigint not null,
  health_goals_metric_value json null,
  created_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  created_by varchar(255),
  updated_by varchar(255)
);

Basically now all these columns like total_eligible_users, total_registered_users, total_users_with_goal, top_goal_name, bottom_goal_name wil be consolidated to single columnhealth_goals_metric_value as a JSON data type.

How can I write the response DTO for JSON data type column. Also what changes needs to be done in my AggMapper class.

Upvotes: 1

Views: 1565

Answers (2)

Kunal Vohra
Kunal Vohra

Reputation: 2846

Well one way is by using converter function. You can use the converter function to get values in same format.

Change your orm.xml something like below on your column definition

<basic name="healthGoalsMetricValue">
                <column name="health_goals_metric_value" nullable="true"/>
                <convert converter="path.to.your.HealthGoalsMetricValueConverter"/>
            </basic>

Or if you have java file

aggentity will have following entry

  @Convert(converter = HealthGoalsMetricValueConverter.class)
    private HealthGoalsHighlight healthGoalsHighlight ;

and your class HealthGoalsMetricValue will look something like

//////////////////Edited converter class after comments

       import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.io.IOException;

@Converter
public class HealthGoalsMetricValueConverter implements AttributeConverter<HealthGoalsMetricValue, String> {

private final ObjectMapper mapper = new ObjectMapper();

//And then override like that
@Override
        public String convertToDatabaseColumn(HealthGoalsHighlight healthGoalsMetricValue) {

            try {                
                json = mapper.writeValueAsString(healthGoalsMetricValue);
            } catch (JsonProcessingException exception) {
                throw new JsonProcessingException("Error occurred while object serialization", exception);
            }
            return json;
    }

 //And then override again
@Override
public HealthGoalsMetricValue  convertToEntityAttribute(String healthGoalsMetricValuestr ) {
    HealthGoalsMetricValue  healthGoalsMetricValue  = null;
    try {
        if (healthGoalsMetricValue != null) {
            healthGoalsMetricValue = mapper.readValue(healthGoalsMetricValuestr, HealthGoalsMetricValue.class);
        }
    } catch (Exception exception) {
        throw new Exception("Error occurred while object Deserialization", exception);
    }
    return healthGoalsMetricValue;
}

This all will do the job for you.

Upvotes: 2

Babl
Babl

Reputation: 7646

If you can add additional library have a look at https://github.com/vladmihalcea/hibernate-types project, it's super easy with that.

With this library you will end up with code as simple as this

@Entity
@Table(name = "health_goals")
@TypeDefs({
    @TypeDef(name = "json", typeClass = JsonStringType.class),
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class HealthGoal {
    // all other columns
    @Type(type = "json")
    private HealthGoalsHighlight healthGoalsHighlight;

    // getters setters

}

And if using the maven add dependency

<dependency>
  <groupId>com.vladmihalcea</groupId>
  <artifactId>hibernate-types-52</artifactId>
  <version>2.9.10</version> // or newer version
</dependency>

Upvotes: 0

Related Questions