Skip to content

Package: StaticMetamodelInitializer

StaticMetamodelInitializer

nameinstructionbranchcomplexitylinemethod
StaticMetamodelInitializer(Metamodel)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getDeclaredAttribute(Field, ManagedType)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getDeclaredIdentifier(Field, ManagedType)
M: 2 C: 26
93%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 1 C: 5
83%
M: 0 C: 1
100%
getDeclaredProperties(Field, ManagedType)
M: 0 C: 23
100%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 4
100%
M: 0 C: 1
100%
getDeclaredTypes(Field, ManagedType)
M: 0 C: 23
100%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 4
100%
M: 0 C: 1
100%
getMetamodelMember(Field, ManagedType)
M: 0 C: 13
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
initStaticMembers(ManagedType, Class)
M: 0 C: 36
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
initializeStaticMetamodel()
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
isCanonicalMetamodelField(Field)
M: 0 C: 12
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 1
100%
M: 0 C: 1
100%
isDeclaredInClass(FieldSpecification, Class)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isNotStaticMetamodelForType(Class, Class)
M: 0 C: 16
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$getMetamodelMember$3(Field, ManagedType)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$null$0(Field)
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$null$1(Field, ManagedType)
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$null$2(Field, ManagedType)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
processEntities()
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
processManagedTypes()
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
processType(ManagedType)
M: 14 C: 30
68%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 2 C: 9
82%
M: 0 C: 1
100%
setFieldValue(Field, Object)
M: 4 C: 9
69%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 3
100%
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%
tryFindingClass(ManagedType)
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
verifyParent(Class, ManagedType)
M: 0 C: 37
100%
M: 2 C: 6
75%
M: 2 C: 3
60%
M: 0 C: 7
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.model.metamodel;
16:
17: import cz.cvut.kbss.jopa.exception.StaticMetamodelInitializationException;
18: import org.slf4j.Logger;
19: import org.slf4j.LoggerFactory;
20:
21: import java.lang.reflect.Field;
22: import java.lang.reflect.Modifier;
23: import java.util.Objects;
24: import java.util.Optional;
25: import java.util.Set;
26:
27: /**
28: * Initializes static metamodel based on the provided runtime metamodel.
29: * <p>
30: * Static metamodel initialization involves going through all managed types in the metamodel, finding a corresponding
31: * static metamodel class (if exists) and populating its attributes with values from the actual runtime metamodel.
32: */
33: public class StaticMetamodelInitializer {
34:
35: private static final Logger LOG = LoggerFactory.getLogger(StaticMetamodelInitializer.class);
36:
37: /**
38: * Suffix appended to a static metamodel class corresponding to a metamodel class.
39: */
40: private static final String STATIC_METAMODEL_CLASS_SUFFIX = "_";
41:
42: private final Metamodel metamodel;
43:
44: public StaticMetamodelInitializer(Metamodel metamodel) {
45: this.metamodel = metamodel;
46: }
47:
48: /**
49: * Executes the static metamodel initialization.
50: */
51: public void initializeStaticMetamodel() {
52: LOG.debug("Initializing static metamodel.");
53: processEntities();
54: processManagedTypes();
55: }
56:
57: private void processEntities() {
58: metamodel.getEntities().forEach(this::processType);
59: }
60:
61: private void processType(ManagedType<?> mt) {
62: final Optional<Class<?>> smClass = tryFindingClass(mt);
63:• if (!smClass.isPresent()) {
64: LOG.trace("No static metamodel type found for {}.", mt);
65: return;
66: }
67: LOG.debug("Processing static metamodel class {} corresponding to {}.", smClass.get(), mt);
68: verifyParent(smClass.get(), mt);
69: try {
70: initStaticMembers(mt, smClass.get());
71: } catch (IllegalAccessException e) {
72: throw new StaticMetamodelInitializationException("Unable to initialize static metamodel class " + smClass,
73: e);
74: }
75: }
76:
77: private static Optional<Class<?>> tryFindingClass(ManagedType<?> type) {
78: final String staticName = type.getJavaType().getName() + STATIC_METAMODEL_CLASS_SUFFIX;
79: try {
80: final Class<?> smClass = Class.forName(staticName);
81:• if (isNotStaticMetamodelForType(smClass, type.getJavaType())) {
82: return Optional.empty();
83: }
84: return Optional.of(smClass);
85: } catch (ClassNotFoundException e) {
86: // Swallow the exception, this just means there is no static metamodel type for the specified entity
87: return Optional.empty();
88: }
89: }
90:
91: private static boolean isNotStaticMetamodelForType(Class<?> smClass, Class<?> metamodelClass) {
92:• return smClass.getAnnotation(StaticMetamodel.class) == null ||
93:• !smClass.getAnnotation(StaticMetamodel.class).value().equals(metamodelClass);
94: }
95:
96: private static void verifyParent(Class<?> smClass, ManagedType<?> type) {
97:• if (type instanceof IdentifiableType<?>) {
98: final IdentifiableType<?> idType = (IdentifiableType<?>) type;
99:• if (idType.getSupertype() != null) {
100: final Optional<Class<?>> supertypeSm = tryFindingClass(idType.getSupertype());
101:• if (!supertypeSm.isPresent() || !Objects.equals(smClass.getSuperclass(), supertypeSm.get())) {
102: throw new StaticMetamodelInitializationException("Managed type " + type +
103: " has a managed supertype. A corresponding relationship must exist between static metamodel classes.");
104: }
105: }
106: }
107: }
108:
109: private <T> void initStaticMembers(ManagedType<T> et, Class<?> smClass) throws IllegalAccessException {
110: final Field[] fields = smClass.getDeclaredFields();
111:• for (Field f : fields) {
112:• if (!isCanonicalMetamodelField(f)) {
113: LOG.debug("Skipping field {}, it is not canonical (public static).", f);
114: continue;
115: }
116: final FieldSpecification<T, ?> att = getMetamodelMember(f, et);
117: setFieldValue(f, att);
118: }
119: }
120:
121: private static boolean isCanonicalMetamodelField(Field field) {
122:• return Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers());
123: }
124:
125: private static void setFieldValue(Field field, Object value) throws IllegalAccessException {
126:• assert isCanonicalMetamodelField(field);
127: field.set(null, value);
128: }
129:
130: private <T> FieldSpecification<T, ?> getMetamodelMember(Field field, ManagedType<T> type) {
131: LOG.trace("Finding metamodel member for static metamodel field {}.", field);
132: return getDeclaredIdentifier(field, type)
133: .orElseGet(() -> getDeclaredAttribute(field, type)
134: .orElseGet(() -> getDeclaredTypes(field, type)
135: .orElseGet(() -> getDeclaredProperties(field, type)
136: .orElseThrow(() -> new StaticMetamodelInitializationException(
137: "No corresponding metamodel member found for static metamodel field " +
138: field)))));
139: }
140:
141: private static <T> Optional<FieldSpecification<T, ?>> getDeclaredIdentifier(Field field, ManagedType<T> type) {
142:• if (!(type instanceof IdentifiableType)) {
143: return Optional.empty();
144: }
145: final IdentifiableType<T> mt = (IdentifiableType<T>) type;
146:• return Objects.equals(field.getName(), mt.getIdentifier().getJavaField().getName()) &&
147:• isDeclaredInClass(mt.getIdentifier(), type.getJavaType()) ?
148: Optional.of((Identifier<T, ?>) mt.getIdentifier()) : Optional.empty();
149: }
150:
151: private static boolean isDeclaredInClass(FieldSpecification<?, ?> fs, Class<?> cls) {
152: return fs.getJavaField().getDeclaringClass().equals(cls);
153: }
154:
155: private static <T> Optional<FieldSpecification<T, ?>> getDeclaredAttribute(Field field, ManagedType<T> type) {
156: try {
157: return Optional.of(type.getDeclaredAttribute(field.getName()));
158: } catch (IllegalArgumentException e) {
159: return Optional.empty();
160: }
161: }
162:
163: private static <T> Optional<FieldSpecification<T, ?>> getDeclaredTypes(Field field, ManagedType<T> type) {
164:• return type.getTypes() != null &&
165:• Objects.equals(field.getName(), type.getTypes().getJavaField().getName()) &&
166:• isDeclaredInClass(type.getTypes(), type.getJavaType()) ?
167: Optional.of((TypesSpecification<T, ?>) type.getTypes()) : Optional.empty();
168: }
169:
170: private static <T> Optional<FieldSpecification<T, ?>> getDeclaredProperties(Field field, ManagedType<T> type) {
171:• return type.getProperties() != null &&
172:• Objects.equals(field.getName(), type.getProperties().getJavaField().getName()) &&
173:• isDeclaredInClass(type.getProperties(), type.getJavaType()) ?
174: Optional.of((PropertiesSpecification<T, ?, ?, ?>) type.getProperties()) : Optional.empty();
175: }
176:
177: private void processManagedTypes() {
178: final Set<ManagedType<?>> managedTypes = metamodel.getManagedTypes();
179: managedTypes.removeAll(metamodel.getEntities());
180: managedTypes.forEach(this::processType);
181: }
182: }