Map a JsonNode object to a String field in SQL DB JPA

PopperJuan :

I got a Sql table with these fields:

id  uniqueidentifier primary key,
<--Omitting extra fields -->
metadata  nvarchar(max)

Which I also have a Entity mapped to it:

@Data
public class GenericEntity implements Serializable {

  @Id
  @GeneratedValue(generator = "uuid2")
  @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
  @Type(type = "uuid-char")
  private UUID id;
<--Omitting extra properties -->
  @Type(type = "string")
  private JsonNode metadata;
}

The second field that is a JsonNode needs to be able to accept different types of json and store it in the table as a String.

How can I go about converting a JsonNode field and store it in the DB as a String then when I read from the table it converts the String back to a JsonNode?

Payload:

{
    "id": "db8e8d4b-eee2-4507-bf30-f55c3f948724",
    <-- Omitting extra properties -->
    "metadata": {
        "description": "Sample",
        "location": "Stack Overflow"
    }
}

Right now everytime I try to save it I get the error:

Could not determine type for: com.fasterxml.jackson.databind.JsonNode, at table: table_name, for columns: [org.hibernate.mapping.Column(metadata)]
PopperJuan :

I followed these instructions: https://www.baeldung.com/hibernate-custom-types

Created a SqlTypeDescriptor

public class JsonNodeStringType extends AbstractSingleColumnStandardBasicType<JsonNode> implements DiscriminatorType<JsonNode> {

  public static final JsonNodeStringType INSTANCE = new JsonNodeStringType();

  public JsonNodeStringType() {
    super(VarcharTypeDescriptor.INSTANCE, JsonNodeStringJavaDescriptor.INSTANCE);
  }

  @Override
  public String getName() {
    return "jsonnode";
  }

  @Override
  public JsonNode stringToObject(String xml) {
    return fromString(xml);
  }

  @Override
  public String objectToSQLString(JsonNode value, Dialect dialect) {
    return '\'' + toString(value) + '\'';
  }
}

Then I created a Java Type Descriptor:

public class JsonNodeStringJavaDescriptor extends AbstractTypeDescriptor<JsonNode> {

  public static final ObjectMapper mapper = new ObjectMapper();

  public static final JsonNodeStringJavaDescriptor INSTANCE = new JsonNodeStringJavaDescriptor();

  public JsonNodeStringJavaDescriptor() {
    super(JsonNode.class, ImmutableMutabilityPlan.INSTANCE);
  }

  @Override
  public String toString(JsonNode value) {
    try {
      return mapper.writeValueAsString(value);
    } catch (JsonProcessingException e) {
      throw new IllegalArgumentException("The given JsonNode object value: " + value + " cannot be transformed to a String", e);
    }
  }

  @Override
  public JsonNode fromString(String string) {
    try {
      return mapper.readTree(string);
    } catch (JsonProcessingException e) {
      throw new IllegalArgumentException("The given string value: " + string + " cannot be transformed to JsonNode object", e);
    }
  }

  @Override
  public <X> X unwrap(JsonNode value, Class<X> type, WrapperOptions options) {
    if (value == null) {
      return null;
    }
    if (String.class.isAssignableFrom(type)) {
      return (X) toString(value);
    }
    throw unknownUnwrap(type);
  }

  @Override
  public <X> JsonNode wrap(X value, WrapperOptions options) {
    if (value == null) {
      return null;
    }
    if (String.class.isInstance(value)) {
      return fromString(value.toString());
    }

    throw unknownWrap(value.getClass());
  }

Then add the type definition to the entity model

@Data
@TypeDef(name = "jsonnode", typeClass = JsonNodeStringType.class)
public class GenericEntity implements Serializable {

  @Id
  @GeneratedValue(generator = "uuid2")
  @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
  @Type(type = "uuid-char")
  private UUID id;
<--Omitting extra properties -->
  @Type(type = "jsonnode")
  private JsonNode metadata;
}

If you don't want to manually create these type descriptors you can also follow this article to use a external dependency: https://vladmihalcea.com/sql-server-json-hibernate/

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Convert JsonNode object to Map

Why MyBatis can't map the JSONB type to a Map<String, Object> or to JsonNode?

How to add field names and values of a json object into List<String> using jsonNode

jpa - create Map<String, List<String>> field with one table

Deserializing a Map<String, Object> field with Gson

Convert List<Map<String, String>> to Object in Java Spring boot jpa

Is there a library to map Dynamo Db Map<String ,AttributeValue> to an Object?

How to accept Tuple of type Map<String,Object> in JPA

Map JSON string column of a JPA entity to Java object automatically

Trim string field in JPA

Flutter SQL Numeric DB Field error 'String' is not a subtype of type 'int?'

How to retrieve a JSON element from a JsonNode object as String using jackson?

Persisting with JPA leaves nested object's db foreign key field null

removing object from DB, JPA

JPA Map<String,String> mapping

JPA: Replace object in DB by object with same id

JPA Querying for json field in Oracle DB

JPA Querying for json field in Oracle DB

Edit object array with JsonNode

Convert in java List<POJO> to Map<String, List<Object>> where the key is a field name and value is a list of values by field

Map db-functionresult to jpa entity property

Turn object from DB into a Map()

couldn't decode Object with field Type Map[String, String] using circe

jq: map object if field exists

Converting Map<String,String> to Map<String,Object>

Convert Map<String,Object> to Map<String,String>

Map<String ,String[]> Converts to Map<String, Object[])

map of string within a map object

Storing a Map<String,String> using JPA