diff --git a/cadc-util/build.gradle b/cadc-util/build.gradle index 0a9f8c87..564392ae 100644 --- a/cadc-util/build.gradle +++ b/cadc-util/build.gradle @@ -15,7 +15,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.12.15' +version = '1.12.16' description = 'OpenCADC core utility library' def git_url = 'https://github.com/opencadc/core' diff --git a/cadc-util/src/main/java/org/opencadc/persist/Entity.java b/cadc-util/src/main/java/org/opencadc/persist/Entity.java index 379d5602..d2c1084f 100644 --- a/cadc-util/src/main/java/org/opencadc/persist/Entity.java +++ b/cadc-util/src/main/java/org/opencadc/persist/Entity.java @@ -120,10 +120,12 @@ public abstract class Entity { private final String localPackage; public static boolean MCS_DEBUG = false; // way to much debug when true + public static byte[] ZERO_BYTE = new byte[] { (byte) 0 }; private final boolean digestFieldNames; private final boolean digestFieldNamesLowerCase; private final boolean truncateDateToSec; + private final boolean digestZeroByteAfterListItem; private UUID id; private Date lastModified; private URI metaChecksum; @@ -145,84 +147,67 @@ static final void assertNotNull(Class caller, String name, Object test) } } - /** - * Backwards compatible constructor: digestFieldNames==false. - * - * @param truncateDateToSec truncate Date values to seconds when converting to bytes for meta checksum calculation - * @deprecated hard code Entity(boolean, boolean, boolean) in model - */ + // backwards compat ctors for cadc-vos @Deprecated - protected Entity(boolean truncateDateToSec) { - this(truncateDateToSec, false, false); + protected Entity(boolean truncateDateToSec, boolean digestFieldNames) { + this(truncateDateToSec, digestFieldNames, false, false); } - - /** - * Backwards compatible constructor: digestFieldNames==false. - * - * @param id assign the specified Entity.id - * @param truncateDateToSec truncate Date values to seconds when converting to bytes for meta checksum calculation - * @deprecated hard code Entity(UUID, boolean, boolean, boolean) in model - */ + @Deprecated - protected Entity(UUID id, boolean truncateDateToSec) { - this(id, truncateDateToSec, false, false); + protected Entity(UUID id, boolean truncateDateToSec, boolean digestFieldNames) { + this(id, truncateDateToSec, digestFieldNames, false, false); } + // end: cadc-vos - /** - * Backwards compatible constructor: digestFieldNamesLowerCase==false. - * - * @param truncateDateToSec truncate Date values to seconds when converting to bytes for meta checksum calculation - * @param digestFieldNames when a field is not null (or collection is non-empty), include the field name in the - * metaChecksum calculation - */ - protected Entity(boolean truncateDateToSec, boolean digestFieldNames) { - this(truncateDateToSec, digestFieldNames, false); + // backwards compat ctor for cadc-inventory + @Deprecated + protected Entity(boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase) { + this(truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase, false); } - - /** - * Backwards compatible constructor: digestFieldNamesLowerCase==false. - * - * @param id assign the specified Entity.id - * @param truncateDateToSec truncate Date values to seconds when converting to bytes for meta checksum calculation - * @param digestFieldNames when a field is not null (or collection is non-empty), include the field name in the - * metaChecksum calculation - */ - protected Entity(UUID id, boolean truncateDateToSec, boolean digestFieldNames) { - this(id, truncateDateToSec, digestFieldNames, false); + + @Deprecated + protected Entity(UUID id, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase) { + this(id, truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase, false); } + // end: cadc-inventory /** - * Constructor.This creates a new entity with a random UUID. + * Constructor. This creates a new entity with a random UUID. * * @param truncateDateToSec truncate Date values to seconds when converting to bytes for meta checksum calculation * @param digestFieldNames when a field is not null (or collection is non-empty), include the field name in the * metaChecksum calculation * @param digestFieldNamesLowerCase convert field names to lower case before digesting + * @param digestZeroByteAfterListItem digest a single byte value 0 after item in a collection */ - protected Entity(boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase) { - this(UUID.randomUUID(), truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase); + protected Entity(boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase, + boolean digestZeroByteAfterListItem) { + this(UUID.randomUUID(), truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase, digestZeroByteAfterListItem); } /** * Constructor.This creates an entity with an existing UUID when reconstructing an instance. The - truncateDateToSec option should be used if instances of the model are to be serialized or stored - in a way that does not recover the exact timestamp to milliseconds. The digestFieldNames option - is needed for any model with "adjacent" fields that could contain the same value; this option - ensures that "moving" the value from one field to another will change the checksum by changing - the sequence of bytes that are digested. + * truncateDateToSec option should be used if instances of the model are to be serialized or stored + * in a way that does not recover the exact timestamp to milliseconds. The digestFieldNames option + * is needed for any model with "adjacent" fields that could contain the same value; this option + * ensures that "moving" the value from one field to another will change the checksum by changing + * the sequence of bytes that are digested. * * @param id unique ID value to assign/restore * @param truncateDateToSec truncate Date values to seconds when converting to bytes for meta checksum calculation * @param digestFieldNames when a field is not null (or collection is non-empty), include the field name in the * metaChecksum calculation * @param digestFieldNamesLowerCase convert field names to lower case before digesting + * @param digestZeroByteAfterListItem digest a single byte value 0 after item in a collection */ - protected Entity(UUID id, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase) { + protected Entity(UUID id, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase, + boolean digestZeroByteAfterListItem) { Entity.assertNotNull(Entity.class, "id", id); this.id = id; this.truncateDateToSec = truncateDateToSec; this.digestFieldNames = digestFieldNames; this.digestFieldNamesLowerCase = digestFieldNamesLowerCase; + this.digestZeroByteAfterListItem = digestZeroByteAfterListItem; this.localPackage = this.getClass().getPackage().getName(); } @@ -327,21 +312,26 @@ private void visitImpl(Class c, Object o, EntityVisitor ev) { SortedSet fields = getStateFields(c); for (Field f : fields) { - String cf = f.getDeclaringClass().getSimpleName() + "." + f.getName(); + String vodmlID = f.getDeclaringClass().getSimpleName() + "." + f.getName(); f.setAccessible(true); Object fo = f.get(o); if (fo == null) { - ev.visitNull(cf); + ev.visitNull(vodmlID); } else { Class ac = fo.getClass(); - if (ac.isEnum() || PrimitiveWrapper.class.isAssignableFrom(ac)) { + if (fo instanceof PrimitiveWrapper) { + PrimitiveWrapper pw = (PrimitiveWrapper) fo; + fo = pw.getWrappedValue(); + ac = fo.getClass(); + } + if (ac.isEnum()) { try { log.warn("unwrap: " + ac.getSimpleName() + ".getValue()"); Method m = ac.getMethod("getValue"); Object val = m.invoke(fo); - ev.visitLeaf(cf, val); + ev.visitLeaf(vodmlID, val); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { throw new RuntimeException("BUG - enum " + ac.getName() + " does not have getValue()", ex); } @@ -349,7 +339,7 @@ private void visitImpl(Class c, Object o, EntityVisitor ev) { // depth-first recursion visitImpl(ac, fo, ev); // visit intermediate DM class - ev.visitNode(cf, fo); + ev.visitNode(vodmlID, fo); } else if (fo instanceof Collection) { Collection stuff = (Collection) fo; if (!stuff.isEmpty()) { @@ -357,11 +347,16 @@ private void visitImpl(Class c, Object o, EntityVisitor ev) { while (i.hasNext()) { Object co = i.next(); Class cc = co.getClass(); - if (cc.isEnum() || PrimitiveWrapper.class.isAssignableFrom(cc)) { + if (co instanceof PrimitiveWrapper) { + PrimitiveWrapper cpo = (PrimitiveWrapper) co; + co = cpo.getWrappedValue(); + cc = co.getClass(); + } + if (cc.isEnum()) { try { Method m = cc.getMethod("getValue"); Object val = m.invoke(co); - ev.visitLeaf(cf, val); + ev.visitLeaf(vodmlID, val); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { throw new RuntimeException("BUG", ex); } @@ -369,19 +364,36 @@ private void visitImpl(Class c, Object o, EntityVisitor ev) { // depth-first recursion visitImpl(cc, co, ev); // visit intermediate DM class - ev.visitNode(cf, co); + ev.visitNode(vodmlID, co); } else { - ev.visitLeaf(cf, co); + ev.visitLeaf(vodmlID, co); } } } - ev.visitCollection(cf, stuff); + ev.visitCollection(vodmlID, stuff); } else { - ev.visitLeaf(cf, fo); + ev.visitLeaf(vodmlID, fo); } } } + SortedSet cfields = getChildFields(c); + for (Field cf : cfields) { + String vodmlID = cf.getDeclaringClass().getSimpleName() + "." + cf.getName(); + cf.setAccessible(true); + Object cfo = cf.get(o); + if (cfo == null) { + ev.visitChildNull(vodmlID); + } else if (cfo instanceof Collection) { + // child fields always collection, never null + Collection stuff = (Collection) cfo; + ev.visitChildCollection(vodmlID, stuff); + } else { + Entity e = (Entity) cfo; + ev.visitChildEntity(vodmlID, e); + } + } + } catch (IllegalAccessException bug) { throw new RuntimeException("Unable to calculate metaChecksum for class " + c.getName(), bug); } @@ -433,11 +445,17 @@ protected final void calcMetaChecksum(Class c, Object o, MessageDigestWrapper di String cf = f.getDeclaringClass().getSimpleName() + "." + f.getName(); f.setAccessible(true); Object fo = f.get(o); + if (fo != null) { Class ac = fo.getClass(); - if (ac.isEnum() || PrimitiveWrapper.class.isAssignableFrom(ac)) { + if (fo instanceof PrimitiveWrapper) { + // unwrap + PrimitiveWrapper pw = (PrimitiveWrapper) fo; + fo = pw.getWrappedValue(); + ac = fo.getClass(); + } + if (ac.isEnum()) { try { - log.warn("unwrap: " + ac.getSimpleName() + ".getValue()"); Method m = ac.getMethod("getValue"); Object val = m.invoke(fo); digest.update(primitiveValueToBytes(val, cf)); @@ -457,11 +475,17 @@ protected final void calcMetaChecksum(Class c, Object o, MessageDigestWrapper di } else if (fo instanceof Collection) { Collection stuff = (Collection) fo; if (!stuff.isEmpty()) { - Iterator i = stuff.iterator(); - while (i.hasNext()) { - Object co = i.next(); + Iterator iter = stuff.iterator(); + while (iter.hasNext()) { + Object co = iter.next(); Class cc = co.getClass(); - if (cc.isEnum() || PrimitiveWrapper.class.isAssignableFrom(cc)) { + if (co instanceof PrimitiveWrapper) { + // unwrap + PrimitiveWrapper cpo = (PrimitiveWrapper) co; + co = cpo.getWrappedValue(); + cc = co.getClass(); + } + if (cc.isEnum()) { try { Method m = cc.getMethod("getValue"); Object val = m.invoke(co); @@ -475,6 +499,9 @@ protected final void calcMetaChecksum(Class c, Object o, MessageDigestWrapper di } else { digest.update(primitiveValueToBytes(co, cf)); } + if (digestZeroByteAfterListItem) { + digest.update(ZERO_BYTE); + } } if (digestFieldNames) { digest.update(fieldNameToBytes(cf)); // field name @@ -664,6 +691,13 @@ protected byte[] primitiveValueToBytes(Object o, String name) { byte[] b = HexUtil.toBytes(Double.doubleToLongBits(da[i])); // IEEE754 double System.arraycopy(b, 0, ret, i * 8, 8); } + } else if (o instanceof long[]) { + long[] da = (long[]) o; + ret = new byte[8 * da.length]; + for (int i = 0; i < da.length; i++) { + byte[] b = HexUtil.toBytes(da[i]); + System.arraycopy(b, 0, ret, i * 8, 8); + } } if (ret != null) { @@ -677,7 +711,7 @@ protected byte[] primitiveValueToBytes(Object o, String name) { return ret; } - throw new UnsupportedOperationException("unexpected primitive/value type: " + o.getClass().getName()); + throw new UnsupportedOperationException("unexpected primitive/value type: " + o.getClass().getName() + " field: " + name); } protected byte[] fieldNameToBytes(String name) { diff --git a/cadc-util/src/main/java/org/opencadc/persist/EntityVisitor.java b/cadc-util/src/main/java/org/opencadc/persist/EntityVisitor.java index 8707bd58..a145beb6 100644 --- a/cadc-util/src/main/java/org/opencadc/persist/EntityVisitor.java +++ b/cadc-util/src/main/java/org/opencadc/persist/EntityVisitor.java @@ -99,8 +99,32 @@ public interface EntityVisitor { public void visitNode(String vodmlID, Object val); /** - * Visit a null value. This could be a node or a primitive. + * Visit a null value. This could be a node or a leaf. * @param vodmlID the {declaringClass}.{fieldName} aka vodml-id */ public void visitNull(String vodmlID); + + /** + * Visit a collection of child entity(s). + * + * @param vodmlID the {declaringClass}.{fieldName} aka vodml-id + * @param val the collection + */ + public void visitChildCollection(String vodmlID, Collection val); + + /** + * Visit a null child entity value. + * + * @param vodmlID the {declaringClass}.{fieldName} aka vodml-id + */ + public void visitChildNull(String vodmlID); + + /** + * Visit a direct child entity. There is no recursion into the structure of + * the child entity. + * + * @param vodmlID the {declaringClass}.{fieldName} aka vodml-id + * @param val the entity + */ + public void visitChildEntity(String vodmlID, Entity val); } diff --git a/cadc-util/src/main/java/org/opencadc/persist/PrimitiveWrapper.java b/cadc-util/src/main/java/org/opencadc/persist/PrimitiveWrapper.java index 93acdd68..2de403e8 100644 --- a/cadc-util/src/main/java/org/opencadc/persist/PrimitiveWrapper.java +++ b/cadc-util/src/main/java/org/opencadc/persist/PrimitiveWrapper.java @@ -75,5 +75,12 @@ * @author pdowler */ public interface PrimitiveWrapper { - public Object getValue(); + /** + * Unwrap the inner state and return it. The return value can be a primitive, + * immutable class (String, URI, Double, Long, etc), a primitive array (e.g. double[]), + * or a java.util.Collection (possibly empty). + * + * @return the wrapped value + */ + public Object getWrappedValue(); } diff --git a/cadc-util/src/test/java/ca/nrc/cadc/date/DateUtilTest.java b/cadc-util/src/test/java/ca/nrc/cadc/date/DateUtilTest.java index 1746612e..463c3b69 100644 --- a/cadc-util/src/test/java/ca/nrc/cadc/date/DateUtilTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/date/DateUtilTest.java @@ -289,6 +289,16 @@ public void testFromModifiedJulianDateToISO8601Date() Assert.fail("unexpected exception: " + unexpected); throw unexpected; } + + DateFormat df = DateUtil.getDateFormat(DateUtil.IVOA_DATE_FORMAT, DateUtil.UTC); + String str = "2026-03-08T02:02:41.056"; + Date orig = df.parse(str); + double mjd = DateUtil.toModifiedJulianDate(orig); + Date actual = DateUtil.fromModifiedJulianDate(mjd); + log.info(str + " -> " + df.format(orig) + " -> " + mjd + " -> " + df.format(actual)); + Assert.assertEquals(orig, actual); + + } @Test diff --git a/cadc-util/src/test/java/org/opencadc/persist/EntityTest.java b/cadc-util/src/test/java/org/opencadc/persist/EntityTest.java index 18d9dc66..88cb9680 100644 --- a/cadc-util/src/test/java/org/opencadc/persist/EntityTest.java +++ b/cadc-util/src/test/java/org/opencadc/persist/EntityTest.java @@ -85,7 +85,7 @@ public class EntityTest { static { Log4jInit.setLevel("org.opencadc.persist", Level.DEBUG); - // this actually controls the large amoutn of debug output from checksum + // this actually controls the large amount of debug output from checksum // algorithm, but it effects the whole jvm so only enable when running // these tests specificially and looking at output //Entity.MCS_DEBUG = true; @@ -109,41 +109,41 @@ public void testTemplate() { @Test public void testEntity() { // base: the cadc-inventory-0.x configuration - doEntityTest(false, false, false); - doNewVersionTest(false, false, false); + doEntityTest(false, false, false, false); + doNewVersionTest(false, false, false, false); } @Test public void testEntityTruncateDates() { // the caom2-2.4 configuration - doEntityTest(true, false, false); - doNewVersionTest(true, false, false); + doEntityTest(true, false, false, false); + doNewVersionTest(true, false, false, false); } @Test public void testEntityDigestFieldNames() { // the cadc-vos-2.x configuration - doEntityTest(false, true, false); - doNewVersionTest(false, true, false); + doEntityTest(false, true, false, false); + doNewVersionTest(false, true, false, false); } @Test public void testEntityDigestFieldNamesLower() { - // the cadc-vos-2.x configuration - doEntityTest(false, true, true); - doNewVersionTest(false, true, true); + // the caom-2.5 configuration + doEntityTest(false, true, true, false); + doNewVersionTest(false, true, true, false); } @Test public void testEntitySafeMode() { // no known use, but truncateDates and digestFieldNames is the safest mode - doEntityTest(true, true, true); - doNewVersionTest(true, true, true); + doEntityTest(true, true, true, true); + doNewVersionTest(true, true, true, false); } - private void doEntityTest(boolean trunc, boolean dig, boolean digL) { + private void doEntityTest(boolean trunc, boolean dig, boolean digL, boolean digZB) { try { - SampleEntity sample = new SampleEntity("name-of-this-entity", trunc, dig, digL); + SampleEntity sample = new SampleEntity("name-of-this-entity", trunc, dig, digL, digZB); log.info("created: " + sample); URI mcs1 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); @@ -173,12 +173,23 @@ private void doEntityTest(boolean trunc, boolean dig, boolean digL) { Assert.assertNotEquals(mcs6, mcs7); // set of string - sample.strList.add("foo"); + sample.strList.add("abc"); URI mcs8 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); Assert.assertNotEquals(mcs7, mcs8); - sample.strList.add("bar"); + sample.strList.add("def"); URI mcs9 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); Assert.assertNotEquals(mcs8, mcs9); + // list-item subtleness + sample.strList.clear(); + sample.strList.add("abcd"); + sample.strList.add("ef"); + log.warn("checking digZB..."); + URI mcs9b = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); + if (digZB) { + Assert.assertNotEquals(mcs9, mcs9b); + } else { + Assert.assertEquals(mcs9, mcs9b); + } // revert to 7 sample.strList.clear(); URI mcs10 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); @@ -193,11 +204,11 @@ private void doEntityTest(boolean trunc, boolean dig, boolean digL) { Assert.assertNotEquals(mcs7, mcs12); // entities do not get included in metaChecksum - sample.children.add(new SampleEntity("flibble", trunc, dig, digL)); + sample.children.add(new SampleEntity("flibble", trunc, dig, digL, digZB)); URI tcs1 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); Assert.assertEquals(mcs12, tcs1); - sample.relation = new SampleEntity("flibble", trunc, dig, digL); + sample.child1 = new SampleEntity("flibble", trunc, dig, digL, digZB); mcs11 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); Assert.assertEquals(mcs12, mcs11); @@ -219,13 +230,13 @@ private void doEntityTest(boolean trunc, boolean dig, boolean digL) { } // also doubles as a sub-class/extension test - private void doNewVersionTest(boolean trunc, boolean dig, boolean digL) { + private void doNewVersionTest(boolean trunc, boolean dig, boolean digL, boolean digZB) { try { - SampleEntity v1 = new SampleEntity("name-of-this-entity", trunc, dig, digL); + SampleEntity v1 = new SampleEntity("name-of-this-entity", trunc, dig, digL, digZB); log.info("created: " + v1); URI mcs1 = v1.computeMetaChecksum(MessageDigest.getInstance("MD5")); - SampleEntityV2 v2 = new SampleEntityV2(v1.getID(), v1.getName(), trunc, dig, digL); + SampleEntityV2 v2 = new SampleEntityV2(v1.getID(), v1.getName(), trunc, dig, digL, digZB); log.info("created: " + v1); URI mcs2 = v2.computeMetaChecksum(MessageDigest.getInstance("MD5")); @@ -239,7 +250,7 @@ private void doNewVersionTest(boolean trunc, boolean dig, boolean digL) { @Test public void testNonState() { try { - SampleEntity sample = new SampleEntity("name-of-this-entity", false, false, false); + SampleEntity sample = new SampleEntity("name-of-this-entity", false, false, false, false); log.info("created: " + sample); URI mcs1 = sample.computeMetaChecksum(MessageDigest.getInstance("MD5")); diff --git a/cadc-util/src/test/java/org/opencadc/persist/EntityVisitorTest.java b/cadc-util/src/test/java/org/opencadc/persist/EntityVisitorTest.java index c269d24d..0b622dc8 100644 --- a/cadc-util/src/test/java/org/opencadc/persist/EntityVisitorTest.java +++ b/cadc-util/src/test/java/org/opencadc/persist/EntityVisitorTest.java @@ -91,7 +91,7 @@ public EntityVisitorTest() { @Test public void testLogVisitor() { - SampleEntity e = new SampleEntity("foo", false, true, true); + SampleEntity e = new SampleEntity("foo", false, true, true, true); e.dateVal = null; e.doubleVal = 2.0; e.longVal = 123L; @@ -99,6 +99,7 @@ public void testLogVisitor() { e.nestedSet.add(new SampleEntity.Nested("abc")); e.nestedSet.add(new SampleEntity.Nested("def")); e.strList.add("foo"); + e.child1 = new SampleEntity("foo.child1", false, true, true, true); log.info("testLogVisitor: START"); LogVisitor v = new LogVisitor(); @@ -108,16 +109,25 @@ public void testLogVisitor() { Assert.assertEquals("numLeaf", 9, v.numLeaf); Assert.assertEquals("numNode", 3, v.numNode); // nested, nestedSet, emptySet Assert.assertEquals("numNull", 7, v.numNull); + Assert.assertEquals("numCol", 3, v.numCol); + Assert.assertEquals("numChildCol", 1, v.numChildCol); + Assert.assertEquals("numChildEntity", 1, v.numChildEntity); + Assert.assertEquals("numChildNull", 2, v.numChildNull); } private class LogVisitor implements EntityVisitor { int numLeaf = 0; int numNode = 0; int numNull = 0; + int numCol = 0; + int numChildCol = 0; + int numChildNull = 0; + int numChildEntity = 0; @Override public void visitCollection(String vodmlID, Collection val) { System.out.println("visit collection: " + vodmlID + " " + val.size()); + numCol++; } @Override @@ -137,7 +147,23 @@ public void visitNull(String vodmlID) { System.out.println("visit null: " + vodmlID); numNull++; } - - + + @Override + public void visitChildCollection(String vodmlID, Collection val) { + System.out.println("visit collection: " + vodmlID); + numChildCol++; + } + + @Override + public void visitChildNull(String vodmlID) { + System.out.println("visit child null: " + vodmlID); + numChildNull++; + } + + @Override + public void visitChildEntity(String vodmlID, Entity val) { + System.out.println("visit child entity: " + vodmlID); + numChildEntity++; + } } } diff --git a/cadc-util/src/test/java/org/opencadc/persist/SampleEntity.java b/cadc-util/src/test/java/org/opencadc/persist/SampleEntity.java index 742ae140..b50b94ef 100644 --- a/cadc-util/src/test/java/org/opencadc/persist/SampleEntity.java +++ b/cadc-util/src/test/java/org/opencadc/persist/SampleEntity.java @@ -97,18 +97,22 @@ public class SampleEntity extends Entity implements Comparable { // not included public Set children = new TreeSet<>(); - public SampleEntity relation; + public SampleEntity child1; + public SampleEntity child2; + public SampleEntity child3; public static String staticVal; public transient String transientVal; - public SampleEntity(String name, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase) { - super(truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase); + public SampleEntity(String name, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase, + boolean digestZeroByteAfterListItem) { + super(truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase, digestZeroByteAfterListItem); this.name = name; } - public SampleEntity(UUID id, String name, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase) { - super(id, truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase); + public SampleEntity(UUID id, String name, boolean truncateDateToSec, boolean digestFieldNames, boolean digestFieldNamesLowerCase, + boolean digestZeroByteAfterListItem) { + super(id, truncateDateToSec, digestFieldNames, digestFieldNamesLowerCase, digestZeroByteAfterListItem); this.name = name; } diff --git a/cadc-util/src/test/java/org/opencadc/persist/SampleEntityV2.java b/cadc-util/src/test/java/org/opencadc/persist/SampleEntityV2.java index bd6ad14c..5e34f861 100644 --- a/cadc-util/src/test/java/org/opencadc/persist/SampleEntityV2.java +++ b/cadc-util/src/test/java/org/opencadc/persist/SampleEntityV2.java @@ -80,8 +80,8 @@ public class SampleEntityV2 extends SampleEntity { public Integer optionalInt; public String optionalString; - public SampleEntityV2(UUID id, String name, boolean trunc, boolean dig, boolean digL) { - super(id, name, trunc, dig, digL); + public SampleEntityV2(UUID id, String name, boolean trunc, boolean dig, boolean digL, boolean digZB) { + super(id, name, trunc, dig, digL, digZB); } public String toString() {