added tests for lazy attributes
diff --git a/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm b/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
index 74c1729..14a4e1e 100644
--- a/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
+++ b/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
@@ -78,8 +78,12 @@
## Create ivars
#foreach( $attr in ${object.DeclaredAttributes} )
+#if ($attr.Lazy)
+ protected Object ${attr.Name};
+#else
protected $importUtils.formatJavaType(${attr.Type}) ${attr.Name};
#end
+#end
#foreach( $rel in ${object.DeclaredRelationships} )
#if( $rel.ToMany )
#if ( ${rel.CollectionType} == "java.util.Map")
@@ -110,7 +114,17 @@
objectContext.prepareForAccess(this, "${attr.Name}", false);
}
+#if ($attr.Lazy)
+ if(this.$attrName instanceof Fault) {
+ this.$attrName = ((Fault) this.$attrName).resolveFault(this, "$attr.Name");
+ }
+#end
+
+#if ($attr.Lazy)
+ return ($importUtils.formatJavaType(${attr.Type})) $attrName;
+#else
return $attrName;
+#end
}
#end
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/cay_2641/Cay2641IT.java b/cayenne-client/src/test/java/org/apache/cayenne/cay_2641/Cay2641IT.java
new file mode 100644
index 0000000..3b2d148
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/cay_2641/Cay2641IT.java
@@ -0,0 +1,97 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.cay_2641;
+
+import org.apache.cayenne.CayenneContext;
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.testdo.cay_2641.client.ArtistLazy;
+import org.apache.cayenne.testdo.cay_2641.client.PaintingLazy;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * @since 4.2
+ */
+@UseServerRuntime(CayenneProjects.CAY_2641)
+public class Cay2641IT extends ClientCase {
+
+ @Inject
+ private CayenneContext context;
+
+ @Before
+ public void setup() {
+ ArtistLazy artistLazy = context.newObject(ArtistLazy.class);
+ artistLazy.setName("Test");
+ artistLazy.setSurname("Test1");
+
+ PaintingLazy paintingLazy = context.newObject(PaintingLazy.class);
+ paintingLazy.setName("Test");
+ paintingLazy.setArtist(artistLazy);
+
+ context.commitChanges();
+ }
+
+ @Test
+ public void testSampleSelect() {
+ List<ArtistLazy> artists = ObjectSelect.query(ArtistLazy.class).select(context);
+
+ assertEquals(artists.size(), 1);
+ assertEquals(artists.get(0).getSurname(), "Test1");
+
+ assertTrue(artists.get(0).readPropertyDirectly("name") instanceof Fault);
+
+ assertEquals(artists.get(0).getName(), "Test");
+ }
+
+ @Test
+ public void testColumnSelect() {
+ List<String> strings = ObjectSelect.columnQuery(ArtistLazy.class, ArtistLazy.NAME).select(context);
+
+ assertEquals(strings.size(), 1);
+ assertEquals(strings.get(0), "Test");
+ }
+
+ @Test
+ public void testPrefetchSelect() {
+ List<PaintingLazy> paintingLazyList1 = ObjectSelect.query(PaintingLazy.class).prefetch(PaintingLazy.ARTIST.joint()).select(context);
+
+ assertEquals(paintingLazyList1.size(), 1);
+ assertTrue(paintingLazyList1.get(0).getArtist().readPropertyDirectly("name") instanceof Fault);
+
+ List<PaintingLazy> paintingLazyList2 = ObjectSelect.query(PaintingLazy.class).prefetch(PaintingLazy.ARTIST.disjoint()).select(context);
+
+ assertEquals(paintingLazyList2.size(), 1);
+ assertTrue(paintingLazyList1.get(0).getArtist().readPropertyDirectly("name") instanceof Fault);
+
+ List<PaintingLazy> paintingLazyList3 = ObjectSelect.query(PaintingLazy.class).prefetch(PaintingLazy.ARTIST.disjointById()).select(context);
+
+ assertEquals(paintingLazyList3.size(), 1);
+ assertTrue(paintingLazyList1.get(0).getArtist().readPropertyDirectly("name") instanceof Fault);
+ }
+
+}
diff --git a/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java b/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java
index 615474d..39e502e 100644
--- a/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java
+++ b/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java
@@ -82,7 +82,7 @@
Collection<String> additionalWhitelist) {
SerializerFactory factory = new CayenneSerializerFactory();
-
+ factory.setAllowNonSerializable(true);
List<String> whitelist = new ArrayList<>(additionalWhitelist);
if(resolver != null) {
whitelist.add("org.apache.cayenne.*");
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowUtils.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowUtils.java
index ce65013..768ed80 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowUtils.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataRowUtils.java
@@ -89,19 +89,18 @@
ObjAttribute attr = property.getAttribute();
String dbAttrPath = attr.getDbAttributePath();
- Object value = snapshot.get(dbAttrPath);
- property.writePropertyDirectly(object, null, value);
-
// note that a check "snaphsot.get(..) == null" would be incorrect in this
// case, as NULL value is entirely valid; still save a map lookup by
// checking for the null value first
- if (value == null && !snapshot.containsKey(dbAttrPath)) {
- if(attr.isLazy()) {
- property.writePropertyDirectly(object, null, new AttributeFault(property));
- } else {
- isPartialSnapshot[0] = true;
- }
+ if (snapshot.containsKey(dbAttrPath) && !attr.isLazy()) {
+ Object value = snapshot.get(dbAttrPath);
+ property.writePropertyDirectly(object, null, value);
+ } else if (attr.isLazy()) {
+ property.writePropertyDirectly(object, null, new AttributeFault(property));
+ } else {
+ isPartialSnapshot[0] = true;
}
+
return true;
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java b/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
index f5a7064..8884e04 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/ObjectDetachOperation.java
@@ -22,16 +22,10 @@
import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
+import org.apache.cayenne.access.AttributeFault;
import org.apache.cayenne.map.EntityResolver;
import org.apache.cayenne.query.PrefetchTreeNode;
-import org.apache.cayenne.reflect.ArcProperty;
-import org.apache.cayenne.reflect.AttributeProperty;
-import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.reflect.PropertyDescriptor;
-import org.apache.cayenne.reflect.PropertyVisitor;
-import org.apache.cayenne.reflect.ToManyMapProperty;
-import org.apache.cayenne.reflect.ToManyProperty;
-import org.apache.cayenne.reflect.ToOneProperty;
+import org.apache.cayenne.reflect.*;
import java.util.ArrayList;
import java.util.Collection;
@@ -197,7 +191,11 @@
public boolean visitAttribute(AttributeProperty property) {
PropertyDescriptor targetProperty = targetDescriptor
.getProperty(property.getName());
- targetProperty.writeProperty(target, null, property.readProperty(source));
+ if (!property.getAttribute().isLazy()) {
+ targetProperty.writeProperty(target, null, property.readProperty(source));
+ } else {
+ targetProperty.writeProperty(target, null, new AttributeFault(property));
+ }
return true;
}
});
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/Cay2641.java b/cayenne-server/src/test/java/org/apache/cayenne/access/Cay2641.java
new file mode 100644
index 0000000..e10be4b
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/Cay2641.java
@@ -0,0 +1,174 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.access;
+
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.access.translator.select.DefaultSelectTranslator;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ColumnSelect;
+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.cay_2641.ArtistLazy;
+import org.apache.cayenne.testdo.cay_2641.DatamapLazy;
+import org.apache.cayenne.testdo.cay_2641.PaintingLazy;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Types;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @since 4.2
+ */
+@UseServerRuntime(CayenneProjects.CAY_2641)
+public class Cay2641 extends ServerCase {
+
+ @Inject
+ private ObjectContext context;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Inject
+ private DbAdapter adapter;
+
+ @Before
+ public void setup() throws Exception {
+ TableHelper th = new TableHelper(dbHelper, "ArtistLazy")
+ .setColumns("ID", "NAME", "SURNAME")
+ .setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.VARCHAR);
+ th.insert(1, "artist1", "artist2");
+
+ th = new TableHelper(dbHelper, "PaintingLazy")
+ .setColumns("ID", "NAME", "ARTIST_ID")
+ .setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.INTEGER);
+ th.insert(1, "painting1", 1);
+ }
+
+ @Test
+ public void testTranslatorSql() {
+ ObjectSelect<ArtistLazy> artists = ObjectSelect.query(ArtistLazy.class);
+
+ DefaultSelectTranslator translator = new DefaultSelectTranslator(artists, adapter, context.getEntityResolver());
+
+ String sql = translator.getSql();
+ assertFalse(sql.contains("t0.NAME"));
+
+ String string = "SELECT t0.SURNAME, t0.ID FROM ArtistLazy t0";
+ assertTrue(sql.equals(string));
+
+ ColumnSelect<String> select = ObjectSelect.columnQuery(ArtistLazy.class, ArtistLazy.NAME);
+ translator = new DefaultSelectTranslator(select, adapter, context.getEntityResolver());
+ sql = translator.getSql();
+
+ assertTrue(sql.contains("t0.NAME"));
+ }
+
+ @Test
+ public void testTypeAttributes() {
+ List<ArtistLazy> artists = ObjectSelect.query(ArtistLazy.class).select(context);
+
+ Object object = artists.get(0).readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+
+ object = artists.get(0).readPropertyDirectly("surname");
+ assertTrue(object.equals("artist2"));
+ }
+
+ @Test
+ public void testTypeLazyAttribute() {
+ ArtistLazy artist = ObjectSelect.query(ArtistLazy.class).selectFirst(context);
+
+ Object object = artist.readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+
+ artist.getName();
+ object = artist.readPropertyDirectly("name");
+ assertTrue(object.equals("artist1"));
+ }
+
+ @Test
+ public void testPrefetchLazyTranslatorSql() {
+ ObjectSelect<PaintingLazy> paintingLazyObjectSelect = ObjectSelect.query(PaintingLazy.class).prefetch(PaintingLazy.ARTIST.joint());
+ DefaultSelectTranslator translator = new DefaultSelectTranslator(paintingLazyObjectSelect, adapter, context.getEntityResolver());
+ String sql = translator.getSql();
+ assertFalse(sql.contains("t0.NAME"));
+
+ String string = "SELECT DISTINCT t0.ARTIST_ID, t0.ID, t1.ID, t1.SURNAME FROM PaintingLazy t0 LEFT JOIN ArtistLazy t1 ON t0.ARTIST_ID = t1.ID";
+ assertTrue(sql.equals(string));
+ }
+
+ @Test
+ public void testPrefetchLazyTypeAttributes() {
+ List<PaintingLazy> paintingLazyList = ObjectSelect.query(PaintingLazy.class).prefetch(PaintingLazy.ARTIST.joint()).select(context);
+
+ Object object = paintingLazyList.get(0).readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+
+ object = paintingLazyList.get(0).getName();
+ assertTrue(object instanceof String);
+ assertTrue(object.equals("painting1"));
+
+ ArtistLazy artist = (ArtistLazy) paintingLazyList.get(0).readPropertyDirectly("artist");
+ object = artist.readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+
+ object = artist.readPropertyDirectly("surname");
+ assertTrue(object.equals("artist2"));
+
+ object = artist.getName();
+ assertTrue(object instanceof String);
+ assertTrue(object.equals("artist1"));
+ }
+
+ @Test
+ public void testsSimpleSelectCustomer() {
+ DatamapLazy optimistic = DatamapLazy.getInstance();
+ List<ArtistLazy> artistLazies = optimistic.performSimpleSelect(context);
+
+ Object object = artistLazies.get(0).readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+
+ object = artistLazies.get(0).readPropertyDirectly("surname");
+ assertTrue(object instanceof String);
+ assertTrue(object.equals("artist2"));
+ }
+
+ @Test
+ public void testsPrefetchSelectCustomer() {
+ DatamapLazy optimistic = DatamapLazy.getInstance();
+ List<PaintingLazy> paintingLazies = optimistic.performPrefetchSelect(context);
+
+ Object object = paintingLazies.get(0).readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+
+ ArtistLazy artist = (ArtistLazy) paintingLazies.get(0).readPropertyDirectly("artist");
+ object = artist.readPropertyDirectly("name");
+ assertTrue(object instanceof Fault);
+ }
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/ArtistLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/ArtistLazy.java
new file mode 100644
index 0000000..dcd9224
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/ArtistLazy.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.cay_2641;
+
+import org.apache.cayenne.testdo.cay_2641.auto._ArtistLazy;
+
+public class ArtistLazy extends _ArtistLazy {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/DatamapLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/DatamapLazy.java
new file mode 100644
index 0000000..f026e12
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/DatamapLazy.java
@@ -0,0 +1,18 @@
+package org.apache.cayenne.testdo.cay_2641;
+
+import org.apache.cayenne.testdo.cay_2641.auto._DatamapLazy;
+
+public class DatamapLazy extends _DatamapLazy {
+
+ private static DatamapLazy instance;
+
+ private DatamapLazy() {}
+
+ public static DatamapLazy getInstance() {
+ if(instance == null) {
+ instance = new DatamapLazy();
+ }
+
+ return instance;
+ }
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/PaintingLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/PaintingLazy.java
new file mode 100644
index 0000000..dd6f77a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/PaintingLazy.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.cay_2641;
+
+import org.apache.cayenne.testdo.cay_2641.auto._PaintingLazy;
+
+public class PaintingLazy extends _PaintingLazy {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_ArtistLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_ArtistLazy.java
new file mode 100644
index 0000000..aedc3e9
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_ArtistLazy.java
@@ -0,0 +1,135 @@
+package org.apache.cayenne.testdo.cay_2641.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.Fault;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.cay_2641.PaintingLazy;
+
+/**
+ * Class _ArtistLazy 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 _ArtistLazy extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "ID";
+
+ public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+ public static final StringProperty<String> SURNAME = PropertyFactory.createString("surname", String.class);
+ public static final ListProperty<PaintingLazy> PAINTINGS = PropertyFactory.createList("paintings", PaintingLazy.class);
+
+ protected Object name;
+ protected String surname;
+
+ protected Object paintings;
+
+ public void setName(String name) {
+ beforePropertyWrite("name", this.name, name);
+ this.name = name;
+ }
+
+ public String getName() {
+ beforePropertyRead("name");
+ if(this.name instanceof Fault) {
+ this.name = ((Fault) this.name).resolveFault(this, "name");
+ }
+ return (String)this.name;
+ }
+
+ public void setSurname(String surname) {
+ beforePropertyWrite("surname", this.surname, surname);
+ this.surname = surname;
+ }
+
+ public String getSurname() {
+ beforePropertyRead("surname");
+ return this.surname;
+ }
+
+ public void addToPaintings(PaintingLazy obj) {
+ addToManyTarget("paintings", obj, true);
+ }
+
+ public void removeFromPaintings(PaintingLazy obj) {
+ removeToManyTarget("paintings", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<PaintingLazy> getPaintings() {
+ return (List<PaintingLazy>)readProperty("paintings");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "name":
+ return this.name;
+ case "surname":
+ return this.surname;
+ case "paintings":
+ return this.paintings;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "name":
+ this.name = val;
+ break;
+ case "surname":
+ this.surname = (String)val;
+ break;
+ case "paintings":
+ this.paintings = val;
+ break;
+ default:
+ super.writePropertyDirectly(propName, val);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ writeSerialized(out);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ readSerialized(in);
+ }
+
+ @Override
+ protected void writeState(ObjectOutputStream out) throws IOException {
+ super.writeState(out);
+ out.writeObject(this.name);
+ out.writeObject(this.surname);
+ out.writeObject(this.paintings);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ this.name = in.readObject();
+ this.surname = (String)in.readObject();
+ this.paintings = in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_DatamapLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_DatamapLazy.java
new file mode 100644
index 0000000..756360a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_DatamapLazy.java
@@ -0,0 +1,33 @@
+package org.apache.cayenne.testdo.cay_2641.auto;
+
+import java.util.List;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.query.MappedSelect;
+import org.apache.cayenne.testdo.cay_2641.ArtistLazy;
+import org.apache.cayenne.testdo.cay_2641.PaintingLazy;
+
+/**
+ * This class 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 class _DatamapLazy {
+
+ public static final String PREFETCH_SELECT_QUERYNAME = "prefetchSelect";
+
+ public static final String SIMPLE_SELECT_QUERYNAME = "simpleSelect";
+
+ public List<PaintingLazy> performPrefetchSelect(ObjectContext context) {
+ MappedSelect<PaintingLazy> query = MappedSelect.query(PREFETCH_SELECT_QUERYNAME, PaintingLazy.class);
+ return query.select(context);
+ }
+
+
+ public List<ArtistLazy> performSimpleSelect(ObjectContext context) {
+ MappedSelect<ArtistLazy> query = MappedSelect.query(SIMPLE_SELECT_QUERYNAME, ArtistLazy.class);
+ return query.select(context);
+ }
+
+}
\ No newline at end of file
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_PaintingLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_PaintingLazy.java
new file mode 100644
index 0000000..5386919
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/auto/_PaintingLazy.java
@@ -0,0 +1,110 @@
+package org.apache.cayenne.testdo.cay_2641.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.cay_2641.ArtistLazy;
+
+/**
+ * Class _PaintingLazy 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 _PaintingLazy extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "ID";
+
+ public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+ public static final EntityProperty<ArtistLazy> ARTIST = PropertyFactory.createEntity("artist", ArtistLazy.class);
+
+ protected Object name;
+
+ protected Object artist;
+
+ public void setName(String name) {
+ beforePropertyWrite("name", this.name, name);
+ this.name = name;
+ }
+
+ public String getName() {
+ beforePropertyRead("name");
+ if(this.name instanceof Fault) {
+ this.name = ((Fault) this.name).resolveFault(this, "name");
+ }
+ return (String)this.name;
+ }
+
+ public void setArtist(ArtistLazy artist) {
+ setToOneTarget("artist", artist, true);
+ }
+
+ public ArtistLazy getArtist() {
+ return (ArtistLazy)readProperty("artist");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "name":
+ return this.name;
+ case "artist":
+ return this.artist;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "name":
+ this.name = val;
+ break;
+ case "artist":
+ this.artist = val;
+ break;
+ default:
+ super.writePropertyDirectly(propName, val);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ writeSerialized(out);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ readSerialized(in);
+ }
+
+ @Override
+ protected void writeState(ObjectOutputStream out) throws IOException {
+ super.writeState(out);
+ out.writeObject(this.name);
+ out.writeObject(this.artist);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ this.name = in.readObject();
+ this.artist = in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/ArtistLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/ArtistLazy.java
new file mode 100644
index 0000000..593a6aa
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/ArtistLazy.java
@@ -0,0 +1,12 @@
+package org.apache.cayenne.testdo.cay_2641.client;
+
+import org.apache.cayenne.testdo.cay_2641.client.auto._ArtistLazy;
+
+/**
+ * A persistent class mapped as "ArtistLazy" Cayenne entity.
+ */
+public class ArtistLazy extends _ArtistLazy {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/PaintingLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/PaintingLazy.java
new file mode 100644
index 0000000..a290ca4
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/PaintingLazy.java
@@ -0,0 +1,12 @@
+package org.apache.cayenne.testdo.cay_2641.client;
+
+import org.apache.cayenne.testdo.cay_2641.client.auto._PaintingLazy;
+
+/**
+ * A persistent class mapped as "PaintingLazy" Cayenne entity.
+ */
+public class PaintingLazy extends _PaintingLazy {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/auto/_ArtistLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/auto/_ArtistLazy.java
new file mode 100644
index 0000000..ec1111d
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/auto/_ArtistLazy.java
@@ -0,0 +1,113 @@
+package org.apache.cayenne.testdo.cay_2641.client.auto;
+
+import java.util.List;
+
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.cay_2641.client.PaintingLazy;
+import org.apache.cayenne.util.PersistentObjectList;
+
+/**
+ * A generated persistent class mapped as "ArtistLazy" Cayenne entity. It is a good idea to
+ * avoid changing this class manually, since it will be overwritten next time code is
+ * regenerated. If you need to make any customizations, put them in a subclass.
+ */
+public abstract class _ArtistLazy extends PersistentObject {
+
+ public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+ public static final StringProperty<String> SURNAME = PropertyFactory.createString("surname", String.class);
+ public static final ListProperty<PaintingLazy> PAINTINGS = PropertyFactory.createList("paintings", PaintingLazy.class);
+
+ protected Object name;
+ protected String surname;
+ protected List<PaintingLazy> paintings;
+
+ public String getName() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "name", false);
+ }
+
+ if(this.name instanceof Fault) {
+ this.name = ((Fault) this.name).resolveFault(this, "name");
+ }
+
+ return (String) name;
+ }
+
+ public void setName(String name) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "name", false);
+ objectContext.propertyChanged(this, "name", this.name, name);
+ }
+
+ this.name = name;
+ }
+
+ public String getSurname() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "surname", false);
+ }
+
+
+ return surname;
+ }
+
+ public void setSurname(String surname) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "surname", false);
+ objectContext.propertyChanged(this, "surname", this.surname, surname);
+ }
+
+ this.surname = surname;
+ }
+
+ public List<PaintingLazy> getPaintings() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "paintings", true);
+ } else if (this.paintings == null) {
+ this.paintings = new PersistentObjectList<>(this, "paintings");
+ }
+
+ return paintings;
+ }
+
+ public void addToPaintings(PaintingLazy object) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "paintings", true);
+ } else if (this.paintings == null) {
+ this.paintings = new PersistentObjectList<>(this, "paintings");
+ }
+
+ this.paintings.add(object);
+ }
+
+ public void removeFromPaintings(PaintingLazy object) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "paintings", true);
+ } else if (this.paintings == null) {
+ this.paintings = new PersistentObjectList<>(this, "paintings");
+ }
+
+ this.paintings.remove(object);
+ }
+
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "name":
+ return this.name;
+ case "surname":
+ return this.surname;
+ case "paintings":
+ return this.paintings;
+ default:
+ return null;
+ }
+ }
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/auto/_PaintingLazy.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/auto/_PaintingLazy.java
new file mode 100644
index 0000000..29e52dc
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/cay_2641/client/auto/_PaintingLazy.java
@@ -0,0 +1,66 @@
+package org.apache.cayenne.testdo.cay_2641.client.auto;
+
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.cay_2641.client.ArtistLazy;
+import org.apache.cayenne.util.PersistentObjectHolder;
+
+/**
+ * A generated persistent class mapped as "PaintingLazy" Cayenne entity. It is a good idea to
+ * avoid changing this class manually, since it will be overwritten next time code is
+ * regenerated. If you need to make any customizations, put them in a subclass.
+ */
+public abstract class _PaintingLazy extends PersistentObject {
+
+ public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+ public static final EntityProperty<ArtistLazy> ARTIST = PropertyFactory.createEntity("artist", ArtistLazy.class);
+
+ protected Object name;
+ protected ValueHolder<ArtistLazy> artist;
+
+ public String getName() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "name", false);
+ }
+
+ if(this.name instanceof Fault) {
+ this.name = ((Fault) this.name).resolveFault(this, "name");
+ }
+
+ return (String) name;
+ }
+
+ public void setName(String name) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "name", false);
+ objectContext.propertyChanged(this, "name", this.name, name);
+ }
+
+ this.name = name;
+ }
+
+ public ArtistLazy getArtist() {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "artist", true);
+ } else if (this.artist == null) {
+ this.artist = new PersistentObjectHolder<>(this, "artist");
+ }
+
+ return artist.getValue();
+ }
+
+ public void setArtist(ArtistLazy artist) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, "artist", true);
+ } else if (this.artist == null) {
+ this.artist = new PersistentObjectHolder<>(this, "artist");
+ }
+
+ this.artist.setValue(artist);
+ }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
index bd971d8..3d7d1e5 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/CayenneProjects.java
@@ -86,4 +86,5 @@
public static final String INHERITANCE_WITH_ENUM_PROJECT = "cayenne-inheritance-with-enum.xml";
public static final String LAZY_ATTRIBUTES_PROJECT = "cayenne-lazy-attributes.xml";
public static final String CAY_2666 = "cay2666/cayenne-cay-2666.xml";
+ public static final String CAY_2641 = "cay2641/cayenne-cay-2641.xml";
}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
index 2b8aed1..8067005 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/SchemaBuilder.java
@@ -82,7 +82,7 @@
"qualified.map.xml", "quoted-identifiers.map.xml", "inheritance-single-table1.map.xml",
"inheritance-vertical.map.xml", "oneway-rels.map.xml", "unsupported-distinct-types.map.xml",
"array-type.map.xml", "cay-2032.map.xml", "weighted-sort.map.xml", "hybrid-data-object.map.xml",
- "java8.map.xml", "inheritance-with-enum.map.xml", "lazy-attributes.map.xml", "cay2666/datamap.map.xml" };
+ "java8.map.xml", "inheritance-with-enum.map.xml", "lazy-attributes.map.xml", "cay2666/datamap.map.xml", "cay2641/datamapLazy.map.xml" };
// hardcoded dependent entities that should be excluded
// if LOBs are not supported
diff --git a/cayenne-server/src/test/resources/cay2641/cayenne-cay-2641.xml b/cayenne-server/src/test/resources/cay2641/cayenne-cay-2641.xml
new file mode 100644
index 0000000..3990e67
--- /dev/null
+++ b/cayenne-server/src/test/resources/cay2641/cayenne-cay-2641.xml
@@ -0,0 +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="datamapLazy"/>
+</domain>
diff --git a/cayenne-server/src/test/resources/cay2641/datamapLazy.map.xml b/cayenne-server/src/test/resources/cay2641/datamapLazy.map.xml
new file mode 100644
index 0000000..884f8c2
--- /dev/null
+++ b/cayenne-server/src/test/resources/cay2641/datamapLazy.map.xml
@@ -0,0 +1,52 @@
+<?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 https://cayenne.apache.org/schema/10/modelMap.xsd"
+ project-version="10">
+ <property name="defaultPackage" value="org.apache.cayenne.testdo.cay_2641"/>
+ <property name="clientSupported" value="true"/>
+ <property name="defaultClientPackage" value="org.apache.cayenne.testdo.cay_2641.client"/>
+ <db-entity name="ArtistLazy">
+ <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="5"/>
+ <db-attribute name="NAME" type="VARCHAR" length="10"/>
+ <db-attribute name="SURNAME" type="VARCHAR" length="10"/>
+ </db-entity>
+ <db-entity name="PaintingLazy">
+ <db-attribute name="ARTIST_ID" type="INTEGER" length="10"/>
+ <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="10"/>
+ <db-attribute name="NAME" type="VARCHAR" length="10"/>
+ </db-entity>
+ <obj-entity name="ArtistLazy" className="org.apache.cayenne.testdo.cay_2641.ArtistLazy" clientClassName="org.apache.cayenne.testdo.cay_2641.client.ArtistLazy" dbEntityName="ArtistLazy">
+ <obj-attribute name="name" type="java.lang.String" lazy="true" db-attribute-path="NAME"/>
+ <obj-attribute name="surname" type="java.lang.String" db-attribute-path="SURNAME"/>
+ </obj-entity>
+ <obj-entity name="PaintingLazy" className="org.apache.cayenne.testdo.cay_2641.PaintingLazy" clientClassName="org.apache.cayenne.testdo.cay_2641.client.PaintingLazy" lock-type="optimistic" dbEntityName="PaintingLazy">
+ <obj-attribute name="name" type="java.lang.String" lazy="true" db-attribute-path="NAME"/>
+ </obj-entity>
+ <db-relationship name="paintings" source="ArtistLazy" target="PaintingLazy" toMany="true">
+ <db-attribute-pair source="ID" target="ARTIST_ID"/>
+ </db-relationship>
+ <db-relationship name="artist" source="PaintingLazy" target="ArtistLazy">
+ <db-attribute-pair source="ARTIST_ID" target="ID"/>
+ </db-relationship>
+ <obj-relationship name="paintings" source="ArtistLazy" target="PaintingLazy" deleteRule="Deny" db-relationship-path="paintings"/>
+ <obj-relationship name="artist" source="PaintingLazy" target="ArtistLazy" deleteRule="Nullify" db-relationship-path="artist"/>
+ <query name="prefetchSelect" type="SelectQuery" root="obj-entity" root-name="PaintingLazy">
+ <prefetch type="disjoint"><![CDATA[artist]]></prefetch>
+ </query>
+ <query name="simpleSelect" type="SelectQuery" root="obj-entity" root-name="ArtistLazy"/>
+ <cgen xmlns="http://cayenne.apache.org/schema/10/cgen">
+ <excludeEntities>ArtistLazy,PaintingLazy</excludeEntities>
+ <destDir>../../java</destDir>
+ <mode>all</mode>
+ <template>templates/v4_1/subclass.vm</template>
+ <superTemplate>templates/v4_1/superclass.vm</superTemplate>
+ <outputPattern>*.java</outputPattern>
+ <makePairs>true</makePairs>
+ <usePkgPath>true</usePkgPath>
+ <overwrite>false</overwrite>
+ <createPropertyNames>false</createPropertyNames>
+ <createPKProperties>false</createPKProperties>
+ <client>false</client>
+ </cgen>
+</data-map>