From 13f7d37e76c0712f7daf59fb689191e4bdba8d8a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 6 May 2016 13:20:51 +1200 Subject: [PATCH] #542 - ENH: @DbJson fields are auto serialized and deserialized to specified classes. --- .../deploy/meta/DeployBeanProperty.java | 17 ++ .../deploy/parse/DeployCreateProperties.java | 2 +- .../server/deploy/parse/DeployUtil.java | 2 +- .../server/type/DefaultTypeManager.java | 62 +++- .../server/type/ModifyAwareSet.java | 7 + .../type/ScalarTypeJsonObjectMapper.java | 268 ++++++++++++++++++ .../server/type/TypeManager.java | 4 +- .../com/avaje/tests/json/TestDbJson_List.java | 72 ++++- .../tests/model/json/EBasicJsonList.java | 46 +++ .../com/avaje/tests/model/json/PlainBean.java | 55 ++++ 10 files changed, 516 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java create mode 100644 src/test/java/com/avaje/tests/model/json/PlainBean.java diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index beefce9eb..6934a2145 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -32,6 +32,7 @@ import javax.persistence.Id; import javax.persistence.Version; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.sql.Types; /** @@ -147,6 +148,8 @@ public class DeployBeanProperty { */ private final Class propertyType; + private final Type genericType; + /** * Set for Non-JDBC types to provide logical to db type conversion. */ @@ -208,10 +211,17 @@ public class DeployBeanProperty { public DeployBeanProperty(DeployBeanDescriptor desc, Class propertyType, ScalarType scalarType, ScalarTypeConverter typeConverter) { this.desc = desc; this.propertyType = propertyType; + this.genericType = null; this.scalarType = wrapScalarType(propertyType, scalarType, typeConverter); this.dbType = (scalarType == null) ? 0 : scalarType.getJdbcType(); } + public DeployBeanProperty(DeployBeanDescriptor desc, Class propertyType, Type genericType) { + this.desc = desc; + this.propertyType = propertyType; + this.genericType = genericType; + } + /** * Wrap the ScalarType using a ScalarTypeConverter. */ @@ -810,6 +820,13 @@ public class DeployBeanProperty { return propertyType; } + /** + * Return the generic type for this property. + */ + public Type getGenericType() { + return genericType; + } + /** * Return true if this is included in the unique id. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java index 071c57fbb..8362fdcc5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployCreateProperties.java @@ -230,7 +230,7 @@ public class DeployCreateProperties { } } if (isSpecialScalarType(field)) { - return new DeployBeanProperty(desc, propertyType, null, null); + return new DeployBeanProperty(desc, propertyType, field.getGenericType()); } // check for Collection type (list, set or map) diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployUtil.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployUtil.java index 52124a5f6..0d430f7e7 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployUtil.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/DeployUtil.java @@ -226,7 +226,7 @@ public class DeployUtil { private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength) { Class type = prop.getPropertyType(); - ScalarType scalarType = typeManager.getJsonScalarType(type, dbType, dbLength); + ScalarType scalarType = typeManager.getJsonScalarType(type, dbType, dbLength, prop.getGenericType()); if (scalarType == null) { throw new RuntimeException("No ScalarType for JSON type [" + type + "] [" + dbType + "]"); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java index 503019e3d..3da28dbd3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/DefaultTypeManager.java @@ -33,6 +33,8 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; @@ -144,7 +146,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { private final JsonConfig.DateTime jsonDateTime; - private final boolean objectMapperPresent; + private final Object objectMapper; private final boolean java7Present; @@ -187,7 +189,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { this.typeMap = new ConcurrentHashMap, ScalarType>(); this.nativeMap = new ConcurrentHashMap>(); - this.objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent(); + boolean objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent(); + this.objectMapper = (objectMapperPresent) ? initObjectMapper(config) : null; this.extraTypeFactory = new DefaultTypeFactory(config); this.postgres = isPostgres(config.getDatabasePlatform()); @@ -355,18 +358,30 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { } @Override - public ScalarType getJsonScalarType(Class type, int dbType, int dbLength) { + public ScalarType getJsonScalarType(Class type, int dbType, int dbLength, Type genericType) { if (type.equals(List.class)) { - return ScalarTypeJsonList.typeFor(postgres, dbType); + if (isValueTypeSimple(genericType)) { + return ScalarTypeJsonList.typeFor(postgres, dbType); + } else { + return createJsonObjectMapperType(type, genericType, dbType); + } } if (type.equals(Set.class)) { - return ScalarTypeJsonSet.typeFor(postgres, dbType); + if (isValueTypeSimple(genericType)) { + return ScalarTypeJsonSet.typeFor(postgres, dbType); + } else { + return createJsonObjectMapperType(type, genericType, dbType); + } } if (type.equals(Map.class)) { - return ScalarTypeJsonMap.typeFor(postgres, dbType); + if (isMapValueTypeObject(genericType)) { + return ScalarTypeJsonMap.typeFor(postgres, dbType); + } else { + return createJsonObjectMapperType(type, genericType, dbType); + } } if (type.equals(JsonNode.class)) { @@ -381,7 +396,30 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { } } - throw new IllegalArgumentException("Type [" + type + "] unsupported for @DbJson mapping"); + return createJsonObjectMapperType(type, type, dbType); + } + + /** + * Return true if value parameter type of the map is Object. + */ + private boolean isValueTypeSimple(Type genericType) { + Type[] typeArgs = ((ParameterizedType) genericType).getActualTypeArguments(); + return String.class.equals(typeArgs[0]) || Long.class.equals(typeArgs[0]); + } + + /** + * Return true if value parameter type of the map is Object. + */ + private boolean isMapValueTypeObject(Type genericType) { + Type[] typeArgs = ((ParameterizedType) genericType).getActualTypeArguments(); + return Object.class.equals(typeArgs[1]); + } + + private ScalarType createJsonObjectMapperType(Class type, Type genericType, int dbType) { + if (objectMapper == null) { + throw new IllegalArgumentException("Type [" + type + "] unsupported for @DbJson mapping - Jackson ObjectMapper not present"); + } + return ScalarTypeJsonObjectMapper.createTypeFor(postgres, type, (ObjectMapper) objectMapper, genericType, dbType); } /** @@ -610,15 +648,13 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { try { ScalarType scalarType; - if (!objectMapperPresent) { + if (objectMapper == null) { scalarType = (ScalarType) cls.newInstance(); - } else { try { // first try objectMapper constructor Constructor constructor = cls.getConstructor(ObjectMapper.class); - ObjectMapper objectMapper = getObjectMapper(serverConfig); - scalarType = (ScalarType)constructor.newInstance(objectMapper); + scalarType = (ScalarType)constructor.newInstance((ObjectMapper)objectMapper); } catch (NoSuchMethodException e) { scalarType = (ScalarType) cls.newInstance(); } @@ -634,9 +670,9 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable { } } - private ObjectMapper getObjectMapper(ServerConfig serverConfig) { + private Object initObjectMapper(ServerConfig serverConfig) { - ObjectMapper objectMapper = (ObjectMapper)serverConfig.getObjectMapper(); + Object objectMapper = serverConfig.getObjectMapper(); if (objectMapper == null) { objectMapper = new ObjectMapper(); serverConfig.setObjectMapper(objectMapper); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ModifyAwareSet.java b/src/main/java/com/avaje/ebeaninternal/server/type/ModifyAwareSet.java index 8bd1da4ae..fbfdff06b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/ModifyAwareSet.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ModifyAwareSet.java @@ -14,6 +14,13 @@ public class ModifyAwareSet extends ModifyAwareCollection implements Set s) { + super(new ModifyAwareFlag(), s); + } + @Override public boolean isMarkedDirty() { return owner.isMarkedDirty(); diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java new file mode 100644 index 000000000..aba059ef7 --- /dev/null +++ b/src/main/java/com/avaje/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java @@ -0,0 +1,268 @@ +package com.avaje.ebeaninternal.server.type; + +import com.avaje.ebean.config.dbplatform.DbType; +import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.persistence.PersistenceException; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.lang.reflect.Type; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Supports @DbJson properties using Jackson ObjectMapper. + */ +public class ScalarTypeJsonObjectMapper { + + /** + * Create and return the appropriate ScalarType. + * + * @param postgres + * @param type The field/property type + * @param objectMapper The Jackson ObjectMapper to use for marshalling + * @param genericType The generic type + * @param dbType The DB storage type to use + */ + public static ScalarType createTypeFor(boolean postgres, Class type, ObjectMapper objectMapper, Type genericType, int dbType) { + + String pgType = getPostgresType(postgres, dbType); + if (Set.class.equals(type)) { + return new OmSet(objectMapper, genericType, dbType, pgType); + } + if (List.class.equals(type)) { + return new OmList(objectMapper, genericType, dbType, pgType); + } + if (Map.class.equals(type)) { + return new OmMap(objectMapper, genericType, dbType, pgType); + } + return new GenericObject(objectMapper, genericType, dbType, pgType); + } + + private static String getPostgresType(boolean postgres, int dbType) { + if (postgres) { + switch (dbType) { + case DbType.JSON : return PostgresHelper.JSON_TYPE; + case DbType.JSONB : return PostgresHelper.JSONB_TYPE; + } + } + return null; + } + + /** + * Maps any type (Object) using Jackson ObjectMapper. + */ + private static class GenericObject extends Base { + + public GenericObject(ObjectMapper objectMapper, Type type, int dbType, String pgType) { + super(Object.class, objectMapper, type, dbType, pgType); + } + } + + /** + * Type for Sets wrapping the ObjectMapper Set as a ModifyAwareSet. + */ + private static class OmSet extends Base { + + public OmSet(ObjectMapper objectMapper, Type type, int dbType, String pgType) { + super(Set.class, objectMapper, type, dbType, pgType); + } + + @Override + @SuppressWarnings("unchecked") + public Set read(DataReader reader) throws SQLException { + Set value = super.read(reader); + return value == null ? null : new ModifyAwareSet(value); + } + } + + /** + * Type for Lists wrapping the ObjectMapper List as a ModifyAwareList. + */ + private static class OmList extends Base { + + public OmList(ObjectMapper objectMapper, Type type, int dbType, String pgType) { + super(List.class, objectMapper, type, dbType, pgType); + } + + @Override + @SuppressWarnings("unchecked") + public List read(DataReader reader) throws SQLException { + List value = super.read(reader); + return value == null ? null : new ModifyAwareList(value); + } + } + + /** + * Type for Map wrapping the ObjectMapper Map as a ModifyAwareMap. + */ + private static class OmMap extends Base { + + public OmMap(ObjectMapper objectMapper, Type type, int dbType, String pgType) { + super(Map.class, objectMapper, type, dbType, pgType); + } + + @Override + @SuppressWarnings("unchecked") + public Map read(DataReader reader) throws SQLException { + Map value = super.read(reader); + return value == null ? null : new ModifyAwareMap(value); + } + } + + /** + * ScalarType that uses Jackson ObjectMapper to marshall/unmarshall to/from JSON + * and storing them in one of JSON, JSONB, VARCHAR, CLOB or BLOB. + */ + private static abstract class Base extends ScalarTypeBase { + + private final ObjectMapper objectMapper; + + private final JavaType javaType; + + private final String pgType; + + /** + * Construct given the object mapper, property type and DB type for storage. + * + * @param objectMapper Jackson object mapper for JSON marshalling/unmarshalling + * @param type The property type (ie. type of field with @DbJson) + * @param dbType The DB type used for storage (JSON, JSONB, VARCHAR, CLOB or BLOB) + */ + public Base(Class cls, ObjectMapper objectMapper, Type type, int dbType, String pgType) { + super(cls, false, dbType); + this.pgType = pgType; + this.objectMapper = objectMapper; + this.javaType = objectMapper.getTypeFactory().constructType(type); + } + + /** + * 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 T read(DataReader reader) throws SQLException { + String json = reader.getString(); + if (json == null || json.isEmpty()) { + return null; + } + try { + return objectMapper.readValue(json, javaType); + } catch (IOException e) { + throw new SQLException("Unable to convert JSON", e); + } + } + + @Override + public void bind(DataBind bind, T value) throws SQLException { + if (pgType != null) { + String rawJson = (value == null) ? null : formatValue(value); + bind.setObject(PostgresHelper.asObject(pgType, rawJson)); + } else { + if (value == null) { + bind.setNull(jdbcType); + } else { + try { + String json = objectMapper.writeValueAsString(value); + bind.setString(json); + } catch (JsonProcessingException e) { + throw new SQLException("Unable to create JSON", e); + } + } + } + } + + @Override + public Object toJdbcType(Object value) { + // no type conversion supported + return value; + } + + @Override + public T toBeanType(Object value) { + // no type conversion supported + return (T) value; + } + + @Override + public String formatValue(T value) { + try { + return objectMapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new PersistenceException("Unable to create JSON", e); + } + } + + @Override + public T parse(String value) { + try { + return objectMapper.readValue(value, javaType); + } catch (IOException e) { + throw new PersistenceException("Unable to convert JSON", e); + } + } + + @Override + public DocPropertyType getDocType() { + return DocPropertyType.OBJECT; + } + + @Override + public boolean isDateTimeCapable() { + return false; + } + + @Override + public T convertFromMillis(long dateTime) { + throw new IllegalStateException("Not supported"); + } + + @Override + public T jsonRead(JsonParser parser) throws IOException { + return objectMapper.readValue(parser, javaType); + } + + @Override + public void jsonWrite(JsonGenerator writer, T value) throws IOException { + objectMapper.writeValue(writer, value); + } + + @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)); + } + } + } +} diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/TypeManager.java b/src/main/java/com/avaje/ebeaninternal/server/type/TypeManager.java index be47722d0..bf7ed1b62 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/type/TypeManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/type/TypeManager.java @@ -2,6 +2,8 @@ package com.avaje.ebeaninternal.server.type; import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse; +import java.lang.reflect.Type; + /** * Convert an Object to the required type. */ @@ -63,5 +65,5 @@ public interface TypeManager { * Note that type expected to be JsonNode or Map. *

