Add QRecord as a handled type inside deepCopySimpleMap (e.g., so copy constructor won't need to warn about it and do slow serialization-based cloning).

This commit is contained in:
2024-01-04 18:11:05 -06:00
parent 92b052fe59
commit 93dcee9f61
2 changed files with 22 additions and 12 deletions

View File

@ -108,7 +108,7 @@ public class QRecord implements Serializable
/******************************************************************************* /*******************************************************************************
** Copy constructor. ** Copy constructor. Makes a deep clone.
** **
*******************************************************************************/ *******************************************************************************/
public QRecord(QRecord record) public QRecord(QRecord record)
@ -120,10 +120,10 @@ public class QRecord implements Serializable
this.displayValues = deepCopySimpleMap(record.displayValues); this.displayValues = deepCopySimpleMap(record.displayValues);
this.backendDetails = deepCopySimpleMap(record.backendDetails); this.backendDetails = deepCopySimpleMap(record.backendDetails);
this.associatedRecords = deepCopyAssociatedRecords(record.associatedRecords);
this.errors = record.errors == null ? null : new ArrayList<>(record.errors); this.errors = record.errors == null ? null : new ArrayList<>(record.errors);
this.warnings = record.warnings == null ? null : new ArrayList<>(record.warnings); this.warnings = record.warnings == null ? null : new ArrayList<>(record.warnings);
this.associatedRecords = deepCopyAssociatedRecords(record.associatedRecords);
} }
@ -143,17 +143,17 @@ public class QRecord implements Serializable
** todo - move to a cloning utils maybe? ** todo - move to a cloning utils maybe?
*******************************************************************************/ *******************************************************************************/
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
private <K, V> Map<K, V> deepCopySimpleMap(Map<K, V> map) private <V extends Serializable> Map<String, V> deepCopySimpleMap(Map<String, V> map)
{ {
if(map == null) if(map == null)
{ {
return (null); return (null);
} }
Map<K, V> clone = new LinkedHashMap<>(); Map<String, V> clone = new LinkedHashMap<>();
for(Map.Entry<K, V> entry : map.entrySet()) for(Map.Entry<String, V> entry : map.entrySet())
{ {
V value = entry.getValue(); Serializable value = entry.getValue();
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// not sure from where/how java.sql.Date objects are getting in here... // // not sure from where/how java.sql.Date objects are getting in here... //
@ -167,15 +167,17 @@ public class QRecord implements Serializable
ArrayList<?> cloneList = new ArrayList<>(arrayList); ArrayList<?> cloneList = new ArrayList<>(arrayList);
clone.put(entry.getKey(), (V) cloneList); clone.put(entry.getKey(), (V) cloneList);
} }
else if(entry.getValue() instanceof Serializable serializableValue) else if(entry.getValue() instanceof QRecord otherQRecord)
{ {
LOG.info("Non-primitive serializable value in QRecord - calling SerializationUtils.clone...", logPair("key", entry.getKey()), logPair("type", value.getClass())); clone.put(entry.getKey(), (V) new QRecord(otherQRecord));
clone.put(entry.getKey(), (V) SerializationUtils.clone(serializableValue));
} }
else else
{ {
LOG.warn("Non-serializable value in QRecord...", logPair("key", entry.getKey()), logPair("type", value.getClass())); //////////////////////////////////////////////////////////////////////////////
clone.put(entry.getKey(), entry.getValue()); // we know entry is serializable at this point, based on type param's bound //
//////////////////////////////////////////////////////////////////////////////
LOG.info("Non-primitive serializable value in QRecord - calling SerializationUtils.clone...", logPair("key", entry.getKey()), logPair("type", value.getClass()));
clone.put(entry.getKey(), (V) SerializationUtils.clone(entry.getValue()));
} }
} }
return (clone); return (clone);

View File

@ -151,6 +151,14 @@ class QRecordTest extends BaseTest
QRecord recordWithArrayListValue = new QRecord().withValue("myList", originalArrayList); QRecord recordWithArrayListValue = new QRecord().withValue("myList", originalArrayList);
QRecord cloneWithArrayListValue = new QRecord(recordWithArrayListValue); QRecord cloneWithArrayListValue = new QRecord(recordWithArrayListValue);
////////////////////////////////////////////
// qrecord as a value inside another (!?) //
////////////////////////////////////////////
QRecord nestedQRecordValue = new QRecord().withValue("myRecord", new QRecord().withValue("A", 1));
QRecord cloneWithNestedQRecord = new QRecord(nestedQRecordValue);
assertEquals(1, ((QRecord) cloneWithNestedQRecord.getValue("myRecord")).getValueInteger("A"));
assertNotSame(cloneWithNestedQRecord.getValue("myRecord"), nestedQRecordValue.getValue("myRecord"));
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// the clone list and original list should be equals (have contents that are equals), but not be the same (reference) // // the clone list and original list should be equals (have contents that are equals), but not be the same (reference) //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////