This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push:
new bc19298 CAY-2728 Add ExtendedType to generate user-friendly
exceptions for internally used values
bc19298 is described below
commit bc1929807b5db5f08258344db182e897b1c3d5b4
Author: Nikita Timofeev <[email protected]>
AuthorDate: Tue Jan 11 17:58:56 2022 +0300
CAY-2728 Add ExtendedType to generate user-friendly exceptions for
internally used values
---
RELEASE-NOTES.txt | 2 +
.../cayenne/access/flush/IdGenerationMarker.java | 8 +-
.../access/flush/ObjectIdValueSupplier.java | 8 +-
.../types/InternalUnsupportedTypeFactory.java | 82 +++++++++++++
.../cayenne/configuration/server/ServerModule.java | 5 +-
.../org/apache/cayenne/CircularDependencyIT.java | 58 +++++++++
.../apache/cayenne/testdo/relationships/E1.java} | 34 +-----
.../apache/cayenne/testdo/relationships/E2.java} | 34 +-----
.../cayenne/testdo/relationships/auto/_E1.java | 130 +++++++++++++++++++++
.../cayenne/testdo/relationships/auto/_E2.java | 130 +++++++++++++++++++++
.../cayenne/unit/di/server/ServerCaseModule.java | 4 +-
.../src/test/resources/relationships.map.xml | 32 +++++
12 files changed, 464 insertions(+), 63 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index c63b79c..2591d7c 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -13,6 +13,8 @@ Date:
----------------------------------
Changes/New Features:
+CAY-2728 Add ExtendedType to generate user-friendly exceptions for internally
used values
+
Bug Fixes:
CAY-2697 Read-only cgen template creates mutator methods for to-many
relationships
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
index 1519556..2a10744 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
@@ -22,13 +22,14 @@ package org.apache.cayenne.access.flush;
import java.io.Serializable;
import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory;
/**
* Special value that denotes generated id attribute
*
* @since 4.2
*/
-class IdGenerationMarker implements Serializable {
+class IdGenerationMarker implements Serializable,
InternalUnsupportedTypeFactory.Marker {
private static final long serialVersionUID = -5339942931435878094L;
private final int id;
@@ -49,4 +50,9 @@ class IdGenerationMarker implements Serializable {
public int hashCode() {
return id;
}
+
+ @Override
+ public String errorMessage() {
+ return "PK is not generated. Check your PK generation strategy or
presence of the mutually dependent entities.";
+ }
}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java
index da27b99..eac62ef 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ObjectIdValueSupplier.java
@@ -23,13 +23,14 @@ import java.util.Objects;
import java.util.function.Supplier;
import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory;
/**
* Deferred value extracted from ObjectId
*
* @since 4.2
*/
-class ObjectIdValueSupplier implements Supplier<Object> {
+class ObjectIdValueSupplier implements Supplier<Object>,
InternalUnsupportedTypeFactory.Marker {
private final ObjectId id;
private final String attribute;
@@ -79,4 +80,9 @@ class ObjectIdValueSupplier implements Supplier<Object> {
public String toString() {
return "{id=" + id + ", attr=" + attribute + '}';
}
+
+ @Override
+ public String errorMessage() {
+ return "Value supplier is not resolved before usage.";
+ }
}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/types/InternalUnsupportedTypeFactory.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/types/InternalUnsupportedTypeFactory.java
new file mode 100644
index 0000000..461a98a
--- /dev/null
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/types/InternalUnsupportedTypeFactory.java
@@ -0,0 +1,82 @@
+/*****************************************************************
+ * 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.types;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+import org.apache.cayenne.CayenneRuntimeException;
+
+/**
+ * Extended type factory that produces types for Cayenne internal value types
that could potentially make it to the DB.
+ * ExtendedTypes that produced by this factory just trying to throw
user-friendly exception instead of unknown type one.
+ *
+ * @since 4.2
+ */
+public class InternalUnsupportedTypeFactory implements ExtendedTypeFactory {
+
+ @Override
+ public ExtendedType<?> getType(Class<?> objectClass) {
+ if(Marker.class.isAssignableFrom(objectClass)) {
+ return new ExtendedType<Marker>() {
+ @Override
+ public String getClassName() {
+ return objectClass.getName();
+ }
+
+ @Override
+ public void setJdbcObject(PreparedStatement statement, Marker
value, int pos, int type, int scale) {
+ throw new CayenneRuntimeException(value.errorMessage());
+ }
+
+ @Override
+ public Marker materializeObject(ResultSet rs, int index, int
type) {
+ // this normally shouldn't happen
+ throw new CayenneRuntimeException("Trying to materialize
internal Cayenne value. Check your mapping or report an issue.");
+ }
+
+ @Override
+ public Marker materializeObject(CallableStatement rs, int
index, int type) {
+ // this normally shouldn't happen
+ throw new CayenneRuntimeException("Trying to materialize
internal Cayenne value. Check your mapping or report an issue.");
+ }
+
+ @Override
+ public String toString(Marker value) {
+ return "Internal marker of type " +
objectClass.getSimpleName();
+ }
+ };
+ }
+ return null;
+ }
+
+ /**
+ * Marker interface, that should be used by any internal value types, that
could potentially get to the SQL
+ */
+ public interface Marker {
+ /**
+ * Error message in case this object made it to the DB
+ */
+ default String errorMessage() {
+ return "Trying to use internal type in the query.";
+ }
+ }
+}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
index 1d12d8f..edd6a15 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
@@ -61,7 +61,7 @@ import org.apache.cayenne.access.types.ExtendedTypeFactory;
import org.apache.cayenne.access.types.FloatType;
import org.apache.cayenne.access.types.GeoJsonType;
import org.apache.cayenne.access.types.IntegerType;
-import org.apache.cayenne.access.types.JsonType;
+import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory;
import org.apache.cayenne.access.types.LocalDateTimeValueType;
import org.apache.cayenne.access.types.LocalDateValueType;
import org.apache.cayenne.access.types.LocalTimeValueType;
@@ -434,7 +434,8 @@ public class ServerModule implements Module {
.add(GeoJsonType.class)
.add(WktType.class);
contributeUserTypes(binder);
- contributeTypeFactories(binder);
+ contributeTypeFactories(binder)
+ .add(new InternalUnsupportedTypeFactory());
// Custom ValueObjects types contribution
contributeValueObjectTypes(binder)
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/CircularDependencyIT.java
b/cayenne-server/src/test/java/org/apache/cayenne/CircularDependencyIT.java
new file mode 100644
index 0000000..6cfc68f
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CircularDependencyIT.java
@@ -0,0 +1,58 @@
+/*****************************************************************
+ * 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;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.testdo.relationships.E1;
+import org.apache.cayenne.testdo.relationships.E2;
+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.Test;
+
+import static org.junit.Assert.*;
+
+@UseServerRuntime(CayenneProjects.RELATIONSHIPS_PROJECT)
+public class CircularDependencyIT extends ServerCase {
+
+ @Inject
+ private ObjectContext context;
+
+ @Test()
+ public void testCycle() {
+ E1 e1 = context.newObject(E1.class);
+ E2 e2 = context.newObject(E2.class);
+
+ e1.setText("e1 #" + 1);
+ e2.setText("e2 #" + 2);
+
+ e1.setE2(e2);
+ e2.setE1(e1);
+
+ try {
+ context.commitChanges();
+ fail("Exception should be thrown here");
+ } catch (CayenneRuntimeException ex) {
+ assertTrue("Unexpected exception message: " + ex.getMessage(),
+ ex.getMessage().contains("PK is not generated"));
+ }
+
+ }
+}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E1.java
similarity index 53%
copy from
cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
copy to
cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E1.java
index 1519556..60069b0 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E1.java
@@ -7,7 +7,7 @@
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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
@@ -17,36 +17,12 @@
* under the License.
****************************************************************/
-package org.apache.cayenne.access.flush;
+package org.apache.cayenne.testdo.relationships;
-import java.io.Serializable;
+import org.apache.cayenne.testdo.relationships.auto._E1;
-import org.apache.cayenne.ObjectId;
+public class E1 extends _E1 {
-/**
- * Special value that denotes generated id attribute
- *
- * @since 4.2
- */
-class IdGenerationMarker implements Serializable {
- private static final long serialVersionUID = -5339942931435878094L;
-
- private final int id;
-
- IdGenerationMarker(ObjectId id) {
- this.id = id.hashCode();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- IdGenerationMarker that = (IdGenerationMarker) o;
- return id == that.id;
- }
+ private static final long serialVersionUID = 1L;
- @Override
- public int hashCode() {
- return id;
- }
}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E2.java
similarity index 53%
copy from
cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
copy to
cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E2.java
index 1519556..bf1065a 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/IdGenerationMarker.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/E2.java
@@ -7,7 +7,7 @@
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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
@@ -17,36 +17,12 @@
* under the License.
****************************************************************/
-package org.apache.cayenne.access.flush;
+package org.apache.cayenne.testdo.relationships;
-import java.io.Serializable;
+import org.apache.cayenne.testdo.relationships.auto._E2;
-import org.apache.cayenne.ObjectId;
+public class E2 extends _E2 {
-/**
- * Special value that denotes generated id attribute
- *
- * @since 4.2
- */
-class IdGenerationMarker implements Serializable {
- private static final long serialVersionUID = -5339942931435878094L;
-
- private final int id;
-
- IdGenerationMarker(ObjectId id) {
- this.id = id.hashCode();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- IdGenerationMarker that = (IdGenerationMarker) o;
- return id == that.id;
- }
+ private static final long serialVersionUID = 1L;
- @Override
- public int hashCode() {
- return id;
- }
}
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E1.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E1.java
new file mode 100644
index 0000000..26f81c1
--- /dev/null
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E1.java
@@ -0,0 +1,130 @@
+package org.apache.cayenne.testdo.relationships.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.EntityProperty;
+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.relationships.E2;
+
+/**
+ * Class _E1 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 _E1 extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "id";
+
+ public static final StringProperty<String> TEXT =
PropertyFactory.createString("text", String.class);
+ public static final EntityProperty<E2> E2 =
PropertyFactory.createEntity("e2", E2.class);
+ public static final ListProperty<E2> E2S =
PropertyFactory.createList("e2s", E2.class);
+
+ protected String text;
+
+ protected Object e2;
+ protected Object e2s;
+
+ public void setText(String text) {
+ beforePropertyWrite("text", this.text, text);
+ this.text = text;
+ }
+
+ public String getText() {
+ beforePropertyRead("text");
+ return this.text;
+ }
+
+ public void setE2(E2 e2) {
+ setToOneTarget("e2", e2, true);
+ }
+
+ public E2 getE2() {
+ return (E2)readProperty("e2");
+ }
+
+ public void addToE2s(E2 obj) {
+ addToManyTarget("e2s", obj, true);
+ }
+
+ public void removeFromE2s(E2 obj) {
+ removeToManyTarget("e2s", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<E2> getE2s() {
+ return (List<E2>)readProperty("e2s");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "text":
+ return this.text;
+ case "e2":
+ return this.e2;
+ case "e2s":
+ return this.e2s;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "text":
+ this.text = (String)val;
+ break;
+ case "e2":
+ this.e2 = val;
+ break;
+ case "e2s":
+ this.e2s = 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.text);
+ out.writeObject(this.e2);
+ out.writeObject(this.e2s);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException,
ClassNotFoundException {
+ super.readState(in);
+ this.text = (String)in.readObject();
+ this.e2 = in.readObject();
+ this.e2s = in.readObject();
+ }
+
+}
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E2.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E2.java
new file mode 100644
index 0000000..1a5e35d
--- /dev/null
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_E2.java
@@ -0,0 +1,130 @@
+package org.apache.cayenne.testdo.relationships.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.EntityProperty;
+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.relationships.E1;
+
+/**
+ * Class _E2 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 _E2 extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String ID_PK_COLUMN = "id";
+
+ public static final StringProperty<String> TEXT =
PropertyFactory.createString("text", String.class);
+ public static final EntityProperty<E1> E1 =
PropertyFactory.createEntity("e1", E1.class);
+ public static final ListProperty<E1> E1S =
PropertyFactory.createList("e1s", E1.class);
+
+ protected String text;
+
+ protected Object e1;
+ protected Object e1s;
+
+ public void setText(String text) {
+ beforePropertyWrite("text", this.text, text);
+ this.text = text;
+ }
+
+ public String getText() {
+ beforePropertyRead("text");
+ return this.text;
+ }
+
+ public void setE1(E1 e1) {
+ setToOneTarget("e1", e1, true);
+ }
+
+ public E1 getE1() {
+ return (E1)readProperty("e1");
+ }
+
+ public void addToE1s(E1 obj) {
+ addToManyTarget("e1s", obj, true);
+ }
+
+ public void removeFromE1s(E1 obj) {
+ removeToManyTarget("e1s", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<E1> getE1s() {
+ return (List<E1>)readProperty("e1s");
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "text":
+ return this.text;
+ case "e1":
+ return this.e1;
+ case "e1s":
+ return this.e1s;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "text":
+ this.text = (String)val;
+ break;
+ case "e1":
+ this.e1 = val;
+ break;
+ case "e1s":
+ this.e1s = 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.text);
+ out.writeObject(this.e1);
+ out.writeObject(this.e1s);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException,
ClassNotFoundException {
+ super.readState(in);
+ this.text = (String)in.readObject();
+ this.e1 = in.readObject();
+ this.e1s = in.readObject();
+ }
+
+}
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
index 27a8e5a..08e3801 100644
---
a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
@@ -42,6 +42,7 @@ import org.apache.cayenne.access.types.DoubleType;
import org.apache.cayenne.access.types.DurationType;
import org.apache.cayenne.access.types.FloatType;
import org.apache.cayenne.access.types.IntegerType;
+import org.apache.cayenne.access.types.InternalUnsupportedTypeFactory;
import org.apache.cayenne.access.types.LocalDateTimeValueType;
import org.apache.cayenne.access.types.LocalDateValueType;
import org.apache.cayenne.access.types.LocalTimeValueType;
@@ -223,7 +224,8 @@ public class ServerCaseModule implements Module {
.add(new CalendarType<>(Calendar.class))
.add(new DurationType());
ServerModule.contributeUserTypes(binder);
- ServerModule.contributeTypeFactories(binder);
+ ServerModule.contributeTypeFactories(binder)
+ .add(new InternalUnsupportedTypeFactory());
ServerModule.contributeValueObjectTypes(binder)
.add(BigIntegerValueType.class)
.add(BigDecimalValueType.class)
diff --git a/cayenne-server/src/test/resources/relationships.map.xml
b/cayenne-server/src/test/resources/relationships.map.xml
index b487db9..7f4b4f5 100644
--- a/cayenne-server/src/test/resources/relationships.map.xml
+++ b/cayenne-server/src/test/resources/relationships.map.xml
@@ -22,6 +22,22 @@
<db-attribute name="NAME" type="VARCHAR" length="100"/>
<db-attribute name="RELATIONSHIP_HELPER_ID" type="INTEGER"
isPrimaryKey="true" isMandatory="true"/>
</db-entity>
+ <db-entity name="CYCLE_E1">
+ <db-attribute name="e2_id" type="INTEGER"/>
+ <db-attribute name="id" type="INTEGER" isPrimaryKey="true"
isGenerated="true" isMandatory="true"/>
+ <db-attribute name="text" type="VARCHAR" length="128"/>
+ </db-entity>
+ <db-entity name="CYCLE_E2">
+ <db-attribute name="e1_id" type="INTEGER"/>
+ <db-attribute name="id" type="INTEGER" isPrimaryKey="true"
isGenerated="true" isMandatory="true"/>
+ <db-attribute name="text" type="VARCHAR" length="128"/>
+ </db-entity>
+ <obj-entity name="CYCLE_E1"
className="org.apache.cayenne.testdo.relationships.E1" dbEntityName="CYCLE_E1">
+ <obj-attribute name="text" type="java.lang.String"
db-attribute-path="text"/>
+ </obj-entity>
+ <obj-entity name="CYCLE_E2"
className="org.apache.cayenne.testdo.relationships.E2" dbEntityName="CYCLE_E2">
+ <obj-attribute name="text" type="java.lang.String"
db-attribute-path="text"/>
+ </obj-entity>
<obj-entity name="FkOfDifferentType"
className="org.apache.cayenne.testdo.relationships.FkOfDifferentType"
dbEntityName="FK_OF_DIFFERENT_TYPE"/>
<obj-entity name="MeaningfulFK"
className="org.apache.cayenne.testdo.relationships.MeaningfulFK"
dbEntityName="MEANINGFUL_FK">
<obj-attribute name="relationshipHelperID" type="int"
db-attribute-path="RELATIONSHIP_HELPER_ID"/>
@@ -56,6 +72,22 @@
<db-relationship name="reflexiveAndToOneArray"
source="RELATIONSHIP_HELPER" target="REFLEXIVE_AND_TO_ONE" toMany="true">
<db-attribute-pair source="RELATIONSHIP_HELPER_ID"
target="RELATIONSHIP_HELPER_ID"/>
</db-relationship>
+ <db-relationship name="e2" source="CYCLE_E1" target="CYCLE_E2">
+ <db-attribute-pair source="e2_id" target="id"/>
+ </db-relationship>
+ <db-relationship name="e2s" source="CYCLE_E1" target="CYCLE_E2"
toMany="true">
+ <db-attribute-pair source="id" target="e1_id"/>
+ </db-relationship>
+ <db-relationship name="e1" source="CYCLE_E2" target="CYCLE_E1">
+ <db-attribute-pair source="e1_id" target="id"/>
+ </db-relationship>
+ <db-relationship name="e1s" source="CYCLE_E2" target="CYCLE_E1"
toMany="true">
+ <db-attribute-pair source="id" target="e2_id"/>
+ </db-relationship>
+ <obj-relationship name="e2" source="CYCLE_E1" target="CYCLE_E2"
deleteRule="Nullify" db-relationship-path="e2"/>
+ <obj-relationship name="e2s" source="CYCLE_E1" target="CYCLE_E2"
deleteRule="Deny" db-relationship-path="e2s"/>
+ <obj-relationship name="e1" source="CYCLE_E2" target="CYCLE_E1"
deleteRule="Nullify" db-relationship-path="e1"/>
+ <obj-relationship name="e1s" source="CYCLE_E2" target="CYCLE_E1"
deleteRule="Deny" db-relationship-path="e1s"/>
<obj-relationship name="relationshipHelper" source="FkOfDifferentType"
target="RelationshipHelper" db-relationship-path="relationshipHelper"/>
<obj-relationship name="toRelationshipHelper" source="MeaningfulFK"
target="RelationshipHelper" db-relationship-path="toRelationshipHelper"/>
<obj-relationship name="children" source="ReflexiveAndToOne"
target="ReflexiveAndToOne" db-relationship-path="children"/>