Skip to content

Package: CollectionChangeDetector

CollectionChangeDetector

nameinstructionbranchcomplexitylinemethod
CollectionChangeDetector(ChangeDetector, MetamodelProvider)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getSetComparator(Class)
M: 0 C: 11
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
hasChanges(Object, Object)
M: 8 C: 37
82%
M: 2 C: 8
80%
M: 2 C: 4
67%
M: 0 C: 11
100%
M: 0 C: 1
100%
lambda$getSetComparator$0(Object, Object)
M: 0 C: 24
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 5
100%
M: 0 C: 1
100%
orderedCollectionChanged(Collection, Collection)
M: 0 C: 28
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
setChanged(Collection, Collection)
M: 8 C: 38
83%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 0 C: 9
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /*
2: * JOPA
3: * Copyright (C) 2023 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jopa.sessions.change;
19:
20: import cz.cvut.kbss.jopa.sessions.MetamodelProvider;
21: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
22:
23: import java.util.*;
24:
25: /**
26: * Checks for changes in a collection. By changes it is understood:
27: * <pre>
28: * <ul>
29: * <li>Different number of elements,</li>
30: * <li>Different order of elements in a collection with deterministic ordering semantics (List, Queue,
31: * <b>NOT!</b> Set)</li>
32: * <li>Different elements in the collection</li>
33: * </ul>
34: * </pre>
35: */
36: class CollectionChangeDetector implements ChangeDetector {
37:
38: private final ChangeDetector changeDetector;
39:
40: private final MetamodelProvider metamodelProvider;
41:
42: CollectionChangeDetector(ChangeDetector changeDetector, MetamodelProvider metamodelProvider) {
43: this.changeDetector = changeDetector;
44: this.metamodelProvider = metamodelProvider;
45: }
46:
47: @Override
48: public boolean hasChanges(Object clone, Object original) {
49:• assert clone != null;
50:• assert original != null;
51:
52: Collection<?> origCol = (Collection<?>) original;
53: Collection<?> cloneCol = (Collection<?>) clone;
54:• if (origCol.size() != cloneCol.size()) {
55: return true;
56: }
57:• if (origCol.isEmpty()) {
58: return false;
59: }
60:• if (origCol instanceof Set) {
61: return setChanged(cloneCol, origCol);
62: } else {
63: return orderedCollectionChanged(cloneCol, origCol);
64: }
65: }
66:
67: private boolean orderedCollectionChanged(Collection<?> clone, Collection<?> original) {
68: Iterator<?> itOrig = original.iterator();
69: Iterator<?> itClone = clone.iterator();
70: boolean changes = false;
71:• while (itOrig.hasNext() && !changes) {
72: final Object cl = itClone.next();
73: final Object orig = itOrig.next();
74: changes = changeDetector.hasChanges(cl, orig);
75: }
76: return changes;
77: }
78:
79: /**
80: * When checking for set changes, we have to make sure different element order does not mean a change.
81: * <p>
82: * Therefore, we first order the elements in a predictable way and then compare the elements.
83: */
84: private boolean setChanged(Collection<?> clone, Collection<?> original) {
85:• assert !clone.isEmpty();
86:• assert !original.isEmpty();
87:
88: final Class<?> elementType = clone.iterator().next().getClass();
89: final List<?> cloneList = new ArrayList<>(clone);
90: final Comparator<Object> comparator = getSetComparator(elementType);
91: cloneList.sort(comparator);
92: final List<?> originalList = new ArrayList<>(original);
93: originalList.sort(comparator);
94: return orderedCollectionChanged(cloneList, originalList);
95: }
96:
97: /**
98: * For managed types, the comparator uses identifier's hashCode, for all other types hashCode is used directly.
99: */
100: private Comparator<Object> getSetComparator(Class<?> elemType) {
101:• if (metamodelProvider.isEntityType(elemType)) {
102: return (o1, o2) -> {
103: final Object keyOne = EntityPropertiesUtils.getIdentifier(o1, metamodelProvider.getMetamodel());
104: final Object keyTwo = EntityPropertiesUtils.getIdentifier(o2, metamodelProvider.getMetamodel());
105:• if (keyOne == null || keyTwo == null) {
106: return 0;
107: }
108: return Integer.compare(keyOne.hashCode(), keyTwo.hashCode());
109: };
110: } else {
111: return Comparator.comparingInt(Object::hashCode);
112: }
113: }
114: }