Skip to content

Method: createDefaultMap(int)

1: /**
2: * Copyright (C) 2016 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.model.descriptors.Descriptor;
20: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
21:
22: import java.lang.reflect.Constructor;
23: import java.lang.reflect.Field;
24: import java.lang.reflect.InvocationTargetException;
25: import java.security.AccessController;
26: import java.security.PrivilegedActionException;
27: import java.util.Collection;
28: import java.util.Collections;
29: import java.util.HashMap;
30: import java.util.Map;
31: import java.util.Map.Entry;
32:
33: class MapInstanceBuilder extends AbstractInstanceBuilder {
34:
35: private static final Class<?> singletonMapClass = Collections.singletonMap(null, null)
36: .getClass();
37:
38: MapInstanceBuilder(CloneBuilderImpl builder, UnitOfWork uow) {
39: super(builder, uow);
40: this.populates = true;
41: }
42:
43: @Override
44: Object buildClone(Object cloneOwner, Field field, Object original, Descriptor repository) {
45: Map<?, ?> orig = (Map<?, ?>) original;
46: if (original instanceof IndirectCollection) {
47: orig = ((IndirectCollection<Map<?, ?>>) original).getReferencedCollection();
48: }
49: final Class<?> origCls = orig.getClass();
50: Map<?, ?> clone;
51: clone = cloneUsingDefaultConstructor(cloneOwner, field, origCls, orig, repository);
52: if (clone == null) {
53: if (singletonMapClass.isInstance(orig)) {
54: clone = buildSingletonClone(cloneOwner, field, orig, repository);
55: } else {
56: throw new IllegalArgumentException("Unsupported map type " + origCls);
57: }
58: }
59: clone = (Map<?, ?>) builder.createIndirectCollection(clone, cloneOwner, field);
60: return clone;
61:
62: }
63:
64: private Map<?, ?> cloneUsingDefaultConstructor(Object cloneOwner, Field field,
65: Class<?> origCls, Map<?, ?> original, Descriptor repository) {
66: Map<?, ?> result = createNewInstance(origCls, original.size());
67: if (result != null) {
68: cloneMapContent(cloneOwner, field, original, result, repository);
69: }
70: return result;
71: }
72:
73: private Map<?, ?> createNewInstance(Class<?> type, int size) {
74: Map<?, ?> result = null;
75: final Class<?>[] types = {int.class};
76: Object[] params;
77: Constructor<?> c = getDeclaredConstructorFor(type, types);
78: if (c != null) {
79: params = new Object[1];
80: params[0] = size;
81: } else {
82: c = getDeclaredConstructorFor(type, null);
83: params = null;
84: }
85: if (c == null) {
86: return null;
87: }
88: try {
89: result = (Map<?, ?>) c.newInstance(params);
90: } catch (InstantiationException | IllegalArgumentException | InvocationTargetException e) {
91: throw new OWLPersistenceException(e);
92: } catch (IllegalAccessException e) {
93: logConstructorAccessException(c, e);
94: try {
95: result = (Map<?, ?>) AccessController
96: .doPrivileged(new PrivilegedInstanceCreator(c));
97: } catch (PrivilegedActionException ex) {
98: logPrivilegedConstructorAccessException(c, ex);
99: // Do nothing
100: }
101: }
102: return result;
103: }
104:
105: private Map<?, ?> buildSingletonClone(Object cloneOwner, Field field, Map<?, ?> orig,
106: Descriptor repository) {
107: final Constructor<?> c = getFirstDeclaredConstructorFor(singletonMapClass);
108: if (!c.isAccessible()) {
109: c.setAccessible(true);
110: }
111: Entry<?, ?> e = orig.entrySet().iterator().next();
112: Object key = CloneBuilderImpl.isImmutable(e.getKey().getClass()) ? e.getKey()
113: : cloneObject(cloneOwner, field, e.getKey(), repository);
114: Object value = CloneBuilderImpl.isImmutable(e.getValue().getClass()) ? e.getValue()
115: : cloneObject(cloneOwner, field, e.getValue(), repository);
116: if (value instanceof Collection || value instanceof Map) {
117: value = builder.createIndirectCollection(value, cloneOwner, field);
118: }
119: try {
120: return (Map<?, ?>) c.newInstance(key, value);
121: } catch (IllegalAccessException ex) {
122: logConstructorAccessException(c, ex);
123: try {
124: return (Map<?, ?>) AccessController.doPrivileged(new PrivilegedInstanceCreator(c,
125: key, value));
126: } catch (PrivilegedActionException exx) {
127: throw new OWLPersistenceException(exx);
128: }
129: } catch (InstantiationException | IllegalArgumentException | InvocationTargetException ex) {
130: throw new OWLPersistenceException(ex);
131: }
132: }
133:
134: private void cloneMapContent(Object cloneOwner, Field field, Map<?, ?> source,
135: Map<?, ?> target, Descriptor repository) {
136: if (source.isEmpty()) {
137: return;
138: }
139: Map<Object, Object> m = (Map<Object, Object>) target;
140: Entry<?, ?> tmp = source.entrySet().iterator().next();
141: boolean keyPrimitive = CloneBuilderImpl.isImmutable(tmp.getKey().getClass());
142: boolean valuePrimitive = CloneBuilderImpl.isImmutable(tmp.getValue().getClass());
143: for (Entry<?, ?> e : source.entrySet()) {
144: Object key;
145: Object value;
146: if (keyPrimitive) {
147: if (valuePrimitive) {
148: m.putAll(source);
149: break;
150: }
151: key = e.getKey();
152: value = cloneObject(cloneOwner, field, e.getValue(), repository);
153: } else {
154: key = cloneObject(cloneOwner, field, e.getKey(), repository);
155: value = valuePrimitive ? e.getValue() : cloneObject(cloneOwner, field,
156: e.getValue(), repository);
157: }
158: m.put(key, value);
159: }
160: }
161:
162: private Object cloneObject(Object owner, Field field, Object obj, Descriptor repository) {
163: Object clone;
164: if (obj == null) {
165: clone = null;
166: } else if (builder.isTypeManaged(obj.getClass())) {
167: clone = uow.registerExistingObject(obj, repository);
168: } else {
169: clone = builder.buildClone(owner, field, obj, repository);
170: }
171: return clone;
172: }
173:
174: @Override
175: void mergeChanges(Field field, Object target, Object originalValue, Object cloneValue) {
176: assert (originalValue == null) || (originalValue instanceof Map);
177: assert cloneValue instanceof Map;
178:
179: Map<Object, Object> orig = (Map<Object, Object>) originalValue;
180: Map<Object, Object> clone = (Map<Object, Object>) cloneValue;
181: if (clone instanceof IndirectCollection) {
182: clone = ((IndirectCollection<Map<Object, Object>>) clone).getReferencedCollection();
183: }
184: if (orig == null) {
185: orig = (Map<Object, Object>) createNewInstance(clone.getClass(), clone.size());
186: if (orig == null) {
187: orig = createDefaultMap(clone.size());
188: }
189: EntityPropertiesUtils.setFieldValue(field, target, orig);
190: }
191: orig.clear();
192: if (clone.isEmpty()) {
193: return;
194: }
195: for (Entry<?, ?> e : clone.entrySet()) {
196: final Object key = e.getKey();
197: final Object value = e.getValue();
198: final Object keyToPut = uow.contains(key) ? builder.getOriginal(key) : key;
199: final Object valueToPut = uow.contains(value) ? builder.getOriginal(value) : value;
200: orig.put(keyToPut, valueToPut);
201: }
202: }
203:
204: private Map<Object, Object> createDefaultMap(int size) {
205:• return new HashMap<>(size > 1 ? size : 16);
206: }
207: }