#2148 - PersistenceException: No ScalarType registered for class java.util.LinkedHashMap

This commit is contained in:
rob bygrave committed 2021-01-20 23:31:45 +13:00
1 parent 449e0832e0
commit 5eac31283d
4 files changed
+96 -46

No files matched your search

@@ -3,6 +3,9 @@ package io.ebeaninternal.server.querydefn;
import io.ebean.ExpressionList; import io.ebean.ExpressionList;
import io.ebean.ProfileLocation; import io.ebean.ProfileLocation;
import io.ebean.UpdateQuery; import io.ebean.UpdateQuery;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
/** /**
* Default implementation of UpdateQuery. * Default implementation of UpdateQuery.
@@ -10,23 +13,30 @@ import io.ebean.UpdateQuery;
public class DefaultUpdateQuery<T> implements UpdateQuery<T> { public class DefaultUpdateQuery<T> implements UpdateQuery<T> {
private final OrmUpdateProperties values = new OrmUpdateProperties(); private final OrmUpdateProperties values = new OrmUpdateProperties();
private final DefaultOrmQuery<T> query; private final DefaultOrmQuery<T> query;
private final BeanDescriptor<T> descriptor;
public DefaultUpdateQuery(DefaultOrmQuery<T> query) { public DefaultUpdateQuery(DefaultOrmQuery<T> query) {
this.query = query; this.query = query;
this.descriptor = query.getBeanDescriptor();
query.setUpdateProperties(values); query.setUpdateProperties(values);
} }
@Override @Override
public UpdateQuery<T> set(String property, Object value) { public UpdateQuery<T> set(String property, Object value) {
values.set(property, value); if (value == null) {
values.setNull(property);
} else {
final BeanProperty beanProperty = descriptor.getBeanProperty(property);
final ScalarType<Object> scalarType = (beanProperty == null) ? null: beanProperty.getScalarType();
values.set(property, value, scalarType);
}
return this; return this;
} }
@Override @Override
public UpdateQuery<T> setNull(String property) { public UpdateQuery<T> setNull(String property) {
values.set(property, null); values.setNull(property);
return this; return this;
} }
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn; package io.ebeaninternal.server.querydefn;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.DeployParser; import io.ebeaninternal.server.deploy.DeployParser;
import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.type.DataBind; import io.ebeaninternal.server.type.DataBind;
@@ -53,9 +54,11 @@ public class OrmUpdateProperties {
private static class SimpleValue extends Value { private static class SimpleValue extends Value {
final Object value; final Object value;
final ScalarType<Object> scalarType;
SimpleValue(Object value) { SimpleValue(Object value, ScalarType<Object> scalarType) {
this.value = value; this.value = value;
this.scalarType = scalarType;
} }
@Override @Override
@@ -70,7 +73,11 @@ public class OrmUpdateProperties {
@Override @Override
public void bind(Binder binder, DataBind dataBind) throws SQLException { public void bind(Binder binder, DataBind dataBind) throws SQLException {
binder.bindObject(dataBind, value); if (scalarType != null) {
scalarType.bind(dataBind, value);
} else {
binder.bindObject(dataBind, value);
}
dataBind.append(value).append(","); dataBind.append(value).append(",");
} }
} }
@@ -115,16 +122,12 @@ public class OrmUpdateProperties {
*/ */
private final LinkedHashMap<String, Value> values = new LinkedHashMap<>(); private final LinkedHashMap<String, Value> values = new LinkedHashMap<>();
/** public void set(String propertyName, Object value, ScalarType<Object> scalarType) {
* Normal set property. values.put(propertyName, new SimpleValue(value, scalarType));
*/ }
public void set(String propertyName, Object value) {
if (value == null) {
values.put(propertyName, NULL_VALUE);
} else { public void setNull(String propertyName) {
values.put(propertyName, new SimpleValue(value)); values.put(propertyName, NULL_VALUE);
}
} }
/** /**
@@ -1,7 +1,7 @@
package org.tests.json; package org.tests.json;
import io.ebean.BaseTestCase; import io.ebean.BaseTestCase;
import io.ebean.Ebean; import io.ebean.DB;
import io.ebean.annotation.ForPlatform; import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.Platform; import io.ebean.annotation.Platform;
import io.ebean.text.TextException; import io.ebean.text.TextException;
@@ -25,7 +25,7 @@ import static org.junit.Assert.assertTrue;
public class TestDbJson_List extends BaseTestCase { public class TestDbJson_List extends BaseTestCase {
private EBasicJsonList bean = new EBasicJsonList(); private final EBasicJsonList bean = new EBasicJsonList();
private EBasicJsonList found; private EBasicJsonList found;
@@ -57,9 +57,9 @@ public class TestDbJson_List extends BaseTestCase {
bean.getBeanMap().put("key0", new PlainBean("k0", 90)); bean.getBeanMap().put("key0", new PlainBean("k0", 90));
bean.getBeanMap().put("key1", new PlainBean("k1", 91)); bean.getBeanMap().put("key1", new PlainBean("k1", 91));
Ebean.save(bean); DB.save(bean);
found = Ebean.find(EBasicJsonList.class, bean.getId()); found = DB.find(EBasicJsonList.class, bean.getId());
assertThat(found.getTags()).containsExactly("one", "two"); assertThat(found.getTags()).containsExactly("one", "two");
assertTrue(found.getFlags().contains(42L)); assertTrue(found.getFlags().contains(42L));
@@ -81,7 +81,7 @@ public class TestDbJson_List extends BaseTestCase {
//@Test//(dependsOnMethods = "insert") //@Test//(dependsOnMethods = "insert")
public void json_parse_format() { public void json_parse_format() {
String asJson = Ebean.json().toJson(found); String asJson = DB.json().toJson(found);
assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]"); assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]");
assertThat(asJson).contains("\"flags\":[42,43,44]"); assertThat(asJson).contains("\"flags\":[42,43,44]");
assertThat(asJson).contains("\"plainBean\":{\"name\":\"plain\""); assertThat(asJson).contains("\"plainBean\":{\"name\":\"plain\"");
@@ -90,7 +90,7 @@ public class TestDbJson_List extends BaseTestCase {
assertThat(asJson).contains("\"beanMap\":{"); assertThat(asJson).contains("\"beanMap\":{");
assertThat(asJson).contains("\"id\":"); assertThat(asJson).contains("\"id\":");
EBasicJsonList fromJson = Ebean.json().toBean(EBasicJsonList.class, asJson); EBasicJsonList fromJson = DB.json().toBean(EBasicJsonList.class, asJson);
assertEquals(found.getId(), fromJson.getId()); assertEquals(found.getId(), fromJson.getId());
assertEquals(found.getId(), fromJson.getId()); assertEquals(found.getId(), fromJson.getId());
assertEquals(found.getName(), fromJson.getName()); assertEquals(found.getName(), fromJson.getName());
@@ -109,7 +109,7 @@ public class TestDbJson_List extends BaseTestCase {
found.setName("mod"); found.setName("mod");
LoggedSqlCollector.start(); LoggedSqlCollector.start();
Ebean.save(found); DB.save(found);
List<String> sql = LoggedSqlCollector.stop(); List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty) // we don't update the phone numbers (as they are not dirty)
@@ -122,7 +122,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getTags().add("three"); found.getTags().add("three");
LoggedSqlCollector.start(); LoggedSqlCollector.start();
Ebean.save(found); DB.save(found);
List<String> sql = LoggedSqlCollector.stop(); List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty) // we don't update the phone numbers (as they are not dirty)
@@ -135,7 +135,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getFlags().remove(42L); found.getFlags().remove(42L);
LoggedSqlCollector.start(); LoggedSqlCollector.start();
Ebean.save(found); DB.save(found);
List<String> sql = LoggedSqlCollector.stop(); List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty) // we don't update the phone numbers (as they are not dirty)
@@ -150,7 +150,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getBeanMap().remove("key0"); found.getBeanMap().remove("key0");
LoggedSqlCollector.start(); LoggedSqlCollector.start();
Ebean.save(found); DB.save(found);
List<String> sql = LoggedSqlCollector.stop(); List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty) // we don't update the phone numbers (as they are not dirty)
@@ -166,13 +166,13 @@ public class TestDbJson_List extends BaseTestCase {
bean.setTags(null); bean.setTags(null);
bean.setBeanMap(null); bean.setBeanMap(null);
Ebean.save(bean); DB.save(bean);
EBasicJsonList found = Ebean.find(EBasicJsonList.class, bean.getId()); EBasicJsonList found = DB.find(EBasicJsonList.class, bean.getId());
assertNull(found.getPlainBean()); assertNull(found.getPlainBean());
String asJson = Ebean.json().toJson(found); String asJson = DB.json().toJson(found);
assertNotNull(asJson); assertNotNull(asJson);
} }
@@ -186,17 +186,16 @@ public class TestDbJson_List extends BaseTestCase {
plainBean.setName("Blubb"); plainBean.setName("Blubb");
bean.getBeanMap().put("bla", plainBean); bean.getBeanMap().put("bla", plainBean);
Ebean.save(bean); DB.save(bean);
// set some invalid JSON content into DB // set some invalid JSON content into DB
Ebean.update(EBasicJsonList.class) DB.sqlUpdate("update ebasic_json_list set bean_map=? where id=?")
.set("beanMap", "blabla") .setParameters("blabla", bean.getId())
.where().eq("id", bean.getId()) .execute();
.update();
try { try {
// a normal query fails due to invalid JSON content // a normal query fails due to invalid JSON content
Ebean.find(EBasicJsonList.class) DB.find(EBasicJsonList.class)
.setId(bean.getId()) .setId(bean.getId())
.findOne(); .findOne();
@@ -208,7 +207,7 @@ public class TestDbJson_List extends BaseTestCase {
assertThat(e.getMessage()).contains("beanMap"); assertThat(e.getMessage()).contains("beanMap");
} }
bean = Ebean.find(EBasicJsonList.class) bean = DB.find(EBasicJsonList.class)
.setId(bean.getId()) .setId(bean.getId())
.setAllowLoadErrors() // allow invalid JSON content .setAllowLoadErrors() // allow invalid JSON content
.findOne(); .findOne();
@@ -220,6 +219,6 @@ public class TestDbJson_List extends BaseTestCase {
.isInstanceOf(TextException.class) .isInstanceOf(TextException.class)
.hasMessageContaining("blabla"); .hasMessageContaining("blabla");
Ebean.delete(bean); DB.delete(bean);
} }
} }
@@ -1,14 +1,16 @@
package org.tests.json; package org.tests.json;
import io.ebean.BaseTestCase; import io.ebean.BaseTestCase;
import io.ebean.Ebean; import io.ebean.DB;
import io.ebean.Query; import io.ebean.Query;
import io.ebean.text.json.EJson; import io.ebean.text.json.EJson;
import io.ebeantest.LoggedSql;
import org.tests.model.json.EBasicJsonMap; import org.tests.model.json.EBasicJsonMap;
import org.junit.Test; import org.junit.Test;
import org.tests.model.json.EBasicJsonMapDetail; import org.tests.model.json.EBasicJsonMapDetail;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -29,9 +31,9 @@ public class TestJsonMapBasic extends BaseTestCase {
bean.getDetails().add(new EBasicJsonMapDetail("detail1")); bean.getDetails().add(new EBasicJsonMapDetail("detail1"));
bean.getDetails().add(new EBasicJsonMapDetail("detail2")); bean.getDetails().add(new EBasicJsonMapDetail("detail2"));
Ebean.save(bean); DB.save(bean);
Query<EBasicJsonMap> query1 = Ebean.find(EBasicJsonMap.class) Query<EBasicJsonMap> query1 = DB.find(EBasicJsonMap.class)
.fetch("details") .fetch("details")
.where().startsWith("details.name", "detail") .where().startsWith("details.name", "detail")
.query(); .query();
@@ -40,7 +42,7 @@ public class TestJsonMapBasic extends BaseTestCase {
assertThat(query1.getGeneratedSql()).contains("select distinct on (t0.id, t1.id) "); assertThat(query1.getGeneratedSql()).contains("select distinct on (t0.id, t1.id) ");
Query<EBasicJsonMap> query2 = Ebean.find(EBasicJsonMap.class) Query<EBasicJsonMap> query2 = DB.find(EBasicJsonMap.class)
.where().startsWith("details.name", "detail") .where().startsWith("details.name", "detail")
.query(); .query();
query2.findList(); query2.findList();
@@ -60,9 +62,9 @@ public class TestJsonMapBasic extends BaseTestCase {
bean.setName("one"); bean.setName("one");
bean.setContent(content); bean.setContent(content);
Ebean.save(bean); DB.save(bean);
EBasicJsonMap bean1 = Ebean.find(EBasicJsonMap.class, bean.getId()); EBasicJsonMap bean1 = DB.find(EBasicJsonMap.class, bean.getId());
assertEquals(bean.getId(), bean1.getId()); assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName()); assertEquals(bean.getName(), bean1.getName());
@@ -70,16 +72,16 @@ public class TestJsonMapBasic extends BaseTestCase {
assertEquals(18L, bean1.getContent().get("docId")); assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name"); bean1.setName("just change name");
Ebean.save(bean1); DB.save(bean1);
// content changes detected - dirty state so included in update // content changes detected - dirty state so included in update
Map<String, Object> content1 = bean1.getContent(); Map<String, Object> content1 = bean1.getContent();
content1.put("additional", "newValue"); content1.put("additional", "newValue");
content1.put("docId", 99L); content1.put("docId", 99L);
bean1.setName("two"); bean1.setName("two");
Ebean.save(bean1); DB.save(bean1);
EBasicJsonMap bean2 = Ebean.find(EBasicJsonMap.class, bean.getId()); EBasicJsonMap bean2 = DB.find(EBasicJsonMap.class, bean.getId());
// name changed and docId changed // name changed and docId changed
assertEquals("two", bean2.getName()); assertEquals("two", bean2.getName());
@@ -89,12 +91,48 @@ public class TestJsonMapBasic extends BaseTestCase {
content1.put("additional", "modValue"); content1.put("additional", "modValue");
bean1.setName("three"); bean1.setName("three");
bean1.setContent(content1); bean1.setContent(content1);
Ebean.save(bean1); DB.save(bean1);
EBasicJsonMap bean3 = Ebean.find(EBasicJsonMap.class, bean.getId()); EBasicJsonMap bean3 = DB.find(EBasicJsonMap.class, bean.getId());
assertEquals("three", bean3.getName()); assertEquals("three", bean3.getName());
assertEquals(99L, bean3.getContent().get("docId")); assertEquals(99L, bean3.getContent().get("docId"));
assertEquals("modValue", bean3.getContent().get("additional")); assertEquals("modValue", bean3.getContent().get("additional"));
} }
@Test
public void updateQuery_bindingMap() throws IOException {
String s0 = "{\"docId\":22,\"contentId\":\"initialDoc\"}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMap bean = new EBasicJsonMap();
bean.setName("one");
bean.setContent(content);
DB.save(bean);
String s1 = "{\"docId\":222,\"contentId\":\"updatedDoc222\"}";
Map<String, Object> content1 = EJson.parseObject(s1);
LoggedSql.start();
final int rows = DB.update(EBasicJsonMap.class)
.set("content", content1)
.where().eq("id", bean.getId())
.update();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("update ebasic_json_map set content=? where id = ?");
assertThat(rows).isEqualTo(1);
final EBasicJsonMap found = DB.find(EBasicJsonMap.class, bean.getId());
final Map<String, Object> content2 = found.getContent();
assertThat(content2.get("contentId")).isEqualTo("updatedDoc222");
assertThat(content2.get("docId")).isEqualTo(222L);
DB.delete(found);
}
} }