#299 - ENH: Add support for mapping Jackson JsonNode as JSON content to DB including Postgres JSON and JSON types

This commit is contained in:
rbygrave
2015-05-28 22:54:32 +12:00
parent f5a2cf8ff9
commit 67f427b83e
13 changed files with 895 additions and 4 deletions
+3 -2
View File
@@ -55,18 +55,19 @@
<version>1.7.7</version>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
<scope>provided</scope>
</dependency>
<!-- provided scope for JsonNode support -->
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.3</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -9,6 +9,7 @@ import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.server.core.BootupClasses;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.type.reflect.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.joda.time.*;
import org.joda.time.LocalDate;
@@ -122,6 +123,29 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
private final boolean objectMapperPresent;
// OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath
/**
* Jackson's JsonNode storage to Clob.
*/
private ScalarType<?> jsonNodeClob;
/**
* Jackson's JsonNode storage to Blob.
*/
private ScalarType<?> jsonNodeBlob;
/**
* Jackson's JsonNode storage to Varchar.
*/
private ScalarType<?> jsonNodeVarchar;
/**
* Jackson's JsonNode storage to Postgres JSON or Clob.
*/
private ScalarType<?> jsonNodeJson;
/**
* Jackson's JsonNode storage to Postgres JSONB or Clob.
*/
private ScalarType<?> jsonNodeJsonb;
/**
* Create the DefaultTypeManager.
*/
@@ -142,6 +166,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
initialiseStandard(jsonDateTime, config);
initialiseJavaTimeTypes(jsonDateTime, config);
initialiseJodaTypes(jsonDateTime);
initialiseJacksonTypes(config);
if (isPostgres(config.getDatabasePlatform())) {
// Postgres has special DB types for JSON/JSONB
@@ -291,6 +316,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
public ScalarType<?> getJsonScalarType(Class<?> type, int dbType) {
if (type.equals(Map.class)) {
// @DbJson Map<String,Object> property
switch (dbType) {
case Types.VARCHAR : return jsonMapVarchar;
case Types.BLOB: return jsonMapBlob;
@@ -302,6 +328,19 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
}
}
if (type.equals(JsonNode.class)) {
// @DbJson JsonNode property (Jackson)
switch (dbType) {
case Types.VARCHAR : return jsonNodeVarchar;
case Types.BLOB: return jsonNodeBlob;
case Types.CLOB : return jsonNodeClob;
case DbType.JSONB: return jsonNodeJsonb;
case DbType.JSON: return jsonNodeJson;
default:
return jsonNodeJson;
}
}
throw new IllegalArgumentException("Type [" + type + "] unsupported for @DbJson mapping");
}
@@ -645,6 +684,38 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
return propParamTypes[1];
}
/**
* Add support for Jackson's JsonNode mapping to Clob, Blob, Varchar, JSON and JSONB.
*/
protected void initialiseJacksonTypes(ServerConfig config) {
if (ClassUtil.isPresent("com.fasterxml.jackson.databind.ObjectMapper", this.getClass())) {
logger.trace("Registering JsonNode type support");
ObjectMapper objectMapper = (ObjectMapper)config.getObjectMapper();
if (objectMapper == null) {
objectMapper = new ObjectMapper();
config.setObjectMapper(objectMapper);
}
jsonNodeClob = new ScalarTypeJsonNode.Clob(objectMapper);
jsonNodeBlob = new ScalarTypeJsonNode.Blob(objectMapper);
jsonNodeVarchar = new ScalarTypeJsonNode.Varchar(objectMapper);
jsonNodeJson = jsonNodeClob; // Default for non-Postgres databases
jsonNodeJsonb = jsonNodeClob; // Default for non-Postgres databases
if (isPostgres(config.getDatabasePlatform())) {
jsonNodeJson = new ScalarTypeJsonNodePostgres.JSON(objectMapper);
jsonNodeJsonb = new ScalarTypeJsonNodePostgres.JSONB(objectMapper);
}
// add as default mapping for JsonNode (when not annotated with @DbJson etc)
typeMap.put(JsonNode.class, jsonNodeJson);
}
}
protected void initialiseJavaTimeTypes(JsonConfig.DateTime mode, ServerConfig config) {
if (ClassUtil.isPresent("java.time.LocalDate", this.getClass())) {
logger.debug("Registering java.time data types");
@@ -0,0 +1,227 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebean.text.TextException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.sql.Types;
/**
* Type which maps Jackson's JsonNode to various DB types (Clob, Varchar, Blob) in JSON format.
*/
public abstract class ScalarTypeJsonNode extends ScalarTypeBase<JsonNode> {
/**
* Clob storage based implementation.
*/
public static class Clob extends ScalarTypeJsonNode {
public Clob(ObjectMapper objectMapper) {
super(objectMapper, Types.CLOB);
}
@Override
public JsonNode read(DataReader dataReader) throws SQLException {
Reader reader = dataReader.getClobReader();
if (reader == null) {
return null;
}
try {
JsonNode tree = parse(reader);
reader.close();
return tree;
} catch (IOException e) {
throw new SQLException("Error reading Clob stream from DB", e);
}
}
}
/**
* Varchar storage based implementation.
*/
public static class Varchar extends ScalarTypeJsonNode {
public Varchar(ObjectMapper objectMapper) {
super(objectMapper, Types.VARCHAR);
}
}
/**
* Blob storage based implementation.
*/
public static class Blob extends ScalarTypeJsonNode {
public Blob(ObjectMapper objectMapper) {
super(objectMapper, Types.BLOB);
}
@Override
public JsonNode read(DataReader dataReader) throws SQLException {
InputStream is = dataReader.getBlobInputStream();
if (is == null) {
return null;
}
try {
InputStreamReader reader = new InputStreamReader(is);
JsonNode tree = parse(reader);
reader.close();
return tree;
} catch (IOException e) {
throw new SQLException("Error reading Blob stream from DB", e);
}
}
@Override
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
if (value == null) {
dataBind.setNull(Types.BLOB);
} else {
String rawJson = formatValue(value);
InputStream stream = new ByteArrayInputStream(rawJson.getBytes(StandardCharsets.UTF_8));
dataBind.setBlob(stream);
}
}
}
/**
* Jackson's ObjectMapper used to read / write JsonNode
*/
final ObjectMapper objectMapper;
public ScalarTypeJsonNode(ObjectMapper objectMapper, int jdbcType) {
super(JsonNode.class, false, jdbcType);
this.objectMapper = objectMapper;
}
/**
* Map is 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 true;
}
@Override
public JsonNode read(DataReader dataReader) throws SQLException {
String rawJson = dataReader.getString();
if (rawJson == null) {
return null;
}
return parse(rawJson);
}
@Override
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
if (value == null) {
dataBind.setNull(Types.VARCHAR);
} else {
String rawJson = formatValue(value);
dataBind.setString(rawJson);
}
}
@Override
public Object toJdbcType(Object value) {
return value;
}
@Override
public JsonNode toBeanType(Object value) {
return (JsonNode) value;
}
@Override
public String formatValue(JsonNode jsonNode) {
try {
return objectMapper.writeValueAsString(jsonNode);
} catch (IOException e) {
throw new TextException(e);
}
}
@Override
public JsonNode parse(String value) {
try {
return objectMapper.readValue(value, JsonNode.class);
} catch (IOException e) {
throw new TextException(e);
}
}
public JsonNode parse(Reader reader) {
try {
return objectMapper.readValue(reader, JsonNode.class);
} catch (IOException e) {
throw new TextException(e);
}
}
@Override
public JsonNode convertFromMillis(long dateTime) {
throw new RuntimeException("Should never be called");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public JsonNode readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
String json = dataInput.readUTF();
return parse(json);
}
}
@Override
public void writeData(DataOutput dataOutput, JsonNode value) throws IOException {
if (value == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
String json = format(value);
dataOutput.writeUTF(json);
}
}
@Override
public void jsonWrite(JsonGenerator ctx, String name, JsonNode value) throws IOException {
// write the field name followed by the JsonNode object
if (value == null) {
ctx.writeNullField(name);
} else {
ctx.writeFieldName(name);
objectMapper.writeTree(ctx, value);
}
}
@Override
public JsonNode jsonRead(JsonParser ctx, JsonToken event) throws IOException {
// at this point the BeanProperty has read the START_OBJECT token
// to check for a null value.
return objectMapper.readValue(ctx, JsonNode.class);
}
}
@@ -0,0 +1,59 @@
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;
/**
* Support for mapping JsonNode to Postgres DB types JSON and JSONB.
*/
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;
ScalarTypeJsonNodePostgres(ObjectMapper objectMapper, int jdbcType, String postgresType) {
super(objectMapper, jdbcType);
this.objectMapper = objectMapper;
this.postgresType = postgresType;
}
@Override
public void bind(DataBind dataBind, JsonNode value) throws SQLException {
String rawJson = (value == null) ? null : formatValue(value);
PGobject pgo = new PGobject();
pgo.setType(postgresType);
pgo.setValue(rawJson);
dataBind.setObject(pgo);
}
/**
* ScalarType mapping JsonNode to Postgres JSON database type.
*/
public static class JSON extends ScalarTypeJsonNodePostgres {
public JSON(ObjectMapper objectMapper) {
super(objectMapper, DbType.JSON, POSTGRES_TYPE_JSON);
}
}
/**
* ScalarType mapping JsonNode to Postgres JSONB database type.
*/
public static class JSONB extends ScalarTypeJsonNodePostgres {
public JSONB(ObjectMapper objectMapper) {
super(objectMapper, DbType.JSONB, POSTGRES_TYPE_JSONB);
}
}
}
@@ -19,8 +19,6 @@ import java.util.Map;
@SuppressWarnings("rawtypes")
public class ScalarTypePostgresHstore extends ScalarTypeBase<Map> {
public static final String KEY = "hstore";
public ScalarTypePostgresHstore() {
super(Map.class, false, DbType.HSTORE);
}
@@ -0,0 +1,102 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.json.EBasicJsonNode;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.Set;
import static org.junit.Assert.*;
public class TestJsonNodeBasic extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
String s1 = "{\"docId\":99,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNode bean = new EBasicJsonNode();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNode bean1 = Ebean.find(EBasicJsonNode.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().path("contentType").asText(), bean1.getContent().path("contentType").asText());
assertEquals(18L, bean1.getContent().get("docId").asLong());
bean1.setName("just change name");
Ebean.save(bean1);
JsonNode content1 = objectMapper.readTree(s1);
bean1.setName("two");
bean1.setContent(content1);
Ebean.save(bean1);
EBasicJsonNode bean2 = Ebean.find(EBasicJsonNode.class, bean.getId());
// name changed and docId changed
assertEquals("two", bean2.getName());
assertEquals(99L, bean2.getContent().path("docId").asLong());
// content persisted even though it has not changed (as it's loaded)
// we can't do dirty detection on JsonNode (like we do on Map<String,Object>)
bean1.setName("three");
Ebean.save(bean1);
EBasicJsonNode bean3 = Ebean.find(EBasicJsonNode.class, bean.getId());
assertEquals("three", bean3.getName());
assertEquals(99L, bean3.getContent().path("docId").asLong());
// write whole bean with content as JSON
String fullBeanJson = Ebean.json().toJson(bean3);
// parse JSON into whole bean with content
EBasicJsonNode beanJsonRestored = Ebean.json().toBean(EBasicJsonNode.class, fullBeanJson);
assertEquals(99L,beanJsonRestored.getContent().path("docId").asLong());
}
@Test
public void testLazyLoading() throws IOException {
String s0 = "{\"docId\":19,\"contentId\":\"asd\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNode bean = new EBasicJsonNode();
bean.setName("lazyLoadTest");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNode bean1 = Ebean.find(EBasicJsonNode.class)
.select("name")
.setId(bean.getId())
.findUnique();
Set<String> loadedProps = Ebean.getBeanState(bean1).getLoadedProps();
assertTrue(loadedProps.contains("name"));
assertFalse(loadedProps.contains("content"));
JsonNode lazyLoadedContent = bean1.getContent();
assertNotNull(lazyLoadedContent);
}
}
@@ -0,0 +1,69 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.json.EBasicJsonNodeBlob;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.Set;
import static org.junit.Assert.*;
public class TestJsonNodeBlob extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNodeBlob bean = new EBasicJsonNodeBlob();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNodeBlob bean1 = Ebean.find(EBasicJsonNodeBlob.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().path("contentType").asText(), bean1.getContent().path("contentType").asText());
assertEquals(18L, bean1.getContent().get("docId").asLong());
}
@Test
public void testLazyLoading() throws IOException {
String s0 = "{\"docId\":19,\"contentId\":\"asd\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNodeBlob bean = new EBasicJsonNodeBlob();
bean.setName("lazyLoadTest");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNodeBlob bean1 = Ebean.find(EBasicJsonNodeBlob.class)
.select("name")
.setId(bean.getId())
.findUnique();
Set<String> loadedProps = Ebean.getBeanState(bean1).getLoadedProps();
assertTrue(loadedProps.contains("name"));
assertFalse(loadedProps.contains("content"));
JsonNode lazyLoadedContent = bean1.getContent();
assertNotNull(lazyLoadedContent);
}
}
@@ -0,0 +1,69 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.json.EBasicJsonNodeJsonB;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.Set;
import static org.junit.Assert.*;
public class TestJsonNodeJsonb extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNodeJsonB bean = new EBasicJsonNodeJsonB();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNodeJsonB bean1 = Ebean.find(EBasicJsonNodeJsonB.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().path("contentType").asText(), bean1.getContent().path("contentType").asText());
assertEquals(18L, bean1.getContent().get("docId").asLong());
}
@Test
public void testLazyLoading() throws IOException {
String s0 = "{\"docId\":19,\"contentId\":\"asd\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNodeJsonB bean = new EBasicJsonNodeJsonB();
bean.setName("lazyLoadTest");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNodeJsonB bean1 = Ebean.find(EBasicJsonNodeJsonB.class)
.select("name")
.setId(bean.getId())
.findUnique();
Set<String> loadedProps = Ebean.getBeanState(bean1).getLoadedProps();
assertTrue(loadedProps.contains("name"));
assertFalse(loadedProps.contains("content"));
JsonNode lazyLoadedContent = bean1.getContent();
assertNotNull(lazyLoadedContent);
}
}
@@ -0,0 +1,69 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.json.EBasicJsonNodeVarchar;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import java.util.Set;
import static org.junit.Assert.*;
public class TestJsonNodeVarchar extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNodeVarchar bean = new EBasicJsonNodeVarchar();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNodeVarchar bean1 = Ebean.find(EBasicJsonNodeVarchar.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().path("contentType").asText(), bean1.getContent().path("contentType").asText());
assertEquals(18L, bean1.getContent().get("docId").asLong());
}
@Test
public void testLazyLoading() throws IOException {
String s0 = "{\"docId\":19,\"contentId\":\"asd\",\"content\":{\"name\":\"rob\",\"age\":45}}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode content = objectMapper.readTree(s0);
EBasicJsonNodeVarchar bean = new EBasicJsonNodeVarchar();
bean.setName("lazyLoadTest");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonNodeVarchar bean1 = Ebean.find(EBasicJsonNodeVarchar.class)
.select("name")
.setId(bean.getId())
.findUnique();
Set<String> loadedProps = Ebean.getBeanState(bean1).getLoadedProps();
assertTrue(loadedProps.contains("name"));
assertFalse(loadedProps.contains("content"));
JsonNode lazyLoadedContent = bean1.getContent();
assertNotNull(lazyLoadedContent);
}
}
@@ -0,0 +1,56 @@
package com.avaje.tests.model.json;
import com.avaje.ebean.annotation.DbJson;
import com.fasterxml.jackson.databind.JsonNode;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.util.Map;
@Entity
public class EBasicJsonNode {
@Id
Long id;
@Version
Long version;
String name;
@DbJson
JsonNode content;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public JsonNode getContent() {
return content;
}
public void setContent(JsonNode content) {
this.content = content;
}
}
@@ -0,0 +1,56 @@
package com.avaje.tests.model.json;
import com.avaje.ebean.annotation.DbJson;
import com.avaje.ebean.annotation.DbJsonType;
import com.fasterxml.jackson.databind.JsonNode;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
@Entity
public class EBasicJsonNodeBlob {
@Id
Long id;
@Version
Long version;
String name;
@DbJson(storage = DbJsonType.BLOB)
JsonNode content;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public JsonNode getContent() {
return content;
}
public void setContent(JsonNode content) {
this.content = content;
}
}
@@ -0,0 +1,58 @@
package com.avaje.tests.model.json;
import com.avaje.ebean.annotation.DbJson;
import com.avaje.ebean.annotation.DbJsonB;
import com.avaje.ebean.annotation.DbJsonType;
import com.fasterxml.jackson.databind.JsonNode;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
@Entity
public class EBasicJsonNodeJsonB {
@Id
Long id;
@Version
Long version;
String name;
//@DbJson(storage = DbJsonType.JSONB)
@DbJsonB
JsonNode content;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public JsonNode getContent() {
return content;
}
public void setContent(JsonNode content) {
this.content = content;
}
}
@@ -0,0 +1,56 @@
package com.avaje.tests.model.json;
import com.avaje.ebean.annotation.DbJson;
import com.avaje.ebean.annotation.DbJsonType;
import com.fasterxml.jackson.databind.JsonNode;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
@Entity
public class EBasicJsonNodeVarchar {
@Id
Long id;
@Version
Long version;
String name;
@DbJson(storage = DbJsonType.VARCHAR, length = 1000)
JsonNode content;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public JsonNode getContent() {
return content;
}
public void setContent(JsonNode content) {
this.content = content;
}
}