#297 - ENH: Add support for mapping Map<String,Object> as JSON content to DB including Postgres JSON and JSON types.

This commit is contained in:
rbygrave
2015-05-28 00:02:57 +12:00
parent 4e1cda691f
commit f5a2cf8ff9
37 changed files with 1898 additions and 193 deletions
@@ -1,6 +1,7 @@
package com.avaje.ebean.json;
import com.avaje.ebean.text.json.EJson;
import com.avaje.ebeaninternal.server.type.ModifyAwareMap;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import org.junit.Assert;
@@ -203,4 +204,46 @@ public class EJsonTests {
}
@Test
public void test_map_nested_modifyAware() throws IOException {
String jsonInput = "{\"name\":\"rob\",\"age\":12,\"org\":{\"name\":\"superorg\",\"rating\":4},\"nums\":[1,2,3]}";
ModifyAwareMap<String,Object> map = (ModifyAwareMap<String, Object>) EJson.parseObject(jsonInput, true);
Assert.assertFalse(map.isMarkedDirty());
Assert.assertEquals(4, map.size());
map.put("name", "jim");
Assert.assertTrue(map.isMarkedDirty());
}
@SuppressWarnings("unchecked")
@Test
public void test_map_nested_modifyAwareNestedList() throws IOException {
String jsonInput = "{\"name\":\"rob\",\"age\":12,\"org\":{\"name\":\"superorg\",\"rating\":4},\"nums\":[1,2,3]}";
ModifyAwareMap<String,Object> map = (ModifyAwareMap<String, Object>) EJson.parseObject(jsonInput, true);
Assert.assertFalse(map.isMarkedDirty());
List<Object> nums = (List<Object>) map.get("nums");
nums.add(4);
Assert.assertTrue(map.isMarkedDirty());
}
@SuppressWarnings("unchecked")
@Test
public void test_map_nested_modifyAwareNestedObject() throws IOException {
String jsonInput = "{\"name\":\"rob\",\"age\":12,\"org\":{\"name\":\"superorg\",\"rating\":4},\"nums\":[1,2,3]}";
ModifyAwareMap<String,Object> map = (ModifyAwareMap<String, Object>) EJson.parseObject(jsonInput, true);
Assert.assertFalse(map.isMarkedDirty());
Map<String,Object> org = (Map<String, Object>) map.get("org");
org.put("extra","foo");
Assert.assertTrue(map.isMarkedDirty());
}
}
@@ -0,0 +1,228 @@
package com.avaje.ebeaninternal.server.type;
import org.junit.Test;
import java.util.*;
import static org.junit.Assert.*;
public class ModifyAwareListTest {
private ModifyAwareList<String> createList() {
ArrayList list = new ArrayList();
list.addAll(Arrays.asList("A","B","C","D","E"));
return new ModifyAwareList<String>(list);
}
private ModifyAwareList<String> createEmptyList() {
return new ModifyAwareList<String>(new ArrayList<String>());
}
@Test
public void testSize() throws Exception {
assertEquals(5, createList().size());
}
@Test
public void testIsEmpty() throws Exception {
assertFalse(createList().isEmpty());
assertTrue(createEmptyList().isEmpty());
}
@Test
public void testContains() throws Exception {
assertTrue(createList().contains("B"));
assertFalse(createList().contains("Z"));
}
@Test
public void testIterator() throws Exception {
ModifyAwareList<String> list = createList();
Iterator<String> iterator = list.iterator();
assertTrue(iterator.hasNext());
assertEquals("A", iterator.next());
assertFalse(list.isMarkedDirty());
iterator.remove();
assertTrue(list.isMarkedDirty());
}
@Test
public void testToArray() throws Exception {
Object[] objects = createList().toArray();
assertEquals(5, objects.length);
assertEquals("A", objects[0]);
assertEquals("E", objects[4]);
}
@Test
public void testToArray1() throws Exception {
String[] objects = createList().toArray(new String[5]);
assertEquals(5, objects.length);
assertEquals("A", objects[0]);
assertEquals("E", objects[4]);
}
@Test
public void testAdd() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
list.add("F");
assertTrue(list.isMarkedDirty());
}
@Test
public void testRemove() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
list.remove("A");
assertTrue(list.isMarkedDirty());
}
@Test
public void testContainsAll() throws Exception {
ModifyAwareList<String> list = createList();
assertTrue(list.containsAll(Arrays.asList("A", "B")));
assertFalse(list.containsAll(Arrays.asList("A", "B", "Z")));
}
@Test
public void testAddAll() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
assertTrue(list.addAll(Arrays.asList("F", "G")));
assertTrue(list.isMarkedDirty());
}
@Test
public void testRemoveAll() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
assertTrue(list.removeAll(Arrays.asList("A", "G")));
assertTrue(list.isMarkedDirty());
}
@Test
public void testRetainAll() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
assertTrue(list.retainAll(Arrays.asList("A", "B")));
assertTrue(list.isMarkedDirty());
assertEquals(2, list.size());
}
@Test
public void testClear() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
list.clear();
assertTrue(list.isMarkedDirty());
assertEquals(0, list.size());
}
@Test
public void testGet() throws Exception {
ModifyAwareList<String> list = createList();
assertEquals("A", list.get(0));
assertEquals("B", list.get(1));
assertEquals("E", list.get(4));
}
@Test
public void testSet() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
list.set(0, "Z");
assertTrue(list.isMarkedDirty());
assertEquals(5, list.size());
}
@Test
public void testIndexOf() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
assertEquals(2, list.indexOf("C"));
assertEquals(-1, list.indexOf("Z"));
assertFalse(list.isMarkedDirty());
}
@Test
public void testLastIndexOf() throws Exception {
ModifyAwareList<String> list = createList();
assertFalse(list.isMarkedDirty());
assertEquals(2, list.lastIndexOf("C"));
assertEquals(-1, list.lastIndexOf("Z"));
assertFalse(list.isMarkedDirty());
}
@Test
public void testListIterator() throws Exception {
ModifyAwareList<String> list = createList();
ListIterator<String> iterator = list.listIterator();
assertTrue(iterator.hasNext());
assertEquals("A", iterator.next());
assertFalse(list.isMarkedDirty());
iterator.remove();
assertTrue(list.isMarkedDirty());
}
@Test
public void testListIterator1() throws Exception {
ModifyAwareList<String> list = createList();
ListIterator<String> iterator = list.listIterator(2);
assertTrue(iterator.hasNext());
assertEquals("C", iterator.next());
assertFalse(list.isMarkedDirty());
iterator.remove();
assertTrue(list.isMarkedDirty());
}
@Test
public void testSubList() throws Exception {
ModifyAwareList<String> list = createList();
List<String> sub = list.subList(1, 3);
assertEquals("B", sub.get(0));
assertEquals("C", sub.get(1));
assertFalse(list.isMarkedDirty());
sub.remove("C");
assertTrue(list.isMarkedDirty());
}
}
@@ -0,0 +1,180 @@
package com.avaje.ebeaninternal.server.type;
import org.junit.Test;
import java.util.*;
import static org.junit.Assert.*;
public class ModifyAwareMapTest {
private ModifyAwareMap<String, String> createMap() {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("A", "one");
map.put("B", "two");
map.put("C", "three");
map.put("D", "four");
map.put("E", "five");
return new ModifyAwareMap<String, String>(map);
}
private ModifyAwareMap<String, String> createEmptyMap() {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
return new ModifyAwareMap<String, String>(map);
}
@Test
public void testToString() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertEquals(map.map.toString(), map.toString());
}
@Test
public void testIsMarkedDirty() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
map.put("A", "change");
assertTrue(map.isMarkedDirty());
}
@Test
public void testMarkAsModified() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
map.markAsModified();
assertTrue(map.isMarkedDirty());
}
@Test
public void testSize() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertEquals(5, map.size());
}
@Test
public void testIsEmpty() throws Exception {
assertFalse(createMap().isEmpty());
assertTrue(createEmptyMap().isEmpty());
}
@Test
public void testContainsKey() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertTrue(map.containsKey("A"));
assertFalse(map.containsKey("Z"));
}
@Test
public void testContainsValue() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertTrue(map.containsValue("one"));
assertFalse(map.containsValue("junk"));
}
@Test
public void testGet() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertEquals("two", map.get("B"));
assertNull(map.get("Z"));
assertFalse(map.isMarkedDirty());
}
@Test
public void testPut() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
map.put("A", "mod");
assertTrue(map.isMarkedDirty());
}
@Test
public void testRemove() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
map.remove("A");
assertTrue(map.isMarkedDirty());
}
@Test
public void testPutAllWithEmpty() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
Map<String, String> other = new HashMap<String, String>();
map.putAll(other);
assertTrue(map.isMarkedDirty());
}
@Test
public void testPutAll() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
Map<String, String> other = new HashMap<String, String>();
other.put("A", "one");
map.putAll(other);
assertTrue(map.isMarkedDirty());
}
@Test
public void testClear() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
map.clear();
assertTrue(map.isMarkedDirty());
}
@Test
public void testKeySet() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
Set<String> keys = map.keySet();
assertEquals(map.size(), keys.size());
assertTrue(keys.contains("A"));
assertFalse(map.isMarkedDirty());
}
@Test
public void testValues() throws Exception {
ModifyAwareMap<String, String> map = createMap();
assertFalse(map.isMarkedDirty());
Collection<String> values = map.values();
assertEquals(map.size(), values.size());
assertTrue(values.contains("one"));
assertFalse(map.isMarkedDirty());
}
@Test
public void testEntrySet() throws Exception {
ModifyAwareMap<String, String> map = createMap();
Set<Map.Entry<String, String>> entries = map.entrySet();
assertFalse(map.isMarkedDirty());
assertEquals(map.size(), entries.size());
assertFalse(map.isMarkedDirty());
}
}
@@ -0,0 +1,67 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.text.json.EJson;
import com.avaje.tests.model.json.EBasicJsonMap;
import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class TestJsonMapBasic 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\":19,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMap bean = new EBasicJsonMap();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonMap bean1 = Ebean.find(EBasicJsonMap.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().get("contentType"), bean1.getContent().get("contentType"));
assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name");
Ebean.save(bean1);
// content changes detected - dirty state so included in update
Map<String, Object> content1 = bean1.getContent();
content1.put("additional", "newValue");
content1.put("docId", 99L);
bean1.setName("two");
Ebean.save(bean1);
EBasicJsonMap bean2 = Ebean.find(EBasicJsonMap.class, bean.getId());
// name changed and docId changed
assertEquals("two", bean2.getName());
assertEquals(99L, bean2.getContent().get("docId"));
assertEquals("newValue", bean2.getContent().get("additional"));
content1.put("additional", "modValue");
bean1.setName("three");
bean1.setContent(content1);
Ebean.save(bean1);
EBasicJsonMap bean3 = Ebean.find(EBasicJsonMap.class, bean.getId());
assertEquals("three", bean3.getName());
assertEquals(99L, bean3.getContent().get("docId"));
assertEquals("modValue", bean3.getContent().get("additional"));
}
}
@@ -0,0 +1,40 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.text.json.EJson;
import com.avaje.tests.model.json.EBasicJsonMapBlob;
import com.avaje.tests.model.json.EBasicJsonMapVarchar;
import org.junit.Test;
import java.io.IOException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class TestJsonMapBlob extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMapBlob bean = new EBasicJsonMapBlob();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonMapBlob bean1 = Ebean.find(EBasicJsonMapBlob.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().get("contentType"), bean1.getContent().get("contentType"));
assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name");
Ebean.save(bean1);
}
}
@@ -0,0 +1,40 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.text.json.EJson;
import com.avaje.tests.model.json.EBasicJsonMapJsonB;
import com.avaje.tests.model.json.EBasicJsonMapJsonB;
import org.junit.Test;
import java.io.IOException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class TestJsonMapJsonB extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMapJsonB bean = new EBasicJsonMapJsonB();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonMapJsonB bean1 = Ebean.find(EBasicJsonMapJsonB.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().get("contentType"), bean1.getContent().get("contentType"));
assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name");
Ebean.save(bean1);
}
}
@@ -0,0 +1,40 @@
package com.avaje.tests.json;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.text.json.EJson;
import com.avaje.tests.model.json.EBasicJsonMap;
import com.avaje.tests.model.json.EBasicJsonMapVarchar;
import org.junit.Test;
import java.io.IOException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class TestJsonMapVarchar extends BaseTestCase {
@Test
public void testInsertUpdateDelete() throws IOException {
String s0 = "{\"docId\":18,\"contentId\":\"asd\",\"active\":true,\"contentType\":\"pg-hello\",\"content\":{\"name\":\"rob\",\"age\":45}}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMapVarchar bean = new EBasicJsonMapVarchar();
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
EBasicJsonMapVarchar bean1 = Ebean.find(EBasicJsonMapVarchar.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
assertEquals(bean.getContent().get("contentType"), bean1.getContent().get("contentType"));
assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name");
Ebean.save(bean1);
}
}
@@ -0,0 +1,55 @@
package com.avaje.tests.model.json;
import com.avaje.ebean.annotation.DbJson;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.util.Map;
@Entity
public class EBasicJsonMap {
@Id
Long id;
@Version
Long version;
String name;
@DbJson
Map<String,Object> 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 Map<String, Object> getContent() {
return content;
}
public void setContent(Map<String, Object> 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 javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.util.Map;
@Entity
public class EBasicJsonMapBlob {
@Id
Long id;
@Version
Long version;
String name;
@DbJson(storage = DbJsonType.BLOB)
Map<String,Object> 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 Map<String, Object> getContent() {
return content;
}
public void setContent(Map<String, Object> content) {
this.content = content;
}
}
@@ -0,0 +1,55 @@
package com.avaje.tests.model.json;
import com.avaje.ebean.annotation.DbJsonB;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.util.Map;
@Entity
public class EBasicJsonMapJsonB {
@Id
Long id;
@Version
Long version;
String name;
@DbJsonB
Map<String,Object> 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 Map<String, Object> getContent() {
return content;
}
public void setContent(Map<String, Object> 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 javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.util.Map;
@Entity
public class EBasicJsonMapVarchar {
@Id
Long id;
@Version
Long version;
String name;
@DbJson(storage = DbJsonType.VARCHAR)//, length = 2200)
Map<String,Object> 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 Map<String, Object> getContent() {
return content;
}
public void setContent(Map<String, Object> content) {
this.content = content;
}
}