Skip to content

Package: MapInstanceBuilder

MapInstanceBuilder

nameinstructionbranchcomplexitylinemethod
MapInstanceBuilder(CloneBuilderImpl, UnitOfWorkImpl)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
buildClone(Object, Field, Object, CloneConfiguration)
M: 19 C: 46
71%
M: 3 C: 5
63%
M: 2 C: 3
60%
M: 3 C: 10
77%
M: 0 C: 1
100%
buildSingletonClone(Object, Field, Map, CloneConfiguration)
M: 20 C: 36
64%
M: 6 C: 4
40%
M: 5 C: 1
17%
M: 1 C: 7
88%
M: 0 C: 1
100%
cloneMapContent(Object, Field, Map, Map, CloneConfiguration)
M: 25 C: 54
68%
M: 4 C: 6
60%
M: 3 C: 3
50%
M: 4 C: 14
78%
M: 0 C: 1
100%
cloneObject(Object, Field, Object, CloneConfiguration)
M: 13 C: 19
59%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 2 C: 4
67%
M: 0 C: 1
100%
cloneUsingDefaultConstructor(Object, Field, Class, Map, CloneConfiguration)
M: 0 C: 16
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
createDefaultMap(int)
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
createNewInstance(Class, int)
M: 22 C: 42
66%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 9 C: 13
59%
M: 0 C: 1
100%
mergeChanges(Field, Object, Object, Object)
M: 23 C: 81
78%
M: 6 C: 14
70%
M: 6 C: 5
45%
M: 2 C: 20
91%
M: 0 C: 1
100%
populatesAttributes()
M: 0 C: 2
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%

Coverage

