Hi Oran,
You can store and load complex database types if you define a JPA converter and a Jmix datatype for them. For example, to work with jsonb
type, add the following classes to your project:
JPA converter:
package com.company.demo.entity;
import elemental.json.Json;
import elemental.json.JsonObject;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import org.postgresql.util.PGobject;
import java.sql.SQLException;
@Converter(autoApply = true)
public class JsonAttributeConverter implements AttributeConverter<JsonObject, PGobject> {
@Override
public PGobject convertToDatabaseColumn(JsonObject object) {
if (object == null) return null;
try {
PGobject out = new PGobject();
out.setType("jsonb");
out.setValue(object.toJson());
return out;
} catch (SQLException ex) {
throw new IllegalArgumentException("Cannot convert " + object + " to JSON", ex);
}
}
@Override
public JsonObject convertToEntityAttribute(PGobject value) {
if (value == null) return null;
return Json.parse(value.getValue());
}
}
Jmix datatype:
package com.company.demo.entity;
import elemental.json.Json;
import elemental.json.JsonObject;
import io.jmix.core.metamodel.annotation.DatatypeDef;
import io.jmix.core.metamodel.annotation.Ddl;
import io.jmix.core.metamodel.datatype.Datatype;
import org.springframework.lang.Nullable;
import java.text.ParseException;
import java.util.Locale;
@DatatypeDef(
id = "json",
javaClass = JsonObject.class,
defaultForClass = true
)
@Ddl(dbms = "postgres", value = "jsonb")
public class JsonDatatype implements Datatype<JsonObject> {
@Override
public String format(@Nullable Object value) {
if (value instanceof JsonObject jsonObject) {
return jsonObject.toJson();
}
return null;
}
@Override
public String format(Object value, Locale locale) {
return format(value);
}
@Override
public JsonObject parse(@Nullable String value) throws ParseException {
if (value == null)
return null;
return Json.parse(value);
}
@Override
public JsonObject parse(String value, Locale locale) throws ParseException {
return parse(value);
}
}
Now you can define attributes of JsonObject
type and map them to jsonb
columns, for example:
@JmixEntity
@Table(name = "CUSTOMER")
@Entity
public class Customer {
// ...
@Column(name = "PROPERTIES")
private JsonObject properties;
public JsonObject getProperties() {
return properties;
}
public void setProperties(JsonObject properties) {
this.properties = properties;
}
}
Such an attribute can be directly displayed in UI if needed, in a data grid column or in a text field. But filtering by this field is hardly possible. To use out-of-the-box filtering features of Jmix (like genericFilter or propertyFilter components), the attribute must be of a simple type or an entity.
Regards,
Konstantin