#693 - ENH: Add support for mapping @DbJson to list of scalar types like List<String>

This commit is contained in:
Robin Bygrave
2016-05-05 16:36:16 +12:00
parent 8c86976e68
commit 2c95d9dc9a
30 changed files with 524 additions and 98 deletions
@@ -36,4 +36,8 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
public @interface DbJsonB {
/**
* For VARCHAR storage specify the column length.
*/
int length() default 0;
}
@@ -117,14 +117,26 @@ public class DbType {
* the scale defined by deployment on a specific property.
*/
public String renderType(int deployLength, int deployScale) {
return renderType(deployLength, deployScale, true);
}
/**
* Render the type defining strict mode.
* <p>
* If strict mode if OFF then this will render with a scale value even if
* that is not strictly supported. The reason for supporting this is to enable
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
* Postgres and VARCHAR(200) for other databases.
* </p>
*/
public String renderType(int deployLength, int deployScale, boolean strict) {
StringBuilder sb = new StringBuilder();
sb.append(name);
if (canHaveLength) {
if (canHaveLength || !strict) {
// see if there is a precision/scale to add (or not)
int len = deployLength != 0 ? deployLength : defaultLength;
if (len > 0) {
sb.append("(");
sb.append(len);
@@ -108,9 +108,9 @@ public class DbTypeMap {
if (logicalTypes) {
// keep it logical for 2 layer DDL generation
put(DbType.HSTORE, new DbType("hstore"));
put(DbType.JSON, new DbType("json"));
put(DbType.JSONB, new DbType("jsonb"));
put(DbType.HSTORE, new DbType("hstore", false));
put(DbType.JSON, new DbType("json", false));
put(DbType.JSONB, new DbType("jsonb", false));
put(DbType.JSONClob, new DbType("jsonclob"));
put(DbType.JSONBlob, new DbType("jsonblob"));
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
@@ -137,7 +137,7 @@ public class DbTypeMap {
/**
* Lookup the platform specific DbType given the standard sql type name.
*/
public DbType lookup(String name) {
public DbType lookup(String name, boolean withScale) {
name = name.trim().toUpperCase();
Integer typeKey = lookup.get(name);
if (typeKey == null) {
@@ -152,18 +152,19 @@ public class DbTypeMap {
case DbType.JSONVarchar:
return get(Types.VARCHAR);
case DbType.JSON:
return getJsonType(DbType.JSON);
return getJsonType(DbType.JSON, withScale);
case DbType.JSONB:
return getJsonType(DbType.JSONB);
return getJsonType(DbType.JSONB, withScale);
default:
return get(typeKey);
}
}
private DbType getJsonType(int type) {
private DbType getJsonType(int type, boolean withScale) {
DbType dbType = get(type);
if (dbType == JSON_CLOB_PLACEHOLDER) {
return get(Types.CLOB);
// if we have scale that implies this maps to varchar
return withScale ? get(Types.VARCHAR) : get(Types.CLOB);
}
if (dbType == JSON_BLOB_PLACEHOLDER) {
return get(Types.BLOB);
@@ -43,9 +43,9 @@ public class PostgresPlatform extends DatabasePlatform {
DbType dbTypeText = new DbType("text");
DbType dbBytea = new DbType("bytea", false);
dbTypeMap.put(DbType.HSTORE, new DbType("hstore"));
dbTypeMap.put(DbType.JSON, new DbType("json"));
dbTypeMap.put(DbType.JSONB, new DbType("jsonb"));
dbTypeMap.put(DbType.HSTORE, new DbType("hstore", false));
dbTypeMap.put(DbType.JSON, new DbType("json", false));
dbTypeMap.put(DbType.JSONB, new DbType("jsonb", false));
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
@@ -47,7 +47,7 @@ public class PlatformTypeConverter {
String suffix = close + 1 < columnDefinition.length() ? columnDefinition.substring(close + 1) : "";
String type = columnDefinition.substring(0, open);
try {
DbType dbType = platformTypes.lookup(type);
DbType dbType = platformTypes.lookup(type, true);
int comma = columnDefinition.indexOf(',', open);
if (comma > -1) {
// scale and precision - decimal(10,4)
@@ -73,7 +73,7 @@ public class PlatformTypeConverter {
protected String convertNoScale(String columnDefinition) {
try {
DbType dbType = platformTypes.lookup(columnDefinition);
DbType dbType = platformTypes.lookup(columnDefinition, false);
return dbType.renderType(0, 0);
} catch (IllegalArgumentException e) {
@@ -108,12 +108,15 @@ public class ModelBuildContext {
}
public String getColumnDefn(BeanProperty p) {
/**
* Render the DB type for this property given the strict mode.
*/
public String getColumnDefn(BeanProperty p, boolean strict) {
DbType dbType = getDbType(p);
if (dbType == null) {
throw new IllegalStateException("Unknown DbType mapping for " + p.getFullBeanName());
}
return p.renderDbType(dbType);
return p.renderDbType(dbType, strict);
}
private DbType getDbType(BeanProperty p) {
@@ -107,7 +107,7 @@ public class ModelBuildIntersectionTable {
throw new RuntimeException("Could not find id property for " + findPropColumn);
}
MColumn col = new MColumn(column, ctx.getColumnDefn(p), true);
MColumn col = new MColumn(column, ctx.getColumnDefn(p, true), true);
col.setPrimaryKey(true);
table.addColumn(col);
}
@@ -184,7 +184,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
if (importedProperty == null) {
throw new RuntimeException("Imported BeanProperty not found?");
}
String columnDefn = ctx.getColumnDefn(importedProperty);
String columnDefn = ctx.getColumnDefn(importedProperty, true);
String refColumn = importedProperty.getDbColumn();
MColumn col = table.addColumn(dbCol, columnDefn, !p.isNullable());
@@ -229,7 +229,9 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
return;
}
MColumn col = new MColumn(p.getDbColumn(), ctx.getColumnDefn(p));
// using non-strict mode to render the DB type such that we have a
// "logical" type like jsonb(200) that can map to JSONB or VARCHAR(200)
MColumn col = new MColumn(p.getDbColumn(), ctx.getColumnDefn(p, false));
col.setDefaultValue(p.getDbColumnDefault());
col.setComment(p.getDbComment());
col.setDraftOnly(p.isDraftOnly());
@@ -90,9 +90,15 @@ public class EJson {
return EJsonReader.parseObject(parser, token);
}
/**
* Parse the json and return as a modify aware List.
*/
public static List<Object> parseList(String json, boolean modifyAware) throws IOException {
return EJsonReader.parseList(json, modifyAware);
}
/**
* Parse the json and return as a List.
* @throws IOException
*/
public static List<Object> parseList(String json) throws IOException {
return EJsonReader.parseList(json);
@@ -100,7 +106,6 @@ public class EJson {
/**
* Parse the json and return as a List taking a Reader.
* @throws IOException
*/
public static List<Object> parseList(Reader reader) throws IOException {
return EJsonReader.parseList(reader);
@@ -110,10 +115,16 @@ public class EJson {
* Parse the json and return as a List taking a JsonParser.
*/
public static List<Object> parseList(JsonParser parser) throws IOException {
return EJsonReader.parseList(parser);
return EJsonReader.parseList(parser, false);
}
/**
* Parse the json returning as a List taking into account the current token.
*/
public static List<Object> parseList(JsonParser parser, JsonToken currentToken) throws IOException {
return (List<Object>)EJsonReader.parse(parser, currentToken, false);
}
/**
* Parse the json and return as a List or Map.
*/
@@ -51,6 +51,11 @@ class EJsonReader {
return (Map<String, Object>)parse(parser, token, false);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(String json, boolean modifyAware) throws IOException {
return (List<Object>) parse(json, modifyAware);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(String json) throws IOException {
return (List<Object>) parse(json);
@@ -62,15 +67,21 @@ class EJsonReader {
}
@SuppressWarnings("unchecked")
static List<Object> parseList(JsonParser parser) throws IOException {
return (List<Object>) parse(parser);
static List<Object> parseList(JsonParser parser, boolean modifyAware) throws IOException {
return (List<Object>) parse(parser, modifyAware);
}
static Object parse(String json) throws IOException {
if (json == null) {
return null;
}
return parse(new StringReader(json));
}
static Object parse(String json, boolean modifyAware) throws IOException {
if (json == null) {
return null;
}
return parse(new StringReader(json), modifyAware);
}
@@ -984,11 +984,11 @@ public class BeanProperty implements ElPropertyValue, Property {
/**
* Return the DB column type definition.
*/
public String renderDbType(DbType dbType) {
public String renderDbType(DbType dbType, boolean strict) {
if (dbColumnDefn != null) {
return dbColumnDefn;
}
return dbType.renderType(dbLength, dbScale);
return dbType.renderType(dbLength, dbScale, strict);
}
/**
@@ -175,12 +175,16 @@ public class AnnotationFields extends AnnotationParser {
if (comment != null) {
prop.setDbComment(comment.value());
}
if (get(prop, DbHstore.class) != null) {
util.setDbHstore(prop);
}
DbJson dbJson = get(prop, DbJson.class);
if (dbJson != null) {
util.setDbJsonType(prop, dbJson);
} else {
if (get(prop, DbJsonB.class) != null) {
util.setDbJsonBType(prop);
DbJsonB dbJsonB = get(prop, DbJsonB.class);
if (dbJsonB != null) {
util.setDbJsonBType(prop, dbJsonB);
}
}
@@ -197,10 +201,6 @@ public class AnnotationFields extends AnnotationParser {
prop.setDocProperty(docProperty);
}
if (get(prop, DbHstore.class) != null) {
util.setDbHstore(prop);
}
Formula formula = get(prop, Formula.class);
if (formula != null) {
prop.setSqlFormula(formula.select(), formula.join());
@@ -223,21 +223,18 @@ public class DeployCreateProperties {
Class<?> propertyType = field.getType();
ManyToOne manyToOne = field.getAnnotation(ManyToOne.class);
if (manyToOne != null){
Class<?> tt = manyToOne.targetEntity();
if (tt != null && !tt.equals(void.class)){
if (!tt.equals(void.class)){
propertyType = tt;
}
}
if (isMappedType(field)) {
if (isSpecialScalarType(field)) {
return new DeployBeanProperty(desc, propertyType, null, null);
}
// check for Collection type (list, set or map)
ManyType manyType = determineManyType.getManyType(propertyType);
if (manyType != null) {
// List, Set or Map based object
Class<?> targetType = determineTargetType(field);
@@ -299,7 +296,7 @@ public class DeployCreateProperties {
/**
* Return true if the field has one of the special mappings.
*/
private boolean isMappedType(Field field) {
private boolean isSpecialScalarType(Field field) {
return (field.getAnnotation(DbJson.class) != null)
|| (field.getAnnotation(DbJsonB.class) != null)
|| (field.getAnnotation(DbHstore.class) != null);
@@ -6,6 +6,7 @@ import javax.persistence.Enumerated;
import javax.persistence.PersistenceException;
import com.avaje.ebean.annotation.DbJson;
import com.avaje.ebean.annotation.DbJsonB;
import com.avaje.ebean.annotation.DbJsonType;
import com.avaje.ebean.config.EncryptDeploy;
import com.avaje.ebean.config.EncryptDeployManager;
@@ -103,6 +104,7 @@ public class DeployUtil {
return new DataEncryptSupport(encryptKeyManager, bytesEncryptor, table, column);
}
@SuppressWarnings("unchecked")
public void setEnumScalarType(Enumerated enumerated, DeployBeanProperty prop) {
Class<?> enumType = prop.getPropertyType();
@@ -200,11 +202,9 @@ public class DeployUtil {
* Map to Postgres HSTORE type.
*/
public void setDbHstore(DeployBeanProperty prop) {
ScalarType<?> scalarType = typeManager.getScalarType(DbType.HSTORE);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType found for HSTORE on [" + prop.getFullBeanName() + "]");
throw new RuntimeException("No ScalarType found for HSTORE on [" + prop.getFullBeanName() + "] ?");
}
prop.setDbType(DbType.HSTORE);
prop.setScalarType(scalarType);
@@ -219,22 +219,20 @@ public class DeployUtil {
setDbJsonType(prop, dbType, dbJsonType.length());
}
public void setDbJsonBType(DeployBeanProperty prop) {
setDbJsonType(prop, DbType.JSONB, 0);
public void setDbJsonBType(DeployBeanProperty prop, DbJsonB dbJsonB) {
setDbJsonType(prop, DbType.JSONB, dbJsonB.length());
}
private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength) {
Class<?> type = prop.getPropertyType();
ScalarType<?> scalarType = typeManager.getJsonScalarType(type, dbType);
ScalarType<?> scalarType = typeManager.getJsonScalarType(type, dbType, dbLength);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType for JSON type [" + type + "] [" + dbType + "]");
}
prop.setDbType(dbType);
prop.setScalarType(scalarType);
if (dbType == Types.VARCHAR) {
if (dbType == Types.VARCHAR || dbLength > 0) {
// determine the db column size
int columnLength = (dbLength > 0) ? dbLength : DEFAULT_JSON_VARCHAR_LENGTH;
prop.setDbLength(columnLength);
@@ -155,6 +155,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final boolean java7Present;
private final boolean postgres;
// OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath
/**
@@ -195,14 +197,14 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
this.objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent();
this.extraTypeFactory = new DefaultTypeFactory(config);
this.postgres = isPostgres(config.getDatabasePlatform());
initialiseStandard(jsonDateTime, config);
initialiseJavaTimeTypes(jsonDateTime, config);
initialiseJodaTypes(jsonDateTime, config);
initialiseJacksonTypes(config);
if (isPostgres(config.getDatabasePlatform())) {
// Postgres has special DB types for JSON/JSONB
if (postgres) {
this.jsonMapJson = new ScalarTypeJsonMapPostgres.JSON();
this.jsonMapJsonb = new ScalarTypeJsonMapPostgres.JSONB();
} else {
@@ -368,7 +370,17 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
}
@Override
public ScalarType<?> getJsonScalarType(Class<?> type, int dbType) {
public ScalarType<?> getJsonScalarType(Class<?> type, int dbType, int dbLength) {
if (type.equals(List.class)) {
if (postgres) {
switch (dbType) {
case DbType.JSONB: return ScalarTypeJsonList.JSONB;
case DbType.JSON: return ScalarTypeJsonList.JSON;
}
}
return ScalarTypeJsonList.VARCHAR;
}
if (type.equals(Map.class)) {
// @DbJson Map<String,Object> property
@@ -24,6 +24,10 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
this.owner = owner;
}
public String toString() {
return list.toString();
}
@Override
public boolean isMarkedDirty() {
return owner.isMarkedDirty();
@@ -0,0 +1,29 @@
package com.avaje.ebeaninternal.server.type;
import org.postgresql.util.PGobject;
import java.sql.SQLException;
public class PostgresHelper {
/**
* The Postgres JSON DB type.
*/
public static final String JSON_TYPE = "json";
/**
* The Postgres JSONB DB type.
*/
public static final String JSONB_TYPE = "jsonb";
/**
* Construct and return Postgres specific PG object.
*/
public static Object asObject(String pgType, String rawJson) throws SQLException {
PGobject pgo = new PGobject();
pgo.setType(pgType);
pgo.setValue(rawJson);
return pgo;
}
}
@@ -0,0 +1,75 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
abstract class ScalarTypeJsonCollection<T> extends ScalarTypeBase<T> {
public ScalarTypeJsonCollection(Class<T> type, int dbType) {
super(type, false, dbType);
}
/**
* Consider as a mutable type. Use the isDirty() method to check for dirty state.
*/
@Override
public boolean isMutable() {
return true;
}
/**
* Return true if the value should be considered dirty (and included in an update).
*/
@Override
public boolean isDirty(Object value) {
return !(value instanceof ModifyAwareOwner) || ((ModifyAwareOwner) value).isMarkedDirty();
}
@Override
public Object toJdbcType(Object value) {
return value;
}
@Override
@SuppressWarnings("unchecked")
public T toBeanType(Object value) {
return (T)value;
}
@Override
public DocPropertyType getDocType() {
return DocPropertyType.LIST;
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public T convertFromMillis(long dateTime) {
return null;
}
@Override
public T readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
return parse(dataInput.readUTF());
}
}
@Override
public void writeData(DataOutput dataOutput, T value) throws IOException {
if (value == null) {
dataOutput.writeBoolean(false);
} else {
ScalarHelp.writeUTF(dataOutput, format(value));
}
}
}
@@ -0,0 +1,137 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.text.json.EJson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import javax.persistence.PersistenceException;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
/**
* Types for mapping List in JSON format to DB types VARCHAR, JSON and JSONB.
*/
public class ScalarTypeJsonList {
public static final ScalarTypeJsonCollection<List> VARCHAR = new ScalarTypeJsonList.Varchar();
public static final ScalarTypeJsonCollection<List> JSON = new ScalarTypeJsonList.Json();
public static final ScalarTypeJsonCollection<List> JSONB = new ScalarTypeJsonList.JsonB();
/**
* List mapped to DB VARCHAR.
*/
private static class Varchar extends ScalarTypeJsonList.Base {
public Varchar() {
super(Types.VARCHAR);
}
}
/**
* List mapped to Postgres JSON.
*/
private static class Json extends ScalarTypeJsonList.PgBase {
public Json() {
super(DbType.JSON, PostgresHelper.JSON_TYPE);
}
}
/**
* List mapped to Postgres JSONB.
*/
private static class JsonB extends ScalarTypeJsonList.PgBase {
public JsonB() {
super(DbType.JSONB, PostgresHelper.JSONB_TYPE);
}
}
/**
* Base class for List handling.
*/
private abstract static class Base extends ScalarTypeJsonCollection<List> {
public Base(int dbType) {
super(List.class, dbType);
}
@Override
public List read(DataReader dataReader) throws SQLException {
try {
// parse JSON into modifyAware list
return EJson.parseList(dataReader.getString(), true);
} catch (IOException e) {
throw new SQLException("Failed to parse JSON content as List: ["+ dataReader.getString() +"]", e);
}
}
@Override
public void bind(DataBind b, List value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else if (value.isEmpty()) {
b.setString("[]");
} else {
try {
b.setString(EJson.write(value));
} catch (IOException e) {
throw new SQLException("Failed to format List into JSON content", e);
}
}
}
@Override
public String formatValue(List value) {
try {
return EJson.write(value);
} catch (IOException e) {
throw new PersistenceException("Failed to format List into JSON content", e);
}
}
@Override
public List parse(String value) {
try {
return EJson.parseList(value, false);
} catch (IOException e) {
throw new PersistenceException("Failed to parse JSON content as List: ["+value+"]", e);
}
}
@Override
public List jsonRead(JsonParser parser) throws IOException {
return EJson.parseList(parser, parser.getCurrentToken());
}
@Override
public void jsonWrite(JsonGenerator writer, List value) throws IOException {
EJson.write(value, writer);
}
}
/**
* Postgres extension to base List handling.
*/
private static class PgBase extends ScalarTypeJsonList.Base {
final String pgType;
PgBase(int jdbcType, String pgType) {
super(jdbcType);
this.pgType = pgType;
}
@Override
public void bind(DataBind bind, List value) throws SQLException {
String rawJson = (value == null) ? null : formatValue(value);
bind.setObject(PostgresHelper.asObject(pgType, rawJson));
}
}
}
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.text.json.EJson;
import com.avaje.ebeaninternal.util.EncodeUtil;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
@@ -12,7 +13,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Map;
@@ -77,7 +77,7 @@ public abstract class ScalarTypeJsonMap extends ScalarTypeBase<Map> {
b.setNull(Types.BLOB);
} else {
String rawJson = formatValue(value);
b.setBytes(rawJson.getBytes(StandardCharsets.UTF_8));
b.setBytes(EncodeUtil.utf8ToBytes(rawJson));
}
}
}
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.dbplatform.DbType;
import org.postgresql.util.PGobject;
import java.sql.SQLException;
import java.util.Map;
@@ -11,10 +10,6 @@ import java.util.Map;
*/
public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
private static final String POSTGRES_TYPE_JSON = "json";
private static final String POSTGRES_TYPE_JSONB = "jsonb";
final String postgresType;
ScalarTypeJsonMapPostgres(int jdbcType, String postgresType) {
@@ -23,14 +18,10 @@ public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
}
@Override
public void bind(DataBind b, Map value) throws SQLException {
public void bind(DataBind bind, Map value) throws SQLException {
String rawJson = (value == null) ? null : formatValue(value);
PGobject pgo = new PGobject();
pgo.setType(postgresType);
pgo.setValue(rawJson);
b.setObject(pgo);
bind.setObject(PostgresHelper.asObject(postgresType, rawJson));
}
/**
@@ -39,7 +30,7 @@ public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
public static class JSON extends ScalarTypeJsonMapPostgres {
public JSON() {
super(DbType.JSON, POSTGRES_TYPE_JSON);
super(DbType.JSON, PostgresHelper.JSON_TYPE);
}
}
@@ -49,7 +40,7 @@ public abstract class ScalarTypeJsonMapPostgres extends ScalarTypeJsonMap {
public static class JSONB extends ScalarTypeJsonMapPostgres {
public JSONB() {
super(DbType.JSONB, POSTGRES_TYPE_JSONB);
super(DbType.JSONB, PostgresHelper.JSONB_TYPE);
}
}
}
@@ -1,6 +1,7 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.text.TextException;
import com.avaje.ebeaninternal.util.EncodeUtil;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
@@ -13,7 +14,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.sql.Types;
@@ -85,7 +85,7 @@ public abstract class ScalarTypeJsonNode extends ScalarTypeBase<JsonNode> {
dataBind.setNull(Types.BLOB);
} else {
String rawJson = formatValue(value);
dataBind.setBlob(rawJson.getBytes(StandardCharsets.UTF_8));
dataBind.setBlob(EncodeUtil.utf8ToBytes(rawJson));
}
}
}
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.config.dbplatform.DbType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.postgresql.util.PGobject;
import java.sql.SQLException;
@@ -12,10 +11,6 @@ import java.sql.SQLException;
*/
public abstract class ScalarTypeJsonNodePostgres extends ScalarTypeJsonNode {
private static final String POSTGRES_TYPE_JSON = "json";
private static final String POSTGRES_TYPE_JSONB = "jsonb";
final ObjectMapper objectMapper;
final String postgresType;
@@ -27,14 +22,9 @@ public abstract class ScalarTypeJsonNodePostgres extends ScalarTypeJsonNode {
}
@Override
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
public void bind(DataBind bind, JsonNode value) throws SQLException {
String rawJson = (value == null) ? null : formatValue(value);
PGobject pgo = new PGobject();
pgo.setType(postgresType);
pgo.setValue(rawJson);
dataBind.setObject(pgo);
bind.setObject(PostgresHelper.asObject(postgresType, rawJson));
}
/**
@@ -43,7 +33,7 @@ public abstract class ScalarTypeJsonNodePostgres extends ScalarTypeJsonNode {
public static class JSON extends ScalarTypeJsonNodePostgres {
public JSON(ObjectMapper objectMapper) {
super(objectMapper, DbType.JSON, POSTGRES_TYPE_JSON);
super(objectMapper, DbType.JSON, PostgresHelper.JSON_TYPE);
}
}
@@ -53,7 +43,7 @@ public abstract class ScalarTypeJsonNodePostgres extends ScalarTypeJsonNode {
public static class JSONB extends ScalarTypeJsonNodePostgres {
public JSONB(ObjectMapper objectMapper) {
super(objectMapper, DbType.JSONB, POSTGRES_TYPE_JSONB);
super(objectMapper, DbType.JSONB, PostgresHelper.JSONB_TYPE);
}
}
}
@@ -63,5 +63,5 @@ public interface TypeManager {
* Note that type expected to be JsonNode or Map.
* </p>
*/
ScalarType<?> getJsonScalarType(Class<?> type, int dbType);
ScalarType<?> getJsonScalarType(Class<?> type, int dbType, int dbLength);
}