1: /**
2: * Copyright (C) 2022 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.sessions;
16:
17: import cz.cvut.kbss.jopa.adapters.IndirectCollection;
18: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
19: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
20:
21: import java.lang.reflect.Constructor;
22: import java.lang.reflect.Field;
23: import java.lang.reflect.InvocationTargetException;
24: import java.security.AccessController;
25: import java.security.PrivilegedActionException;
26: import java.util.Collection;
27: import java.util.Collections;
28: import java.util.HashMap;
29: import java.util.Map;
30: import java.util.Map.Entry;
31:
32: class MapInstanceBuilder extends AbstractInstanceBuilder {
33:
34: private static final Class<?> singletonMapClass = Collections.singletonMap(null, null)
35: .getClass();
36:
37: MapInstanceBuilder(CloneBuilderImpl builder, UnitOfWorkImpl uow) {
38: super(builder, uow);
39: }
40:
41: @Override
42: Object buildClone(Object cloneOwner, Field field, Object original, CloneConfiguration configuration) {
43: Map<?, ?> orig = (Map<?, ?>) original;
44:• if (original instanceof IndirectCollection) {
45: orig = ((IndirectCollection<Map<?, ?>>) original).unwrap();
46: }
47: final Class<?> origCls = orig.getClass();
48: Map<?, ?> clone;
49: clone = cloneUsingDefaultConstructor(cloneOwner, field, origCls, orig, configuration);
50:• if (clone == null) {
51:• if (singletonMapClass.isInstance(orig)) {
52: clone = buildSingletonClone(cloneOwner, field, orig, configuration);
53:• } else if (Collections.emptyMap().equals(orig)) {
54: clone = orig;
55: }
56: else {
57: throw new IllegalArgumentException("Unsupported map type " + origCls);
58: }
59: }
60: clone = (Map<?, ?>) uow.createIndirectCollection(clone, cloneOwner, field);
61: return clone;
62:
63: }
64:
65: private Map<?, ?> cloneUsingDefaultConstructor(Object cloneOwner, Field field, Class<?> origCls, Map<?, ?> original,
66: CloneConfiguration configuration) {
67: Map<?, ?> result = createNewInstance(origCls, original.size());
68:• if (result != null) {
69: cloneMapContent(cloneOwner, field, original, result, configuration);
70: }
71: return result;
72: }
73:
74: private static Map<?, ?> createNewInstance(Class<?> type, int size) {
75: Map<?, ?> result = null;
76: final Class<?>[] types = {int.class};
77: Object[] params;
78: Constructor<?> c = getDeclaredConstructorFor(type, types);
79:• if (c != null) {
80: params = new Object[1];
81: params[0] = size;
82: } else {
83: c = getDeclaredConstructorFor(type, null);
84: params = null;
85: }
86:• if (c == null) {
87: return null;
88: }
89: try {
90: result = (Map<?, ?>) c.newInstance(params);
91: } catch (InstantiationException | IllegalArgumentException | InvocationTargetException e) {
92: throw new OWLPersistenceException(e);
93: } catch (IllegalAccessException e) {
94: logConstructorAccessException(c, e);
95: try {
96: result = (Map<?, ?>) AccessController
97: .doPrivileged(new PrivilegedInstanceCreator(c));
98: } catch (PrivilegedActionException ex) {
99: logPrivilegedConstructorAccessException(c, ex);
100: // Do nothing
101: }
102: }
103: return result;
104: }
105:
106: private Map<?, ?> buildSingletonClone(Object cloneOwner, Field field, Map<?, ?> orig,
107: CloneConfiguration configuration) {
108: Entry<?, ?> e = orig.entrySet().iterator().next();
109:• Object key = CloneBuilderImpl.isImmutable(e.getKey()) ? e.getKey() :
110: cloneObject(cloneOwner, field, e.getKey(), configuration);
111:• Object value = CloneBuilderImpl.isImmutable(e.getValue()) ? e.getValue() :
112: cloneObject(cloneOwner, field, e.getValue(), configuration);
113:• if ((value instanceof Collection || value instanceof Map) && !(value instanceof IndirectCollection)) {
114: value = uow.createIndirectCollection(value, cloneOwner, field);
115: }
116: return Collections.singletonMap(key, value);
117: }
118:
119: private void cloneMapContent(Object cloneOwner, Field field, Map<?, ?> source,
120: Map<?, ?> target, CloneConfiguration configuration) {
121:• if (source.isEmpty()) {
122: return;
123: }
124: final Map<Object, Object> m = (Map<Object, Object>) target;
125: final Entry<?, ?> tmp = source.entrySet().iterator().next();
126: // Note: If we encounter null -> null mapping first, the whole map will be treated as immutable type map, which can be incorrect
127: final boolean keyPrimitive = CloneBuilderImpl.isImmutable(tmp.getKey());
128: final boolean valuePrimitive = CloneBuilderImpl.isImmutable(tmp.getValue());
129:• for (Entry<?, ?> e : source.entrySet()) {
130: Object key;
131: Object value;
132:• if (keyPrimitive) {
133:• if (valuePrimitive) {
134: m.putAll(source);
135: break;
136: }
137: key = e.getKey();
138: value = cloneObject(cloneOwner, field, e.getValue(), configuration);
139: } else {
140: key = cloneObject(cloneOwner, field, e.getKey(), configuration);
141:• value = valuePrimitive ? e.getValue() : cloneObject(cloneOwner, field, e.getValue(), configuration);
142: }
143: m.put(key, value);
144: }
145: }
146:
147: private Object cloneObject(Object owner, Field field, Object obj, CloneConfiguration configuration) {
148: Object clone;
149:• if (obj == null) {
150: clone = null;
151:• } else if (builder.isTypeManaged(obj.getClass())) {
152: clone = uow.registerExistingObject(obj, configuration.getDescriptor(), configuration.getPostRegister());
153: } else {
154: clone = builder.buildClone(owner, field, obj, configuration.getDescriptor());
155: }
156: return clone;
157: }
158:
159: @Override
160: void mergeChanges(Field field, Object target, Object originalValue, Object cloneValue) {
161:• assert (originalValue == null) || (originalValue instanceof Map);
162:• assert cloneValue instanceof Map;
163:
164: Map<Object, Object> orig = (Map<Object, Object>) originalValue;
165: Map<Object, Object> clone = (Map<Object, Object>) cloneValue;
166:• if (clone instanceof IndirectCollection) {
167: clone = ((IndirectCollection<Map<Object, Object>>) clone).unwrap();
168: }
169:• if (orig == null) {
170: orig = (Map<Object, Object>) createNewInstance(clone.getClass(), clone.size());
171:• if (orig == null) {
172: orig = createDefaultMap(clone.size());
173: }
174: EntityPropertiesUtils.setFieldValue(field, target, orig);
175: }
176: orig.clear();
177:• if (clone.isEmpty()) {
178: return;
179: }
180:• for (Entry<?, ?> e : clone.entrySet()) {
181: final Object key = e.getKey();
182: final Object value = e.getValue();
183:• final Object keyToPut = uow.contains(key) ? builder.getOriginal(key) : key;
184:• final Object valueToPut = uow.contains(value) ? builder.getOriginal(value) : value;
185: orig.put(keyToPut, valueToPut);
186: }
187: }
188:
189: private static Map<Object, Object> createDefaultMap(int size) {
190:• return new HashMap<>(size > 1 ? size : 16);
191: }
192:
193: @Override
194: boolean populatesAttributes() {
195: return true;
196: }
197: }