You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2019/08/19 13:49:05 UTC
[cayenne] branch STABLE-4.1 updated: CAY-2606 Can't resolve obj
path with embeddable component
This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch STABLE-4.1
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/STABLE-4.1 by this push:
new 4c0bd42 CAY-2606 Can't resolve obj path with embeddable component
4c0bd42 is described below
commit 4c0bd42379f6850ccee3d3f3a1726a979757e4e2
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Mon Aug 19 16:48:37 2019 +0300
CAY-2606 Can't resolve obj path with embeddable component
---
RELEASE-NOTES.txt | 1 +
.../apache/cayenne/map/PathComponentIterator.java | 15 ++++-
.../org/apache/cayenne/access/EmbeddingIT.java | 63 +++++++++++++++++-
.../cayenne/testdo/embeddable/EmbedEntity2.java | 9 +++
.../testdo/embeddable/auto/_EmbedEntity1.java | 24 +++++++
.../{_EmbedEntity1.java => _EmbedEntity2.java} | 75 +++++++++++-----------
.../src/test/resources/cayenne-embeddable.xml | 2 +
.../src/test/resources/embeddable.map.xml | 25 +++++++-
8 files changed, 169 insertions(+), 45 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 953bc62..dce7b52 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -34,6 +34,7 @@ CAY-2600 Modeler DbImport: Can't retrieve schema for databases with no catalog s
CAY-2601 Modeler DbImport: result dialog issues
CAY-2603 NPE reloading project in the model
CAY-2605 Modeler: Unable to save - java.nio.file.InvalidPathException
+CAY-2606 Can't resolve obj path with embeddable component
----------------------------------
Release: 4.1.B2
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java b/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
index a23a281..210540f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
@@ -37,6 +37,7 @@ class PathComponentIterator implements Iterator<PathComponent<Attribute, Relatio
private final String path;
private final Map<String, String> aliasMap;
+ private EmbeddedAttribute embeddedAttribute;
private Entity currentEntity;
PathComponentIterator(Entity root, String path, Map<String, String> aliasMap) {
@@ -44,6 +45,7 @@ class PathComponentIterator implements Iterator<PathComponent<Attribute, Relatio
this.path = Objects.requireNonNull(path);
this.aliasMap = Objects.requireNonNull(aliasMap);
this.toks = new StringTokenizer(path, Entity.PATH_SEPARATOR);
+ this.embeddedAttribute = null;
}
public boolean hasNext() {
@@ -62,10 +64,19 @@ class PathComponentIterator implements Iterator<PathComponent<Attribute, Relatio
}
// see if this is an attribute
- Attribute attr = currentEntity.getAttribute(pathComp);
+ Attribute attr;
+ if(embeddedAttribute != null) {
+ attr = embeddedAttribute.getAttribute(pathComp);
+ embeddedAttribute = null;
+ } else {
+ attr = currentEntity.getAttribute(pathComp);
+ }
+
if (attr != null) {
// do a sanity check...
- if (toks.hasMoreTokens()) {
+ if(attr instanceof EmbeddedAttribute) {
+ embeddedAttribute = (EmbeddedAttribute)attr;
+ } else if (toks.hasMoreTokens()) {
throw new ExpressionException(
"Attribute must be the last component of the path: '" + pathComp + "'.", path, null);
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
index 9675a0c..0c38d9e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
@@ -24,9 +24,11 @@ import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.PersistenceState;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
import org.apache.cayenne.test.jdbc.DBHelper;
import org.apache.cayenne.test.jdbc.TableHelper;
import org.apache.cayenne.testdo.embeddable.EmbedEntity1;
+import org.apache.cayenne.testdo.embeddable.EmbedEntity2;
import org.apache.cayenne.testdo.embeddable.Embeddable1;
import org.apache.cayenne.unit.di.server.CayenneProjects;
import org.apache.cayenne.unit.di.server.ServerCase;
@@ -49,21 +51,29 @@ public class EmbeddingIT extends ServerCase {
protected DBHelper dbHelper;
protected TableHelper tEmbedEntity1;
+ protected TableHelper tEmbedEntity2;
@Before
public void setUp() throws Exception {
tEmbedEntity1 = new TableHelper(dbHelper, "EMBED_ENTITY1");
tEmbedEntity1.setColumns("ID", "NAME", "EMBEDDED10", "EMBEDDED20", "EMBEDDED30", "EMBEDDED40");
+
+ tEmbedEntity2 = new TableHelper(dbHelper, "EMBED_ENTITY2");
+ tEmbedEntity2.setColumns("ID", "NAME", "ENTITY1_ID", "EMBEDDED10", "EMBEDDED20");
}
protected void createSelectDataSet() throws Exception {
- tEmbedEntity1.delete().execute();
tEmbedEntity1.insert(1, "n1", "e1", "e2", "e3", "e4");
tEmbedEntity1.insert(2, "n2", "ex1", "ex2", "ex3", "ex4");
}
+
+ protected void createSelectDataSet2() throws Exception {
+ createSelectDataSet();
+ tEmbedEntity2.insert(1, "n2-1", 1, "e1", "e2");
+ tEmbedEntity2.insert(2, "n2-1", 2, "e1", "e2");
+ }
protected void createUpdateDataSet() throws Exception {
- tEmbedEntity1.delete().execute();
tEmbedEntity1.insert(1, "n1", "e1", "e2", "e3", "e4");
}
@@ -180,4 +190,53 @@ public class EmbeddingIT extends ServerCase {
assertNotNull(row);
assertEquals("x1", row.get("EMBEDDED10"));
}
+
+ @Test
+ public void testPropertyExpression() throws Exception {
+ createSelectDataSet();
+
+ List<EmbedEntity1> result = ObjectSelect.query(EmbedEntity1.class)
+ .where(EmbedEntity1.EMBEDDED1.dot(Embeddable1.EMBEDDED10).eq("e1"))
+ .orderBy(EmbedEntity1.EMBEDDED2.dot(Embeddable1.EMBEDDED20).desc())
+ .select(context);
+
+ assertEquals(1, result.size());
+ }
+
+ @Test
+ public void testRelatedEmbedded() throws Exception {
+ createSelectDataSet2();
+
+ List<EmbedEntity2> result = ObjectSelect.query(EmbedEntity2.class)
+ .where(EmbedEntity2.ENTITY1.dot(EmbedEntity1.EMBEDDED1).dot(Embeddable1.EMBEDDED10).eq("e1"))
+ .orderBy(EmbedEntity2.ENTITY1.dot(EmbedEntity1.EMBEDDED2).dot(Embeddable1.EMBEDDED20).desc())
+ .select(context);
+
+ assertEquals(1, result.size());
+ }
+
+ @Test
+ public void testPrefetchWithEmbedded() throws Exception {
+ createSelectDataSet2();
+
+ List<EmbedEntity2> result = ObjectSelect.query(EmbedEntity2.class)
+ .prefetch(EmbedEntity2.ENTITY1.joint())
+ .select(context);
+
+ assertEquals(2, result.size());
+ assertNotNull(result.get(0).getEntity1().getEmbedded1());
+ assertNotNull(result.get(1).getEntity1().getEmbedded1());
+ }
+
+ @Test
+ public void testInMemoryFilteringByEmbeddable() throws Exception {
+ createSelectDataSet();
+
+ List<EmbedEntity1> result = ObjectSelect.query(EmbedEntity1.class).select(context);
+ assertEquals(2, result.size());
+
+ List<EmbedEntity1> filtered = EmbedEntity1.EMBEDDED1.dot(Embeddable1.EMBEDDED10).eq("e1").filterObjects(result);
+ assertEquals(1, filtered.size());
+ assertEquals("n1", filtered.get(0).getName());
+ }
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedEntity2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedEntity2.java
new file mode 100644
index 0000000..128e79b
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedEntity2.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.embeddable;
+
+import org.apache.cayenne.testdo.embeddable.auto._EmbedEntity2;
+
+public class EmbedEntity2 extends _EmbedEntity2 {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
index 2634b64..d1e34d0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
@@ -3,9 +3,11 @@ package org.apache.cayenne.testdo.embeddable.auto;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.List;
import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.testdo.embeddable.EmbedEntity2;
import org.apache.cayenne.testdo.embeddable.Embeddable1;
/**
@@ -23,11 +25,13 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
public static final Property<Embeddable1> EMBEDDED1 = Property.create("embedded1", Embeddable1.class);
public static final Property<Embeddable1> EMBEDDED2 = Property.create("embedded2", Embeddable1.class);
public static final Property<String> NAME = Property.create("name", String.class);
+ public static final Property<List<EmbedEntity2>> EMBED_ENTITY2S = Property.create("embedEntity2s", List.class);
protected Embeddable1 embedded1;
protected Embeddable1 embedded2;
protected String name;
+ protected Object embedEntity2s;
public void setEmbedded1(Embeddable1 embedded1) {
beforePropertyWrite("embedded1", this.embedded1, embedded1);
@@ -59,6 +63,19 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
return this.name;
}
+ public void addToEmbedEntity2s(EmbedEntity2 obj) {
+ addToManyTarget("embedEntity2s", obj, true);
+ }
+
+ public void removeFromEmbedEntity2s(EmbedEntity2 obj) {
+ removeToManyTarget("embedEntity2s", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<EmbedEntity2> getEmbedEntity2s() {
+ return (List<EmbedEntity2>)readProperty("embedEntity2s");
+ }
+
@Override
public Object readPropertyDirectly(String propName) {
if(propName == null) {
@@ -72,6 +89,8 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
return this.embedded2;
case "name":
return this.name;
+ case "embedEntity2s":
+ return this.embedEntity2s;
default:
return super.readPropertyDirectly(propName);
}
@@ -93,6 +112,9 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
case "name":
this.name = (String)val;
break;
+ case "embedEntity2s":
+ this.embedEntity2s = val;
+ break;
default:
super.writePropertyDirectly(propName, val);
}
@@ -112,6 +134,7 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
out.writeObject(this.embedded1);
out.writeObject(this.embedded2);
out.writeObject(this.name);
+ out.writeObject(this.embedEntity2s);
}
@Override
@@ -120,6 +143,7 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
this.embedded1 = (Embeddable1)in.readObject();
this.embedded2 = (Embeddable1)in.readObject();
this.name = (String)in.readObject();
+ this.embedEntity2s = in.readObject();
}
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
similarity index 62%
copy from cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
copy to cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
index 2634b64..de53c02 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
@@ -6,57 +6,56 @@ import java.io.ObjectOutputStream;
import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.testdo.embeddable.EmbedEntity1;
import org.apache.cayenne.testdo.embeddable.Embeddable1;
/**
- * Class _EmbedEntity1 was generated by Cayenne.
+ * Class _EmbedEntity2 was generated by Cayenne.
* It is probably a good idea to avoid changing this class manually,
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _EmbedEntity1 extends BaseDataObject {
+public abstract class _EmbedEntity2 extends BaseDataObject {
private static final long serialVersionUID = 1L;
public static final String ID_PK_COLUMN = "ID";
- public static final Property<Embeddable1> EMBEDDED1 = Property.create("embedded1", Embeddable1.class);
- public static final Property<Embeddable1> EMBEDDED2 = Property.create("embedded2", Embeddable1.class);
public static final Property<String> NAME = Property.create("name", String.class);
+ public static final Property<Embeddable1> EMBEDDED = Property.create("embedded", Embeddable1.class);
+ public static final Property<EmbedEntity1> ENTITY1 = Property.create("entity1", EmbedEntity1.class);
- protected Embeddable1 embedded1;
- protected Embeddable1 embedded2;
protected String name;
+ protected Embeddable1 embedded;
+ protected Object entity1;
- public void setEmbedded1(Embeddable1 embedded1) {
- beforePropertyWrite("embedded1", this.embedded1, embedded1);
- this.embedded1 = embedded1;
+ public void setName(String name) {
+ beforePropertyWrite("name", this.name, name);
+ this.name = name;
}
- public Embeddable1 getEmbedded1() {
- beforePropertyRead("embedded1");
- return this.embedded1;
+ public String getName() {
+ beforePropertyRead("name");
+ return this.name;
}
- public void setEmbedded2(Embeddable1 embedded2) {
- beforePropertyWrite("embedded2", this.embedded2, embedded2);
- this.embedded2 = embedded2;
+ public void setEmbedded(Embeddable1 embedded) {
+ beforePropertyWrite("embedded", this.embedded, embedded);
+ this.embedded = embedded;
}
- public Embeddable1 getEmbedded2() {
- beforePropertyRead("embedded2");
- return this.embedded2;
+ public Embeddable1 getEmbedded() {
+ beforePropertyRead("embedded");
+ return this.embedded;
}
- public void setName(String name) {
- beforePropertyWrite("name", this.name, name);
- this.name = name;
+ public void setEntity1(EmbedEntity1 entity1) {
+ setToOneTarget("entity1", entity1, true);
}
- public String getName() {
- beforePropertyRead("name");
- return this.name;
+ public EmbedEntity1 getEntity1() {
+ return (EmbedEntity1)readProperty("entity1");
}
@Override
@@ -66,12 +65,12 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
}
switch(propName) {
- case "embedded1":
- return this.embedded1;
- case "embedded2":
- return this.embedded2;
case "name":
return this.name;
+ case "embedded":
+ return this.embedded;
+ case "entity1":
+ return this.entity1;
default:
return super.readPropertyDirectly(propName);
}
@@ -84,15 +83,15 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
}
switch (propName) {
- case "embedded1":
- this.embedded1 = (Embeddable1)val;
- break;
- case "embedded2":
- this.embedded2 = (Embeddable1)val;
- break;
case "name":
this.name = (String)val;
break;
+ case "embedded":
+ this.embedded = (Embeddable1)val;
+ break;
+ case "entity1":
+ this.entity1 = val;
+ break;
default:
super.writePropertyDirectly(propName, val);
}
@@ -109,17 +108,17 @@ public abstract class _EmbedEntity1 extends BaseDataObject {
@Override
protected void writeState(ObjectOutputStream out) throws IOException {
super.writeState(out);
- out.writeObject(this.embedded1);
- out.writeObject(this.embedded2);
out.writeObject(this.name);
+ out.writeObject(this.embedded);
+ out.writeObject(this.entity1);
}
@Override
protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
super.readState(in);
- this.embedded1 = (Embeddable1)in.readObject();
- this.embedded2 = (Embeddable1)in.readObject();
this.name = (String)in.readObject();
+ this.embedded = (Embeddable1)in.readObject();
+ this.entity1 = in.readObject();
}
}
diff --git a/cayenne-server/src/test/resources/cayenne-embeddable.xml b/cayenne-server/src/test/resources/cayenne-embeddable.xml
index aedacf3..eabee1b 100644
--- a/cayenne-server/src/test/resources/cayenne-embeddable.xml
+++ b/cayenne-server/src/test/resources/cayenne-embeddable.xml
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<domain xmlns="http://cayenne.apache.org/schema/10/domain"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain https://cayenne.apache.org/schema/10/domain.xsd"
project-version="10">
<map name="embeddable"/>
</domain>
diff --git a/cayenne-server/src/test/resources/embeddable.map.xml b/cayenne-server/src/test/resources/embeddable.map.xml
index 10c4db6..dbcae05 100644
--- a/cayenne-server/src/test/resources/embeddable.map.xml
+++ b/cayenne-server/src/test/resources/embeddable.map.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<data-map xmlns="http://cayenne.apache.org/schema/10/modelMap"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap http://cayenne.apache.org/schema/10/modelMap.xsd"
+ xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap https://cayenne.apache.org/schema/10/modelMap.xsd"
project-version="10">
<property name="defaultPackage" value="org.apache.cayenne.testdo.embeddable"/>
<embeddable className="org.apache.cayenne.testdo.embeddable.Embeddable1">
- <embeddable-attribute name="embedded10" type="java.lang.String" db-attribute-name="EMBEDDED10"/>
<embeddable-attribute name="embedded20" type="java.lang.String" db-attribute-name="EMBEDDED20"/>
+ <embeddable-attribute name="embedded10" type="java.lang.String" db-attribute-name="EMBEDDED10"/>
</embeddable>
<db-entity name="EMBED_ENTITY1">
<db-attribute name="EMBEDDED10" type="VARCHAR" length="100"/>
@@ -16,12 +16,31 @@
<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="NAME" type="VARCHAR" length="100"/>
</db-entity>
+ <db-entity name="EMBED_ENTITY2">
+ <db-attribute name="EMBEDDED10" type="VARCHAR" length="100"/>
+ <db-attribute name="EMBEDDED20" type="VARCHAR" length="100"/>
+ <db-attribute name="ENTITY1_ID" type="INTEGER"/>
+ <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+ <db-attribute name="NAME" type="VARCHAR" length="100"/>
+ </db-entity>
<obj-entity name="EmbedEntity1" className="org.apache.cayenne.testdo.embeddable.EmbedEntity1" dbEntityName="EMBED_ENTITY1">
<embedded-attribute name="embedded1" type="org.apache.cayenne.testdo.embeddable.Embeddable1"/>
<embedded-attribute name="embedded2" type="org.apache.cayenne.testdo.embeddable.Embeddable1">
- <embeddable-attribute-override name="embedded10" db-attribute-path="EMBEDDED30"/>
<embeddable-attribute-override name="embedded20" db-attribute-path="EMBEDDED40"/>
+ <embeddable-attribute-override name="embedded10" db-attribute-path="EMBEDDED30"/>
</embedded-attribute>
<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
</obj-entity>
+ <obj-entity name="EmbedEntity2" className="org.apache.cayenne.testdo.embeddable.EmbedEntity2" dbEntityName="EMBED_ENTITY2">
+ <embedded-attribute name="embedded" type="org.apache.cayenne.testdo.embeddable.Embeddable1"/>
+ <obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+ </obj-entity>
+ <db-relationship name="untitledRel" source="EMBED_ENTITY1" target="EMBED_ENTITY2" toMany="true">
+ <db-attribute-pair source="ID" target="ENTITY1_ID"/>
+ </db-relationship>
+ <db-relationship name="untitledRel" source="EMBED_ENTITY2" target="EMBED_ENTITY1">
+ <db-attribute-pair source="ENTITY1_ID" target="ID"/>
+ </db-relationship>
+ <obj-relationship name="embedEntity2s" source="EmbedEntity1" target="EmbedEntity2" deleteRule="Deny" db-relationship-path="untitledRel"/>
+ <obj-relationship name="entity1" source="EmbedEntity2" target="EmbedEntity1" deleteRule="Nullify" db-relationship-path="untitledRel"/>
</data-map>