*/ - ScalarType getJsonScalarType(Class type, int dbType, int dbLength); + ScalarType getJsonScalarType(Class type, int dbType, int dbLength, Type genericType); } diff --git a/src/test/java/com/avaje/tests/json/TestDbJson_List.java b/src/test/java/com/avaje/tests/json/TestDbJson_List.java index 7e876027d..fc96b7f3f 100644 --- a/src/test/java/com/avaje/tests/json/TestDbJson_List.java +++ b/src/test/java/com/avaje/tests/json/TestDbJson_List.java @@ -3,13 +3,19 @@ package com.avaje.tests.json; import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; import com.avaje.tests.model.json.EBasicJsonList; +import com.avaje.tests.model.json.PlainBean; import org.avaje.ebeantest.LoggedSqlCollector; import org.junit.Test; +import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class TestDbJson_List extends BaseTestCase { @@ -30,6 +36,22 @@ public class TestDbJson_List extends BaseTestCase { bean.getFlags().add(43L); bean.getFlags().add(44L); + bean.setPlainBean(new PlainBean("plain", 52)); + + List beanList = new ArrayList(); + beanList.add(new PlainBean("one", 1)); + beanList.add(new PlainBean("two", 2)); + bean.setBeanList(beanList); + + + Set beanSet = new LinkedHashSet(); + beanSet.add(new PlainBean("A", 1)); + beanSet.add(new PlainBean("B", 2)); + bean.setBeanSet(beanSet); + + bean.getBeanMap().put("key0", new PlainBean("k0", 90)); + bean.getBeanMap().put("key1", new PlainBean("k1", 91)); + Ebean.save(bean); found = Ebean.find(EBasicJsonList.class, bean.getId()); @@ -38,11 +60,15 @@ public class TestDbJson_List extends BaseTestCase { assertTrue(found.getFlags().contains(42L)); assertTrue(found.getFlags().contains(43L)); assertTrue(found.getFlags().contains(44L)); + assertThat(found.getBeanList()).hasSize(2); + assertThat(found.getBeanSet()).hasSize(2); + assertThat(found.getBeanMap()).hasSize(2); json_parse_format(); update_when_notDirty(); update_when_dirty(); update_when_dirty_flags(); + update_when_dirty_SetListMap(); } //@Test//(dependsOnMethods = "insert") @@ -51,6 +77,10 @@ public class TestDbJson_List extends BaseTestCase { String asJson = Ebean.json().toJson(found); assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]"); assertThat(asJson).contains("\"flags\":[42,43,44]"); + assertThat(asJson).contains("\"plainBean\":{\"name\":\"plain\""); + assertThat(asJson).contains("\"beanSet\":["); + assertThat(asJson).contains("\"beanList\":["); + assertThat(asJson).contains("\"beanMap\":{"); assertThat(asJson).contains("\"id\":"); EBasicJsonList fromJson = Ebean.json().toBean(EBasicJsonList.class, asJson); @@ -62,6 +92,9 @@ public class TestDbJson_List extends BaseTestCase { assertTrue(fromJson.getFlags().contains(43L)); assertTrue(fromJson.getFlags().contains(44L)); + assertThat(fromJson.getBeanSet()).hasSize(2); + assertThat(fromJson.getBeanList()).hasSize(2); + assertThat(fromJson.getBeanMap()).hasSize(2); } //@Test//(dependsOnMethods = "insert") @@ -73,7 +106,7 @@ public class TestDbJson_List extends BaseTestCase { List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) - assertThat(sql.get(0)).contains("update ebasic_json_list set name=?, version=? where"); + assertThat(sql.get(0)).contains("update ebasic_json_list set name=?, plain_bean=?, version=? where"); } public void update_when_dirty() { @@ -86,7 +119,7 @@ public class TestDbJson_List extends BaseTestCase { List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) - assertThat(sql.get(0)).contains("update ebasic_json_list set tags=?, version=? where"); + assertThat(sql.get(0)).contains("update ebasic_json_list set plain_bean=?, tags=?, version=? where id=? and version=?"); } public void update_when_dirty_flags() { @@ -99,7 +132,40 @@ public class TestDbJson_List extends BaseTestCase { List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) - assertThat(sql.get(0)).contains("update ebasic_json_list set flags=?, version=? where"); + assertThat(sql.get(0)).contains("update ebasic_json_list set plain_bean=?, flags=?, version=? where id=? and version=?;"); } + public void update_when_dirty_SetListMap() { + + //found.setName("modAgain"); + found.getBeanSet().clear(); + found.getBeanList().clear(); + found.getBeanMap().remove("key0"); + + LoggedSqlCollector.start(); + Ebean.save(found); + List sql = LoggedSqlCollector.stop(); + + // we don't update the phone numbers (as they are not dirty) + assertThat(sql.get(0)).contains("update ebasic_json_list set bean_set=?, bean_list=?, bean_map=?, plain_bean=?, version=? where id=? and version=?"); + } + + @Test + public void insert_fetch_when_null() { + + EBasicJsonList bean = new EBasicJsonList(); + bean.setName("leave some nulls"); + bean.setFlags(null); + bean.setTags(null); + bean.setBeanMap(null); + + Ebean.save(bean); + + EBasicJsonList found = Ebean.find(EBasicJsonList.class, bean.getId()); + + assertNull(found.getPlainBean()); + + String asJson = Ebean.json().toJson(found); + assertNotNull(asJson); + } } diff --git a/src/test/java/com/avaje/tests/model/json/EBasicJsonList.java b/src/test/java/com/avaje/tests/model/json/EBasicJsonList.java index 9d6688a08..64d1256a5 100644 --- a/src/test/java/com/avaje/tests/model/json/EBasicJsonList.java +++ b/src/test/java/com/avaje/tests/model/json/EBasicJsonList.java @@ -7,8 +7,10 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Version; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; @Entity @@ -19,6 +21,18 @@ public class EBasicJsonList { String name; + @DbJson(length = 700) + Set beanSet; + + @DbJson(length = 700) + List beanList; + + @DbJson(length = 700) + Map beanMap = new LinkedHashMap(); + + @DbJson(length = 500) + PlainBean plainBean; + @DbJson(length = 50) Set flags = new LinkedHashSet(); @@ -60,6 +74,38 @@ public class EBasicJsonList { this.flags = flags; } + public PlainBean getPlainBean() { + return plainBean; + } + + public void setPlainBean(PlainBean plainBean) { + this.plainBean = plainBean; + } + + public Set getBeanSet() { + return beanSet; + } + + public void setBeanSet(Set beanSet) { + this.beanSet = beanSet; + } + + public List getBeanList() { + return beanList; + } + + public void setBeanList(List beanList) { + this.beanList = beanList; + } + + public Map getBeanMap() { + return beanMap; + } + + public void setBeanMap(Map beanMap) { + this.beanMap = beanMap; + } + public Long getVersion() { return version; } diff --git a/src/test/java/com/avaje/tests/model/json/PlainBean.java b/src/test/java/com/avaje/tests/model/json/PlainBean.java new file mode 100644 index 000000000..3e8c9d7c5 --- /dev/null +++ b/src/test/java/com/avaje/tests/model/json/PlainBean.java @@ -0,0 +1,55 @@ +package com.avaje.tests.model.json; + +import java.sql.Timestamp; + +/** + * Something for Jackson ObjectMapper to marshall. + */ +public class PlainBean { + + String name; + + long along; + + Timestamp timestamp; + + public PlainBean(String name, long along) { + this.name = name; + this.along = along; + this.timestamp = new Timestamp(System.currentTimeMillis()); + } + + /** + * A constructor for Jackson. + */ + public PlainBean() { + } + + public String toString() { + return "name:" + name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getAlong() { + return along; + } + + public void setAlong(long along) { + this.along = along; + } + + public Timestamp getTimestamp() { + return timestamp; + } + + public void setTimestamp(Timestamp timestamp) { + this.timestamp = timestamp; + } +}