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 2017/08/11 07:54:47 UTC
[10/18] cayenne git commit: CAY-2330 Field based data objects
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-cgen/src/main/resources/templates/v4_1/superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v4_1/superclass.vm b/cayenne-cgen/src/main/resources/templates/v4_1/superclass.vm
new file mode 100644
index 0000000..860e4af
--- /dev/null
+++ b/cayenne-cgen/src/main/resources/templates/v4_1/superclass.vm
@@ -0,0 +1,292 @@
+## 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
+##
+## http://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.
+##
+##Terminology:
+## Base class - super superclass of entity, ie, org.apache.cayenne.CayenneDataObject or MyBaseClass
+## Super class - superclass of entity, ie, org.apache.cayenne.art.auto._Artist
+## Sub class - class of entity, ie, org.apache.cayenne.art.Artist
+##
+## Classes available in template
+## object (duplicated as 'objEntity') - the ObjEntity class: See org.apache.cayenne.map.ObjectEntity
+## stringUtils - class for string "helper" functions: See org.apache.cayenne.gen.StringUtils
+## entityUtils - class for entity "helper" functions: See org.apache.cayenne.gen.EntityUtils
+## importUtils - class for import statement management: See org.apache.cayenne.gen.ImportUtils
+## superClassName
+## superPackageName
+## subClassName
+## subPackageName
+## baseClassName
+## basePackageName
+##
+###################
+## Create import ##
+###################
+${importUtils.setPackage($superPackageName)}##
+${importUtils.addReservedType("${superPackageName}.${superClassName}")}##
+${importUtils.addType("${basePackageName}.${baseClassName}")}##
+${importUtils.addType("java.io.IOException")}##
+${importUtils.addType("java.io.ObjectInputStream")}##
+${importUtils.addType("java.io.ObjectOutputStream")}##
+#if((${object.DeclaredAttributes} && !${object.DeclaredAttributes.isEmpty()}) || (${object.DeclaredRelationships} && !${object.DeclaredRelationships.isEmpty()}))
+${importUtils.addType('org.apache.cayenne.exp.Property')}##
+#end
+#foreach( $attr in ${object.DeclaredAttributes} )
+$importUtils.addType(${attr.Type})##
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+$importUtils.addType(${rel.TargetEntity.ClassName})##
+#if(${rel.CollectionType})
+$importUtils.addType(${rel.CollectionType})##
+#end
+#end
+${importUtils.generate()}
+
+/**
+ * Class ${superClassName} 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 ${superClassName} extends ${baseClassName} {
+
+ private static final long serialVersionUID = 1L;
+
+###########################
+## Create property names ##
+###########################
+#if( $createPropertyNames )
+#foreach( $attr in ${object.DeclaredAttributes} )
+ public static final String ${stringUtils.capitalizedAsConstant($attr.Name)}_PROPERTY = "${attr.Name}";
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+ public static final String ${stringUtils.capitalizedAsConstant($rel.Name)}_PROPERTY = "${rel.Name}";
+#end
+
+#end
+#if( $object.DbEntity )
+#foreach( $idAttr in ${object.DbEntity.PrimaryKeys} )
+ public static final String ${stringUtils.capitalizedAsConstant($idAttr.Name)}_PK_COLUMN = "${idAttr.Name}";
+#end
+#end
+
+#######################
+## Create Properties ##
+#######################
+#foreach( $attr in ${object.DeclaredAttributes} )
+ #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)")
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ${rel.CollectionType} == "java.util.Map")
+ #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)>" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#else
+ #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)>" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#else
+ #set( $type = "$importUtils.formatJavaType(${rel.TargetEntity.ClassName})" )
+ public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
+#end
+#end
+
+###################
+## Create Fields ##
+###################
+#foreach( $attr in ${object.DeclaredAttributes} )
+#set ( $type = "$importUtils.formatJavaType(${attr.Type})")
+ protected $type ${attr.Name};
+#end
+
+#foreach( $rel in ${object.DeclaredRelationships} )
+ protected Object ${rel.Name};
+#end
+
+#########################################################
+## Create attributes and relationships set/get methods ##
+#########################################################
+#foreach( $attr in ${object.DeclaredAttributes} )
+#set ( $name = "$stringUtils.formatVariableName(${attr.Name})")
+##
+## setter
+#if ("true" != "${object.isReadOnly()}")
+ public void set${stringUtils.capitalized($attr.Name)}($importUtils.formatJavaType(${attr.Type}) $name) {
+ beforePropertyWrite("${attr.Name}", this.$name, $name);
+ this.$name = $name;
+ }
+
+#end
+##
+## getter
+#if ( $importUtils.isBoolean(${attr.Type}) )
+ public boolean is${stringUtils.capitalized($attr.Name)}() {
+#else
+ public $importUtils.formatJavaType(${attr.Type}) get${stringUtils.capitalized($attr.Name)}() {
+#end
+ beforePropertyRead("${attr.Name}");
+ return $stringUtils.formatVariableName(${attr.Name});
+ }
+
+#end
+##
+## Create list add/remove/get methods
+#foreach( $rel in ${object.DeclaredRelationships} )
+#if( $rel.ToMany )
+#if ( ! $rel.ReadOnly )
+ public void addTo${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
+ addToManyTarget("${rel.Name}", obj, true);
+ }
+
+ public void removeFrom${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
+ removeToManyTarget("${rel.Name}", obj, true);
+ }
+
+#end
+ @SuppressWarnings("unchecked")
+#if ( ${rel.CollectionType} == "java.util.Map")
+ public $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)> get${stringUtils.capitalized($rel.Name)}() {
+ return ($importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClassName)>)readProperty("${rel.Name}");
+ }
+#else
+ public $importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)> get${stringUtils.capitalized($rel.Name)}() {
+ return ($importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClassName)>)readProperty("${rel.Name}");
+ }
+#end
+
+#else
+#if ( !${object.isReadOnly()} && !$rel.ReadOnly )
+ public void set${stringUtils.capitalized($rel.Name)}($importUtils.formatJavaType(${rel.TargetEntity.ClassName}) $stringUtils.formatVariableName(${rel.name})) {
+ setToOneTarget("${rel.Name}", $stringUtils.formatVariableName(${rel.name}), true);
+ }
+
+#end
+ public $importUtils.formatJavaType(${rel.TargetEntity.ClassName}) get${stringUtils.capitalized($rel.Name)}() {
+ return ($importUtils.formatJavaType(${rel.TargetEntity.ClassName}))readProperty("${rel.Name}");
+ }
+
+#end
+#end
+#############################
+## Create callback methods ##
+#############################
+#foreach($cbname in ${entityUtils.callbackNames})
+protected abstract void ${cbname}();
+
+#end
+###########################################################
+## Create writePropertyDirect/readPropertyDirect methods ##
+###########################################################
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+#foreach( $attr in ${object.DeclaredAttributes} )
+#set ( $name = "$stringUtils.formatVariableName(${attr.Name})")
+ case "${attr.Name}":
+ return this.${name};
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+ case "${rel.Name}":
+ return this.$stringUtils.formatVariableName(${rel.name});
+#end
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+#foreach( $attr in ${object.DeclaredAttributes} )
+#set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)")
+#set ( $realType = "$importUtils.formatJavaType(${attr.Type})")
+#set ( $name = "$stringUtils.formatVariableName(${attr.Name})")
+ case "${attr.Name}":
+#if ( $importUtils.isBoolean($realType) )
+ this.${name} = val == null ? false : ($type)val;
+#elseif ($importUtils.isPrimitive($realType))
+ this.${name} = val == null ? 0 : ($type)val;
+#else
+ this.${name} = ($type)val;
+#end
+ break;
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+ case "${rel.Name}":
+ this.$stringUtils.formatVariableName(${rel.name}) = val;
+ break;
+#end
+ default:
+ super.writePropertyDirectly(propName, val);
+ }
+ }
+
+##################################
+## Create serialization support ##
+##################################
+ 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);
+#foreach( $attr in ${object.DeclaredAttributes} )
+#set ( $name = "$stringUtils.formatVariableName(${attr.Name})")
+#set ( $type = "$importUtils.formatJavaType(${attr.Type})")
+#if($importUtils.isPrimitive($type))
+ out.write${stringUtils.capitalized($type)}($name);
+#else
+ out.writeObject(${name});
+#end
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+ out.writeObject(${stringUtils.formatVariableName($rel.Name)});
+#end
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+#foreach( $attr in ${object.DeclaredAttributes} )
+#set ( $name = "$stringUtils.formatVariableName(${attr.Name})")
+#set ( $type = "$importUtils.formatJavaType(${attr.Type})")
+#if($importUtils.isPrimitive($type))
+ $name = in.read${stringUtils.capitalized($type)}();
+#else
+ $name = ($type)in.readObject();
+#end
+#end
+#foreach( $rel in ${object.DeclaredRelationships} )
+#set ( $name = "${stringUtils.formatVariableName($rel.Name)}")
+ $name = in.readObject();
+#end
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
index c6e1885..2eaffa6 100644
--- a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
@@ -46,7 +46,7 @@ public class ClassGenerationActionTest {
@Before
public void setUp() throws Exception {
- this.writers = new ArrayList<StringWriter>(3);
+ this.writers = new ArrayList<>(3);
this.action = new ClassGenerationAction() {
@Override
@@ -79,7 +79,7 @@ public class ClassGenerationActionTest {
String superclass = generated.get(0);
assertTrue(superclass, superclass.contains("package org.example.auto;"));
- assertTrue(superclass, superclass.contains("import org.apache.cayenne.CayenneDataObject;"));
+ assertTrue(superclass, superclass.contains("import org.apache.cayenne.BaseDataObject;"));
String subclass = generated.get(1);
assertTrue(subclass, subclass.contains("package org.example;"));
@@ -147,18 +147,16 @@ public class ClassGenerationActionTest {
String superclass = generated.get(0);
assertTrue(superclass, superclass.contains("public void setID(int ID)"));
- assertTrue(superclass, superclass.contains("writeProperty(\"ID\", ID);"));
+ assertTrue(superclass, superclass.contains("this.ID = ID;"));
assertTrue(superclass, superclass.contains("public int getID()"));
- assertTrue(superclass, superclass.contains("Object value = readProperty(\"ID\");"));
- assertTrue(superclass, superclass.contains("return (value != null) ? (Integer) value : 0;"));
+ assertTrue(superclass, superclass.contains("return this.ID;"));
assertTrue(superclass, superclass.contains("public void setName(char name)"));
- assertTrue(superclass, superclass.contains("writeProperty(\"name\", name);"));
+ assertTrue(superclass, superclass.contains("this.name = name;"));
assertTrue(superclass, superclass.contains("public char getName()"));
- assertTrue(superclass, superclass.contains("Object value = readProperty(\"name\");"));
- assertTrue(superclass, superclass.contains("return (value != null) ? (Character) value : 0;"));
+ assertTrue(superclass, superclass.contains("return this.name;"));
}
@@ -247,7 +245,7 @@ public class ClassGenerationActionTest {
action.execute(artifact);
- List<String> strings = new ArrayList<String>(writers.size());
+ List<String> strings = new ArrayList<>(writers.size());
for (StringWriter writer : writers) {
strings.add(writer.toString());
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPrimitiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPrimitiveIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPrimitiveIT.java
index acc7c69..e57ab05 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPrimitiveIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPrimitiveIT.java
@@ -19,6 +19,7 @@
package org.apache.cayenne;
import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.query.SortOrder;
import org.apache.cayenne.test.jdbc.DBHelper;
@@ -104,4 +105,32 @@ public class CayenneContextPrimitiveIT extends ClientCase {
assertFalse(tTablePrimitives.getBoolean("BOOLEAN_COLUMN"));
assertEquals(8, tTablePrimitives.getInt("INT_COLUMN"));
}
+
+ @Test
+ public void testCommitEmptyChangesPrimitives() throws Exception {
+
+ ClientTablePrimitives object = context.newObject(ClientTablePrimitives.class);
+
+ context.commitChanges();
+
+ assertFalse(tTablePrimitives.getBoolean("BOOLEAN_COLUMN"));
+ assertEquals(0, tTablePrimitives.getInt("INT_COLUMN"));
+
+ object.setBooleanColumn(true);
+ object.setIntColumn(8);
+ context.commitChanges();
+
+ assertTrue(tTablePrimitives.getBoolean("BOOLEAN_COLUMN"));
+ assertEquals(8, tTablePrimitives.getInt("INT_COLUMN"));
+ }
+
+ @Test
+ public void testSelectEmptyPrimitives() throws Exception {
+ tTablePrimitives.insert(1, accessStackAdapter.supportsBoolean() ? true : 1, null);
+
+ ClientTablePrimitives object = ObjectSelect.query(ClientTablePrimitives.class).selectFirst(context);
+
+ assertTrue(object.isBooleanColumn());
+ assertEquals(0, object.getIntColumn());
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
index ca49870..3c773f5 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table1.java
@@ -1,6 +1,10 @@
package org.apache.cayenne.crypto.db.auto;
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -9,7 +13,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _Table1 extends CayenneDataObject {
+public abstract class _Table1 extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -20,34 +24,120 @@ public abstract class _Table1 extends CayenneDataObject {
public static final Property<Integer> PLAIN_INT = Property.create("plainInt", Integer.class);
public static final Property<String> PLAIN_STRING = Property.create("plainString", String.class);
+ protected int cryptoInt;
+ protected String cryptoString;
+ protected int plainInt;
+ protected String plainString;
+
+
public void setCryptoInt(int cryptoInt) {
- writeProperty("cryptoInt", cryptoInt);
+ beforePropertyWrite("cryptoInt", this.cryptoInt, cryptoInt);
+ this.cryptoInt = cryptoInt;
}
+
public int getCryptoInt() {
- Object value = readProperty("cryptoInt");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("cryptoInt");
+ return cryptoInt;
}
public void setCryptoString(String cryptoString) {
- writeProperty("cryptoString", cryptoString);
+ beforePropertyWrite("cryptoString", this.cryptoString, cryptoString);
+ this.cryptoString = cryptoString;
}
+
public String getCryptoString() {
- return (String)readProperty("cryptoString");
+ beforePropertyRead("cryptoString");
+ return cryptoString;
}
public void setPlainInt(int plainInt) {
- writeProperty("plainInt", plainInt);
+ beforePropertyWrite("plainInt", this.plainInt, plainInt);
+ this.plainInt = plainInt;
}
+
public int getPlainInt() {
- Object value = readProperty("plainInt");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("plainInt");
+ return plainInt;
}
public void setPlainString(String plainString) {
- writeProperty("plainString", plainString);
+ beforePropertyWrite("plainString", this.plainString, plainString);
+ this.plainString = plainString;
}
+
public String getPlainString() {
- return (String)readProperty("plainString");
+ beforePropertyRead("plainString");
+ return plainString;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "cryptoInt":
+ return this.cryptoInt;
+ case "cryptoString":
+ return this.cryptoString;
+ case "plainInt":
+ return this.plainInt;
+ case "plainString":
+ return this.plainString;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "cryptoInt":
+ this.cryptoInt = val == null ? 0 : (Integer)val;
+ break;
+ case "cryptoString":
+ this.cryptoString = (String)val;
+ break;
+ case "plainInt":
+ this.plainInt = val == null ? 0 : (Integer)val;
+ break;
+ case "plainString":
+ this.plainString = (String)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.writeInt(cryptoInt);
+ out.writeObject(cryptoString);
+ out.writeInt(plainInt);
+ out.writeObject(plainString);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ cryptoInt = in.readInt();
+ cryptoString = (String)in.readObject();
+ plainInt = in.readInt();
+ plainString = (String)in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table2.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table2.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table2.java
index 3c65795..c10987e 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table2.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table2.java
@@ -1,6 +1,10 @@
package org.apache.cayenne.crypto.db.auto;
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -9,7 +13,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _Table2 extends CayenneDataObject {
+public abstract class _Table2 extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -18,18 +22,84 @@ public abstract class _Table2 extends CayenneDataObject {
public static final Property<byte[]> CRYPTO_BYTES = Property.create("cryptoBytes", byte[].class);
public static final Property<byte[]> PLAIN_BYTES = Property.create("plainBytes", byte[].class);
+ protected byte[] cryptoBytes;
+ protected byte[] plainBytes;
+
+
public void setCryptoBytes(byte[] cryptoBytes) {
- writeProperty("cryptoBytes", cryptoBytes);
+ beforePropertyWrite("cryptoBytes", this.cryptoBytes, cryptoBytes);
+ this.cryptoBytes = cryptoBytes;
}
+
public byte[] getCryptoBytes() {
- return (byte[])readProperty("cryptoBytes");
+ beforePropertyRead("cryptoBytes");
+ return cryptoBytes;
}
public void setPlainBytes(byte[] plainBytes) {
- writeProperty("plainBytes", plainBytes);
+ beforePropertyWrite("plainBytes", this.plainBytes, plainBytes);
+ this.plainBytes = plainBytes;
}
+
public byte[] getPlainBytes() {
- return (byte[])readProperty("plainBytes");
+ beforePropertyRead("plainBytes");
+ return plainBytes;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "cryptoBytes":
+ return this.cryptoBytes;
+ case "plainBytes":
+ return this.plainBytes;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "cryptoBytes":
+ this.cryptoBytes = (byte[])val;
+ break;
+ case "plainBytes":
+ this.plainBytes = (byte[])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(cryptoBytes);
+ out.writeObject(plainBytes);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ cryptoBytes = (byte[])in.readObject();
+ plainBytes = (byte[])in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table3.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table3.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table3.java
index 917197c..9e0d027 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table3.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table3.java
@@ -1,6 +1,10 @@
package org.apache.cayenne.crypto.db.auto;
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -9,7 +13,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _Table3 extends CayenneDataObject {
+public abstract class _Table3 extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -17,11 +21,66 @@ public abstract class _Table3 extends CayenneDataObject {
public static final Property<String> CRYPTO_STRING = Property.create("cryptoString", String.class);
+ protected String cryptoString;
+
+
public void setCryptoString(String cryptoString) {
- writeProperty("cryptoString", cryptoString);
+ beforePropertyWrite("cryptoString", this.cryptoString, cryptoString);
+ this.cryptoString = cryptoString;
}
+
public String getCryptoString() {
- return (String)readProperty("cryptoString");
+ beforePropertyRead("cryptoString");
+ return cryptoString;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "cryptoString":
+ return this.cryptoString;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "cryptoString":
+ this.cryptoString = (String)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(cryptoString);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ cryptoString = (String)in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
index ae30286..5563c63 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table4.java
@@ -1,6 +1,10 @@
package org.apache.cayenne.crypto.db.auto;
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -9,7 +13,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _Table4 extends CayenneDataObject {
+public abstract class _Table4 extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -18,19 +22,84 @@ public abstract class _Table4 extends CayenneDataObject {
public static final Property<Integer> PLAIN_INT = Property.create("plainInt", Integer.class);
public static final Property<String> PLAIN_STRING = Property.create("plainString", String.class);
+ protected int plainInt;
+ protected String plainString;
+
+
public void setPlainInt(int plainInt) {
- writeProperty("plainInt", plainInt);
+ beforePropertyWrite("plainInt", this.plainInt, plainInt);
+ this.plainInt = plainInt;
}
+
public int getPlainInt() {
- Object value = readProperty("plainInt");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("plainInt");
+ return plainInt;
}
public void setPlainString(String plainString) {
- writeProperty("plainString", plainString);
+ beforePropertyWrite("plainString", this.plainString, plainString);
+ this.plainString = plainString;
}
+
public String getPlainString() {
- return (String)readProperty("plainString");
+ beforePropertyRead("plainString");
+ return plainString;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "plainInt":
+ return this.plainInt;
+ case "plainString":
+ return this.plainString;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "plainInt":
+ this.plainInt = val == null ? 0 : (Integer)val;
+ break;
+ case "plainString":
+ this.plainString = (String)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.writeInt(plainInt);
+ out.writeObject(plainString);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ plainInt = in.readInt();
+ plainString = (String)in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table5.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table5.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table5.java
index 3f4127f..44aa168 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table5.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table5.java
@@ -1,6 +1,10 @@
package org.apache.cayenne.crypto.db.auto;
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -9,7 +13,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _Table5 extends CayenneDataObject {
+public abstract class _Table5 extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -19,28 +23,102 @@ public abstract class _Table5 extends CayenneDataObject {
public static final Property<Integer> CRYPTO_INT3 = Property.create("cryptoInt3", Integer.class);
public static final Property<Integer> CRYPTO_INT4 = Property.create("cryptoInt4", Integer.class);
+ protected int cryptoInt1;
+ protected int cryptoInt3;
+ protected int cryptoInt4;
+
+
public void setCryptoInt1(int cryptoInt1) {
- writeProperty("cryptoInt1", cryptoInt1);
+ beforePropertyWrite("cryptoInt1", this.cryptoInt1, cryptoInt1);
+ this.cryptoInt1 = cryptoInt1;
}
+
public int getCryptoInt1() {
- Object value = readProperty("cryptoInt1");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("cryptoInt1");
+ return cryptoInt1;
}
public void setCryptoInt3(int cryptoInt3) {
- writeProperty("cryptoInt3", cryptoInt3);
+ beforePropertyWrite("cryptoInt3", this.cryptoInt3, cryptoInt3);
+ this.cryptoInt3 = cryptoInt3;
}
+
public int getCryptoInt3() {
- Object value = readProperty("cryptoInt3");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("cryptoInt3");
+ return cryptoInt3;
}
public void setCryptoInt4(int cryptoInt4) {
- writeProperty("cryptoInt4", cryptoInt4);
+ beforePropertyWrite("cryptoInt4", this.cryptoInt4, cryptoInt4);
+ this.cryptoInt4 = cryptoInt4;
}
+
public int getCryptoInt4() {
- Object value = readProperty("cryptoInt4");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("cryptoInt4");
+ return cryptoInt4;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "cryptoInt1":
+ return this.cryptoInt1;
+ case "cryptoInt3":
+ return this.cryptoInt3;
+ case "cryptoInt4":
+ return this.cryptoInt4;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "cryptoInt1":
+ this.cryptoInt1 = val == null ? 0 : (Integer)val;
+ break;
+ case "cryptoInt3":
+ this.cryptoInt3 = val == null ? 0 : (Integer)val;
+ break;
+ case "cryptoInt4":
+ this.cryptoInt4 = val == null ? 0 : (Integer)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.writeInt(cryptoInt1);
+ out.writeInt(cryptoInt3);
+ out.writeInt(cryptoInt4);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ cryptoInt1 = in.readInt();
+ cryptoInt3 = in.readInt();
+ cryptoInt4 = in.readInt();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table6.java
----------------------------------------------------------------------
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table6.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table6.java
index cd5df66..61db882 100644
--- a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table6.java
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/db/auto/_Table6.java
@@ -1,6 +1,10 @@
package org.apache.cayenne.crypto.db.auto;
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -9,7 +13,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _Table6 extends CayenneDataObject {
+public abstract class _Table6 extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -18,20 +22,84 @@ public abstract class _Table6 extends CayenneDataObject {
public static final Property<Long> CRYPTO_INT1 = Property.create("cryptoInt1", Long.class);
public static final Property<Integer> CRYPTO_INT4 = Property.create("cryptoInt4", Integer.class);
+ protected long cryptoInt1;
+ protected int cryptoInt4;
+
+
public void setCryptoInt1(long cryptoInt1) {
- writeProperty("cryptoInt1", cryptoInt1);
+ beforePropertyWrite("cryptoInt1", this.cryptoInt1, cryptoInt1);
+ this.cryptoInt1 = cryptoInt1;
}
+
public long getCryptoInt1() {
- Object value = readProperty("cryptoInt1");
- return (value != null) ? (Long) value : 0;
+ beforePropertyRead("cryptoInt1");
+ return cryptoInt1;
}
public void setCryptoInt4(int cryptoInt4) {
- writeProperty("cryptoInt4", cryptoInt4);
+ beforePropertyWrite("cryptoInt4", this.cryptoInt4, cryptoInt4);
+ this.cryptoInt4 = cryptoInt4;
}
+
public int getCryptoInt4() {
- Object value = readProperty("cryptoInt4");
- return (value != null) ? (Integer) value : 0;
+ beforePropertyRead("cryptoInt4");
+ return cryptoInt4;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "cryptoInt1":
+ return this.cryptoInt1;
+ case "cryptoInt4":
+ return this.cryptoInt4;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "cryptoInt1":
+ this.cryptoInt1 = val == null ? 0 : (Long)val;
+ break;
+ case "cryptoInt4":
+ this.cryptoInt4 = val == null ? 0 : (Integer)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.writeLong(cryptoInt1);
+ out.writeInt(cryptoInt4);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ cryptoInt1 = in.readLong();
+ cryptoInt4 = in.readInt();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTestEntity.java b/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTestEntity.java
index d5db3b9..8b41f9c 100644
--- a/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTestEntity.java
+++ b/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTestEntity.java
@@ -1,8 +1,11 @@
package org.apache.cayenne.java8.db.auto;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.time.LocalDate;
-import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -11,7 +14,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _LocalDateTestEntity extends CayenneDataObject {
+public abstract class _LocalDateTestEntity extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -19,11 +22,66 @@ public abstract class _LocalDateTestEntity extends CayenneDataObject {
public static final Property<LocalDate> DATE = Property.create("date", LocalDate.class);
+ protected LocalDate date;
+
+
public void setDate(LocalDate date) {
- writeProperty("date", date);
+ beforePropertyWrite("date", this.date, date);
+ this.date = date;
}
+
public LocalDate getDate() {
- return (LocalDate)readProperty("date");
+ beforePropertyRead("date");
+ return date;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "date":
+ return this.date;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "date":
+ this.date = (LocalDate)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(date);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ date = (LocalDate)in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTimeTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTimeTestEntity.java b/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTimeTestEntity.java
index 59623a0..b630aad 100644
--- a/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTimeTestEntity.java
+++ b/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalDateTimeTestEntity.java
@@ -1,8 +1,11 @@
package org.apache.cayenne.java8.db.auto;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.time.LocalDateTime;
-import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -11,7 +14,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _LocalDateTimeTestEntity extends CayenneDataObject {
+public abstract class _LocalDateTimeTestEntity extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -19,11 +22,66 @@ public abstract class _LocalDateTimeTestEntity extends CayenneDataObject {
public static final Property<LocalDateTime> TIMESTAMP = Property.create("timestamp", LocalDateTime.class);
+ protected LocalDateTime timestamp;
+
+
public void setTimestamp(LocalDateTime timestamp) {
- writeProperty("timestamp", timestamp);
+ beforePropertyWrite("timestamp", this.timestamp, timestamp);
+ this.timestamp = timestamp;
}
+
public LocalDateTime getTimestamp() {
- return (LocalDateTime)readProperty("timestamp");
+ beforePropertyRead("timestamp");
+ return timestamp;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "timestamp":
+ return this.timestamp;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "timestamp":
+ this.timestamp = (LocalDateTime)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(timestamp);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ timestamp = (LocalDateTime)in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalTimeTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalTimeTestEntity.java b/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalTimeTestEntity.java
index 3b2ea88..f1496d3 100644
--- a/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalTimeTestEntity.java
+++ b/cayenne-java8/src/test/java/org/apache/cayenne/java8/db/auto/_LocalTimeTestEntity.java
@@ -1,8 +1,11 @@
package org.apache.cayenne.java8.db.auto;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.time.LocalTime;
-import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.Property;
/**
@@ -11,7 +14,7 @@ import org.apache.cayenne.exp.Property;
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
-public abstract class _LocalTimeTestEntity extends CayenneDataObject {
+public abstract class _LocalTimeTestEntity extends BaseDataObject {
private static final long serialVersionUID = 1L;
@@ -19,11 +22,66 @@ public abstract class _LocalTimeTestEntity extends CayenneDataObject {
public static final Property<LocalTime> TIME = Property.create("time", LocalTime.class);
+ protected LocalTime time;
+
+
public void setTime(LocalTime time) {
- writeProperty("time", time);
+ beforePropertyWrite("time", this.time, time);
+ this.time = time;
}
+
public LocalTime getTime() {
- return (LocalTime)readProperty("time");
+ beforePropertyRead("time");
+ return time;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "time":
+ return this.time;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "time":
+ this.time = (LocalTime)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(time);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readState(in);
+ time = (LocalTime)in.readObject();
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/544aae08/cayenne-server/src/main/java/org/apache/cayenne/BaseDataObject.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/BaseDataObject.java b/cayenne-server/src/main/java/org/apache/cayenne/BaseDataObject.java
new file mode 100644
index 0000000..17447c7
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/BaseDataObject.java
@@ -0,0 +1,722 @@
+/*****************************************************************
+ * 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
+ *
+ * http://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 java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbJoin;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.EmbeddedAttribute;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.reflect.PropertyUtils;
+import org.apache.cayenne.validation.BeanValidationFailure;
+import org.apache.cayenne.validation.ValidationFailure;
+import org.apache.cayenne.validation.ValidationResult;
+
+/**
+ * Base implementation of DataObject,
+ * have no assumption about how data is actually stored.
+ *
+ * Two variants are currently supported:
+ * - field based storage, e.g. each entity class will directly define fields to store data
+ * - Map based storage, e.g. values will be stored in general Map (see {@link CayenneDataObject})
+ *
+ * @see CayenneDataObject
+ * @since 4.1
+ */
+public abstract class BaseDataObject extends PersistentObject implements DataObject, Validating {
+
+ private static final long serialVersionUID = 4598677040697008371L;
+
+ protected long snapshotVersion = DEFAULT_VERSION;
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ // return null by default to keep compatibility with pre 4.1 versions
+ return null;
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ throw new IllegalArgumentException("Unknown property: " + propName);
+ }
+
+ protected void beforePropertyRead(String propName) {
+ if(objectContext != null) {
+ // will resolve faults ourselves below as checking class descriptors
+ // for the "lazyFaulting" flag is inefficient. Passing "false" here to
+ // suppress fault processing
+ objectContext.prepareForAccess(this, propName, false);
+ }
+ }
+
+ protected void beforePropertyWrite(String propName, Object oldValue, Object newValue) {
+ if(objectContext != null) {
+ objectContext.prepareForAccess(this, propName, false);
+ objectContext.propertyChanged(this, propName, oldValue, newValue);
+ }
+ }
+
+ @Override
+ public Object readProperty(String propertyName) {
+ beforePropertyRead(propertyName);
+
+ Object object = readPropertyDirectly(propertyName);
+
+ if (object instanceof Fault) {
+ object = ((Fault) object).resolveFault(this, propertyName);
+ writePropertyDirectly(propertyName, object);
+ }
+
+ return object;
+ }
+
+ /**
+ * Returns a value of the property identified by a property path. Supports
+ * reading both mapped and unmapped properties. Unmapped properties are
+ * accessed in a manner consistent with JavaBeans specification.
+ * <p>
+ * Property path (or nested property) is a dot-separated path used to
+ * traverse object relationships until the final object is found. If a null
+ * object found while traversing path, null is returned. If a list is
+ * encountered in the middle of the path, CayenneRuntimeException is thrown.
+ * Unlike {@link #readPropertyDirectly(String)}, this method will resolve an
+ * object if it is HOLLOW.
+ * <p>
+ * Examples:
+ * </p>
+ * <ul>
+ * <li>Read this object property:<br>
+ * <code>String name = (String)artist.readNestedProperty("name");</code><br>
+ * <br>
+ * </li>
+ * <li>Read an object related to this object:<br>
+ * <code>Gallery g = (Gallery)paintingInfo.readNestedProperty("toPainting.toGallery");</code>
+ * <br>
+ * <br>
+ * </li>
+ * <li>Read a property of an object related to this object: <br>
+ * <code>String name = (String)painting.readNestedProperty("toArtist.artistName");</code>
+ * <br>
+ * <br>
+ * </li>
+ * <li>Read to-many relationship list:<br>
+ * <code>List exhibits = (List)painting.readNestedProperty("toGallery.exhibitArray");</code>
+ * <br>
+ * <br>
+ * </li>
+ * <li>Read to-many relationship in the middle of the path:<br>
+ * <code>List<String> names = (List<String>)artist.readNestedProperty("paintingArray.paintingName");</code>
+ * <br>
+ * <br>
+ * </li>
+ * </ul>
+ *
+ * @since 1.0.5
+ */
+ public Object readNestedProperty(String path) {
+
+ if ((null == path) || (0 == path.length())) {
+ throw new IllegalArgumentException("the path must be supplied in order to lookup a nested property");
+ }
+
+ int dotIndex = path.indexOf('.');
+
+ if (0 == dotIndex) {
+ throw new IllegalArgumentException("the path is invalid because it starts with a period character");
+ }
+
+ if (dotIndex == path.length() - 1) {
+ throw new IllegalArgumentException("the path is invalid because it ends with a period character");
+ }
+
+ if (-1 == dotIndex) {
+ return readSimpleProperty(path);
+ }
+
+ String path0 = path.substring(0, dotIndex);
+ String pathRemainder = path.substring(dotIndex + 1);
+
+ // this is copied from the old code where the placement of a plus
+ // character at the end of a segment of a property path would
+ // simply strip out the plus. I am not entirely sure why this is
+ // done. See unit test 'testReadNestedPropertyToManyInMiddle1'.
+
+ if ('+' == path0.charAt(path0.length() - 1)) {
+ path0 = path0.substring(0, path0.length() - 1);
+ }
+
+ Object property = readSimpleProperty(path0);
+
+ if (property == null) {
+ return null;
+ } else if (property instanceof DataObject) {
+ return ((DataObject) property).readNestedProperty(pathRemainder);
+ } else {
+ return Cayenne.readNestedProperty(property, pathRemainder);
+ }
+ }
+
+ Object readSimpleProperty(String property) {
+
+ // side effect - resolves HOLLOW object
+ Object object = readProperty(property);
+
+ // if a null value is returned, there is still a chance to
+ // find a non-persistent property via reflection
+ if (object == null) {
+ object = PropertyUtils.getProperty(this, property);
+ }
+
+ return object;
+ }
+
+ @Override
+ public void writeProperty(String propName, Object val) {
+ Object oldValue = readPropertyDirectly(propName);
+ beforePropertyWrite(propName, oldValue, val);
+
+ writePropertyDirectly(propName, val);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void removeToManyTarget(String relName, DataObject value, boolean setReverse) {
+
+ // Now do the rest of the normal handling (regardless of whether it was
+ // flattened or not)
+ Object holder = readProperty(relName);
+
+ // call 'propertyChanged' AFTER readProperty as readProperty ensures
+ // that this object fault is resolved
+ objectContext.propertyChanged(this, relName, value, null);
+
+ // TODO: andrus 8/20/2007 - can we optimize this somehow, avoiding type checking??
+ if (holder instanceof Collection) {
+ ((Collection<Object>) holder).remove(value);
+ } else if (holder instanceof Map) {
+ ((Map<Object, Object>) holder).remove(getMapKey(relName, value));
+ }
+
+ if (value != null && setReverse) {
+ unsetReverseRelationship(relName, value);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void addToManyTarget(String relName, DataObject value, boolean setReverse) {
+ if (value == null) {
+ throw new NullPointerException("Attempt to add null target DataObject.");
+ }
+
+ willConnect(relName, value);
+
+ // Now do the rest of the normal handling (regardless of whether it was
+ // flattened or not)
+ Object holder = readProperty(relName);
+
+ // call 'propertyChanged' AFTER readProperty as readProperty ensures
+ // that this object fault is resolved
+ objectContext.propertyChanged(this, relName, null, value);
+
+ // TODO: andrus 8/20/2007 - can we optimize this somehow, avoiding type checking??
+ if (holder instanceof Collection) {
+ ((Collection<Object>) holder).add(value);
+ } else if (holder instanceof Map) {
+ ((Map<Object, Object>) holder).put(getMapKey(relName, value), value);
+ }
+
+ if (setReverse) {
+ setReverseRelationship(relName, value);
+ }
+ }
+
+ /**
+ * Sets the relationships to the specified <code>DataObject</code> objects.
+ *
+ * <p>
+ * New relationships will be created with
+ * {@link #addToManyTarget(String, org.apache.cayenne.DataObject, boolean)},
+ * already established relationships stay untouched. Missing relationships
+ * will be removed with
+ * {@link #removeToManyTarget(String, org.apache.cayenne.DataObject, boolean)}
+ * and returnd as List. You may delete them manually.
+ * </p>
+ *
+ * <p>
+ * Notice: Moving an object relationship to another object, is still needing
+ * an manually "unregister" from the first object by
+ * {@link #removeToManyTarget(String, org.apache.cayenne.DataObject, boolean)}
+ * </p>
+ *
+ * @param relName
+ * name of the relation
+ * @param values
+ * <code>DataObject</code> objects of this
+ * <code>Collection</code> are set to the object. No changes will
+ * be made to the the <code>Collection</code>, a copy is used. It
+ * is safe to pass a persisted <code>Collection</code> of another
+ * object.
+ * @param setReverse
+ * update reverse relationships
+ * @return <code>List<? extends DataObject></code> of unrelated
+ * DataObjects. If no relationship was removed an empty List is
+ * returned.
+ * @throws IllegalArgumentException
+ * if no relationship could be read by relName, or if the passed
+ * <code>Collection</code> is null. To clear all relationships
+ * use an empty <code>Collection</code>
+ * @throws UnsupportedOperationException
+ * if the relation Collection Type is neither
+ * <code>java.util.Collection</code> nor
+ * <code>java.util.Map</code>
+ * @since 4.0
+ */
+ @SuppressWarnings("unchecked")
+ public List<? extends DataObject> setToManyTarget(String relName, Collection<? extends DataObject> values,
+ boolean setReverse) {
+ if (values == null) {
+ throw new IllegalArgumentException("values Collection is null. To clear all relationships use an empty Collection");
+ }
+
+ Object property = readProperty(relName);
+ if(property == null) {
+ throw new IllegalArgumentException("unknown relName " + relName);
+ }
+ Collection<DataObject> old = null;
+ if (property instanceof Map) {
+ old = ((Map) property).values();
+ } else if (property instanceof Collection) {
+ old = (Collection) property;
+ } else {
+ throw new UnsupportedOperationException("setToManyTarget operates only with Map or Collection types");
+ }
+
+ // operate on a copy of passed collection
+ values = new ArrayList<>(values);
+
+ List<DataObject> removedObjects = new ArrayList<>();
+
+ // remove all relationships, which are missing in passed collection
+ Object[] oldValues = old.toArray();
+ for (Object obj : oldValues) {
+ if (!values.contains(obj)) {
+ DataObject obj2 = (DataObject) obj;
+ removeToManyTarget(relName, obj2, setReverse);
+ // collect objects whose relationship was removed
+ removedObjects.add((DataObject) obj2);
+ }
+ }
+
+ // dont add elements which are already present
+ for (Object obj : old) {
+ values.remove(obj);
+ }
+
+ // add new elements
+ for (DataObject obj : values) {
+ addToManyTarget(relName, obj, setReverse);
+ }
+
+ return removedObjects;
+ }
+
+ @Override
+ public void setToOneTarget(String relationshipName, DataObject value, boolean setReverse) {
+
+ willConnect(relationshipName, value);
+
+ Object oldTarget = readProperty(relationshipName);
+ if (oldTarget == value) {
+ return;
+ }
+
+ getObjectContext().propertyChanged(this, relationshipName, oldTarget, value);
+
+ if (setReverse) {
+ // unset old reverse relationship
+ if (oldTarget instanceof DataObject) {
+ unsetReverseRelationship(relationshipName, (DataObject) oldTarget);
+ }
+
+ // set new reverse relationship
+ if (value != null) {
+ setReverseRelationship(relationshipName, value);
+ }
+ }
+
+ // readProperty will call this
+ //objectContext.prepareForAccess(this, relationshipName, false);
+ writePropertyDirectly(relationshipName, value);
+ }
+
+ /**
+ * Called before establishing a relationship with another object. Applies
+ * "persistence by reachability" logic, pulling one of the two objects to a
+ * DataConext of another object in case one of the objects is transient. If
+ * both objects are persistent, and they don't have the same DataContext,
+ * CayenneRuntimeException is thrown.
+ *
+ * @since 1.2
+ */
+ protected void willConnect(String relationshipName, Persistent object) {
+ // first handle most common case - both objects are in the same
+ // ObjectContext or target is null
+ if (object == null || this.getObjectContext() == object.getObjectContext()) {
+ return;
+ } else if (this.getObjectContext() == null && object.getObjectContext() != null) {
+ object.getObjectContext().registerNewObject(this);
+ } else if (this.getObjectContext() != null && object.getObjectContext() == null) {
+ this.getObjectContext().registerNewObject(object);
+ } else {
+ throw new CayenneRuntimeException("Cannot set object as destination of relationship %s"
+ + " because it is in a different ObjectContext", relationshipName);
+ }
+ }
+
+ /**
+ * Initializes reverse relationship from object <code>val</code> to this
+ * object.
+ *
+ * @param relName
+ * name of relationship from this object to <code>val</code>.
+ */
+ protected void setReverseRelationship(String relName, DataObject val) {
+ ObjRelationship rel = objectContext.getEntityResolver().getObjEntity(objectId.getEntityName())
+ .getRelationship(relName);
+ ObjRelationship revRel = rel.getReverseRelationship();
+ if (revRel != null) {
+ if (revRel.isToMany()) {
+ val.addToManyTarget(revRel.getName(), this, false);
+ } else {
+ val.setToOneTarget(revRel.getName(), this, false);
+ }
+ }
+ }
+
+ /**
+ * Removes current object from reverse relationship of object
+ * <code>val</code> to this object.
+ */
+ protected void unsetReverseRelationship(String relName, DataObject val) {
+
+ EntityResolver resolver = objectContext.getEntityResolver();
+ ObjEntity entity = resolver.getObjEntity(objectId.getEntityName());
+
+ if (entity == null) {
+ throw new IllegalStateException("DataObject's entity is unmapped, objectId: " + objectId);
+ }
+
+ ObjRelationship rel = entity.getRelationship(relName);
+ ObjRelationship revRel = rel.getReverseRelationship();
+ if (revRel != null) {
+ if (revRel.isToMany()) {
+ val.removeToManyTarget(revRel.getName(), this, false);
+ } else {
+ val.setToOneTarget(revRel.getName(), null, false);
+ }
+ }
+ }
+
+ @Override
+ public void setPersistenceState(int persistenceState) {
+ this.persistenceState = persistenceState;
+ }
+
+ /**
+ * @since 1.1
+ */
+ @Override
+ public long getSnapshotVersion() {
+ return snapshotVersion;
+ }
+
+ /**
+ * @since 1.1
+ */
+ @Override
+ public void setSnapshotVersion(long snapshotVersion) {
+ this.snapshotVersion = snapshotVersion;
+ }
+
+ /**
+ * Performs property validation of the object, appending any validation
+ * failures to the provided validationResult object. This method is invoked
+ * from "validateFor.." before committing a NEW or MODIFIED object to the
+ * database. Validation includes checking for null values and value sizes.
+ * CayenneDataObject subclasses may override this method, calling super.
+ *
+ * @since 1.1
+ */
+ protected void validateForSave(ValidationResult validationResult) {
+
+ ObjEntity objEntity = getObjectContext().getEntityResolver().getObjEntity(this);
+ if (objEntity == null) {
+ throw new CayenneRuntimeException("No ObjEntity mapping found for DataObject %s", getClass().getName());
+ }
+
+ // validate mandatory attributes
+
+ Map<String, ValidationFailure> failedDbAttributes = null;
+
+ for (ObjAttribute next : objEntity.getAttributes()) {
+
+ // TODO: andrus, 2/20/2007 - handle embedded attribute
+ if (next instanceof EmbeddedAttribute) {
+ continue;
+ }
+
+ DbAttribute dbAttribute = next.getDbAttribute();
+ if (dbAttribute == null) {
+ throw new CayenneRuntimeException("ObjAttribute '%s"
+ + "' does not have a corresponding DbAttribute", next.getName());
+ }
+
+ // pk may still be generated
+ if (dbAttribute.isPrimaryKey()) {
+ continue;
+ }
+
+ Object value = this.readPropertyDirectly(next.getName());
+ if (dbAttribute.isMandatory()) {
+ ValidationFailure failure = BeanValidationFailure.validateNotNull(this, next.getName(), value);
+
+ if (failure != null) {
+
+ if (failedDbAttributes == null) {
+ failedDbAttributes = new HashMap<>();
+ }
+
+ failedDbAttributes.put(dbAttribute.getName(), failure);
+ continue;
+ }
+ }
+
+ // validate length
+ if (value != null && dbAttribute.getMaxLength() > 0) {
+ if (value.getClass().isArray()) {
+ int len = Array.getLength(value);
+ if (len > dbAttribute.getMaxLength()) {
+ String message = "\"" + next.getName() + "\" exceeds maximum allowed length ("
+ + dbAttribute.getMaxLength() + " bytes): " + len;
+ validationResult.addFailure(new BeanValidationFailure(this, next.getName(), message));
+ }
+ } else if (value instanceof CharSequence) {
+ int len = ((CharSequence) value).length();
+ if (len > dbAttribute.getMaxLength()) {
+ String message = "\"" + next.getName() + "\" exceeds maximum allowed length ("
+ + dbAttribute.getMaxLength() + " chars): " + len;
+ validationResult.addFailure(new BeanValidationFailure(this, next.getName(), message));
+ }
+ }
+ }
+ }
+
+ // validate mandatory relationships
+ for (final ObjRelationship relationship : objEntity.getRelationships()) {
+
+ List<DbRelationship> dbRels = relationship.getDbRelationships();
+ if (dbRels.isEmpty()) {
+ continue;
+ }
+
+ // skip db relationships that we can't validate or that can't be invalid here
+ // can't handle paths longer than two db relationships
+ // see ObjRelationship.recalculateReadOnlyValue() for more info
+ if (relationship.isSourceIndependentFromTargetChange()) {
+ continue;
+ }
+
+ // if db relationship is not based on a PK and is based on mandatory
+ // attributes, see if we have a target object set
+ // relationship will be validated only if all db path has mandatory
+ // db relationships
+ boolean validate = true;
+ for (DbRelationship dbRelationship : dbRels) {
+ for (DbJoin join : dbRelationship.getJoins()) {
+ DbAttribute source = join.getSource();
+ if (source.isMandatory()) {
+ // clear attribute failures...
+ if (failedDbAttributes != null && !failedDbAttributes.isEmpty()) {
+ failedDbAttributes.remove(source.getName());
+ }
+ } else {
+ // do not validate if the relation is based on
+ // multiple keys with some that can be nullable.
+ validate = false;
+ }
+ }
+ }
+
+ if (validate) {
+ Object value = this.readPropertyDirectly(relationship.getName());
+ ValidationFailure failure = BeanValidationFailure.validateNotNull(this, relationship.getName(), value);
+
+ if (failure != null) {
+ validationResult.addFailure(failure);
+ }
+ }
+ }
+
+ // deal with previously found attribute failures...
+ if (failedDbAttributes != null && !failedDbAttributes.isEmpty()) {
+ for (ValidationFailure failure : failedDbAttributes.values()) {
+ validationResult.addFailure(failure);
+ }
+ }
+ }
+
+ /**
+ * Calls {@link #validateForSave(ValidationResult)}. CayenneDataObject
+ * subclasses may override it providing validation logic that should be
+ * executed for the newly created objects before saving them.
+ *
+ * @since 1.1
+ */
+ @Override
+ public void validateForInsert(ValidationResult validationResult) {
+ validateForSave(validationResult);
+ }
+
+ /**
+ * Calls {@link #validateForSave(ValidationResult)}. CayenneDataObject
+ * subclasses may override it providing validation logic that should be
+ * executed for the modified objects before saving them.
+ *
+ * @since 1.1
+ */
+ @Override
+ public void validateForUpdate(ValidationResult validationResult) {
+ validateForSave(validationResult);
+ }
+
+ /**
+ * This implementation does nothing. CayenneDataObject subclasses may
+ * override it providing validation logic that should be executed for the
+ * deleted objects before committing them.
+ *
+ * @since 1.1
+ */
+ @Override
+ public void validateForDelete(ValidationResult validationResult) {
+ // does nothing
+ }
+
+ /**
+ * @since 1.2
+ */
+ @Override
+ public void setObjectContext(ObjectContext objectContext) {
+ this.objectContext = objectContext;
+
+ if (objectContext == null) {
+ this.persistenceState = PersistenceState.TRANSIENT;
+ }
+ }
+
+ /**
+ * Serialization support.
+ * Will write down persistenceState and objectId, delegating data serialization down to sub-classes.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ writeSerialized(out);
+ }
+
+ /**
+ * Serialization support.
+ * Will read persistenceState and objectId, delegating data serialization down to sub-classes.
+ */
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ readSerialized(in);
+ }
+
+ protected void writeSerialized(ObjectOutputStream out) throws IOException {
+ out.writeInt(persistenceState);
+ out.writeObject(objectId);
+
+ if(persistenceState == PersistenceState.COMMITTED
+ || persistenceState == PersistenceState.HOLLOW) {
+ return;
+ }
+
+ writeState(out);
+ }
+
+ protected void readSerialized(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ this.persistenceState = in.readInt();
+ this.objectId = (ObjectId) in.readObject();
+
+ if(persistenceState == PersistenceState.COMMITTED
+ || persistenceState == PersistenceState.HOLLOW) {
+ persistenceState = PersistenceState.HOLLOW;
+ return;
+ }
+
+ readState(in);
+ }
+
+ protected void writeState(ObjectOutputStream out) throws IOException {
+ // no additional info for base class
+ }
+
+ protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ // no additional info for base class
+ }
+
+ /**
+ * A variation of "toString" method, that may be more efficient in some
+ * cases. For example when printing a list of objects into the same String.
+ */
+ public StringBuffer toStringBuffer(StringBuffer buffer, boolean fullDesc) {
+ String id = (objectId != null) ? objectId.toString() : "<no id>";
+ String state = PersistenceState.persistenceStateName(persistenceState);
+
+ buffer.append('{').append(id).append("; ").append(state).append("; ");
+
+ if (fullDesc) {
+ appendProperties(buffer);
+ }
+
+ buffer.append("}");
+ return buffer;
+ }
+
+ protected void appendProperties(StringBuffer buffer) {
+ }
+
+ @Override
+ public String toString() {
+ return toStringBuffer(new StringBuffer(), true).toString();
+ }
+
+}