Skip to content

Package: DefaultInstanceBuilder

DefaultInstanceBuilder

nameinstructionbranchcomplexitylinemethod
DefaultInstanceBuilder(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: 147 C: 17
10%
M: 12 C: 4
25%
M: 7 C: 2
22%
M: 42 C: 7
14%
M: 0 C: 1
100%
buildNewInstanceUsingDefaultConstructor(Class)
M: 22 C: 17
44%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 10 C: 7
41%
M: 0 C: 1
100%
mergeChanges(Field, Object, Object, Object)
M: 0 C: 43
100%
M: 1 C: 7
88%
M: 1 C: 4
80%
M: 0 C: 11
100%
M: 0 C: 1
100%
mergeFieldChanges(Object, Object, Class)
M: 9 C: 36
80%
M: 2 C: 4
67%
M: 2 C: 2
50%
M: 1 C: 8
89%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
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;
19:
20: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
21: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
22: import org.slf4j.Logger;
23: import org.slf4j.LoggerFactory;
24:
25: import java.lang.reflect.Constructor;
26: import java.lang.reflect.Field;
27: import java.lang.reflect.InvocationTargetException;
28: import java.security.AccessController;
29: import java.security.PrivilegedActionException;
30: import java.util.ArrayList;
31: import java.util.Collection;
32: import java.util.List;
33:
34: /**
35: * This class has responsibility for creating new instances of various kinds of objects. It handles security
36: * restrictions as well.
37: */
38: class DefaultInstanceBuilder extends AbstractInstanceBuilder {
39:
40: private static final Logger LOG = LoggerFactory.getLogger(DefaultInstanceBuilder.class);
41:
42: DefaultInstanceBuilder(CloneBuilderImpl builder, UnitOfWorkImpl uow) {
43: super(builder, uow);
44: }
45:
46: /**
47: * Builds a new instance of the specified class.
48: *
49: * @return New object of the given class.
50: */
51: @Override
52: Object buildClone(Object cloneOwner, Field field, Object original, CloneConfiguration config) {
53:• if (CloneBuilderImpl.isImmutable(original)) {
54: return original;
55: }
56: final Class<?> javaClass = original.getClass();
57: Object newInstance = buildNewInstanceUsingDefaultConstructor(javaClass);
58:• if (newInstance == null) {
59: final Field[] fields = javaClass.getDeclaredFields();
60: List<Class<?>> fieldClasses = new ArrayList<>();
61: Constructor<?> c;
62: try {
63:• for (Field f : fields) {
64:• if (EntityPropertiesUtils.isFieldTransient(f)) {
65: continue;
66: }
67: Class<?>[] args = {f.getType()};
68: c = getDeclaredConstructorFor(javaClass, args);
69:• if (c == null) {
70: fieldClasses.add(f.getType());
71: } else {
72: try {
73: Object[] params = new Object[1];
74: params[0] = original.getClass().getDeclaredField(f.getName());
75: newInstance = c.newInstance(params);
76: return newInstance;
77: } catch (SecurityException e) {
78: logConstructorAccessException(c, e);
79: try {
80: newInstance = AccessController.doPrivileged(new PrivilegedInstanceCreator(c));
81: } catch (PrivilegedActionException ex) {
82: throw new OWLPersistenceException(ex);
83: }
84:• if (newInstance != null) {
85: return newInstance;
86: }
87: } catch (NoSuchFieldException e) {
88: throw new OWLPersistenceException(e);
89: }
90: }
91: }
92: Class<?>[] args = new Class<?>[fieldClasses.size()];
93: args = fieldClasses.toArray(args);
94: c = getDeclaredConstructorFor(javaClass, args);
95:• if (c != null) {
96: Object[] params = new Object[args.length];
97: try {
98: newInstance = c.newInstance(params);
99: } catch (SecurityException e) {
100: logConstructorAccessException(c, e);
101: try {
102: newInstance = AccessController.doPrivileged(new PrivilegedInstanceCreator(c));
103: } catch (PrivilegedActionException ex) {
104: throw new OWLPersistenceException(ex);
105: }
106: }
107: }
108: } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
109: throw new OWLPersistenceException(e);
110: }
111: }
112:• if (newInstance == null) {
113: throw new OWLPersistenceException(
114: "Unable to create a new object or to find a suitable constructor for class "
115: + javaClass.getName());
116: }
117: return newInstance;
118: }
119:
120: @Override
121: void mergeChanges(Field field, Object target, Object originalValue, Object cloneValue) {
122:• if (originalValue == null) {
123: Object clOrig = builder.getOriginal(cloneValue);
124:• if (clOrig == null) {
125: clOrig = cloneValue;
126: }
127: EntityPropertiesUtils.setFieldValue(field, target, clOrig);
128: return;
129: }
130: Class<?> cls = originalValue.getClass();
131:• if (builder.isTypeManaged(cls) && builder.getOriginal(cloneValue) != null) {
132: EntityPropertiesUtils.setFieldValue(field, target, builder.getOriginal(cloneValue));
133: } else {
134: mergeFieldChanges(originalValue, cloneValue, cls);
135: }
136: }
137:
138: private void mergeFieldChanges(Object originalValue, Object cloneValue, Class<?> cls) {
139: List<Field> fields = EntityPropertiesUtils.getAllFields(cls);
140:• for (Field f : fields) {
141: Object clVal = EntityPropertiesUtils.getFieldValue(f, cloneValue);
142: Object origVal = EntityPropertiesUtils.getFieldValue(f, originalValue);
143:• if (!(clVal instanceof Collection) && !builder.isOriginalInUoW(origVal)) {
144: EntityPropertiesUtils.setFieldValue(f, originalValue, clVal);
145: } else {
146: builder.getInstanceBuilder(origVal).mergeChanges(f, originalValue, origVal, clVal);
147: }
148: }
149: }
150:
151: /**
152: * Builds a new instance of the specified class, using its no-argument constructor.
153: *
154: * @return New object of the given class, or null if the class has no no-argument constructor.
155: */
156: private static Object buildNewInstanceUsingDefaultConstructor(final Class<?> javaClass) {
157: final Constructor<?> c = getDeclaredConstructorFor(javaClass, null);
158: Object newInstance = null;
159:• if (c != null) {
160: try {
161: try {
162: newInstance = c.newInstance((Object[]) null);
163: } catch (SecurityException e) {
164: logConstructorAccessException(c, e);
165: try {
166: newInstance = AccessController
167: .doPrivileged(new PrivilegedInstanceCreator(c));
168: } catch (PrivilegedActionException ex) {
169: logPrivilegedConstructorAccessException(c, ex);
170: return null;
171: }
172: }
173: } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
174: LOG.trace("Class {} does not have a suitable no-arg constructor.", javaClass);
175: // Do nothing
176: }
177: }
178: return newInstance;
179: }
180: }