Skip to content

Package: ClassFieldMetamodelProcessor

ClassFieldMetamodelProcessor

nameinstructionbranchcomplexitylinemethod
ClassFieldMetamodelProcessor(TypeBuilderContext, MetamodelBuilder)
M: 0 C: 23
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
createAttribute(Field, ClassFieldMetamodelProcessor.InferenceInfo, PropertyAttributes)
M: 5 C: 124
96%
M: 1 C: 7
88%
M: 1 C: 4
80%
M: 1 C: 25
96%
M: 0 C: 1
100%
createListAttribute(Field, ClassFieldMetamodelProcessor.InferenceInfo, PropertyAttributes)
M: 5 C: 51
91%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 12
92%
M: 0 C: 1
100%
createQueryAttribute(Field, Class)
M: 9 C: 87
91%
M: 2 C: 6
75%
M: 2 C: 3
60%
M: 2 C: 17
89%
M: 0 C: 1
100%
getFieldValueType(Field)
M: 0 C: 22
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
getSetOrListErasureType(ParameterizedType)
M: 10 C: 17
63%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 2 C: 5
71%
M: 0 C: 1
100%
isAspectIntegrationField(Field)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isPropertiesField(Field)
M: 0 C: 8
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isQueryAttribute(Field)
M: 0 C: 8
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isTypesField(Field)
M: 0 C: 8
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
processField(Field)
M: 17 C: 105
86%
M: 1 C: 17
94%
M: 1 C: 9
90%
M: 1 C: 28
97%
M: 0 C: 1
100%
processIdentifierField(Field)
M: 0 C: 27
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
processInferenceInfo(Field)
M: 0 C: 20
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
processPropertiesField(Field, Class, ClassFieldMetamodelProcessor.InferenceInfo)
M: 0 C: 38
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
processTypesField(Field, Class, ClassFieldMetamodelProcessor.InferenceInfo)
M: 0 C: 24
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
registerTypeReference(Attribute)
M: 0 C: 23
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 5
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%

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.MetamodelInitializationException;
18: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
19: import cz.cvut.kbss.jopa.model.BeanListenerAspect;
20: import cz.cvut.kbss.jopa.model.IRI;
21: import cz.cvut.kbss.jopa.model.annotations.Properties;
22: import cz.cvut.kbss.jopa.model.annotations.*;
23: import cz.cvut.kbss.jopa.oom.converter.ConverterWrapper;
24: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
25: import org.slf4j.Logger;
26: import org.slf4j.LoggerFactory;
27:
28: import java.lang.reflect.Field;
29: import java.lang.reflect.ParameterizedType;
30: import java.lang.reflect.Type;
31: import java.util.*;
32:
33: class ClassFieldMetamodelProcessor<X> {
34:
35: private static final Logger LOG = LoggerFactory.getLogger(ClassFieldMetamodelProcessor.class);
36:
37: private final FieldMappingValidator mappingValidator = new FieldMappingValidator();
38:
39: private final Class<X> cls;
40: private final AbstractIdentifiableType<X> et;
41: private final TypeBuilderContext<X> context;
42: private final MetamodelBuilder metamodelBuilder;
43:
44: ClassFieldMetamodelProcessor(TypeBuilderContext<X> context, MetamodelBuilder metamodelBuilder) {
45: this.cls = context.getType().getJavaType();
46: this.context = context;
47: this.et = context.getType();
48: this.metamodelBuilder = metamodelBuilder;
49: }
50:
51: void processField(Field field) {
52: LOG.trace("processing field: {}", field);
53:• if (EntityPropertiesUtils.isFieldTransient(field)) {
54: // Do not log static fields
55:• if (!EntityPropertiesUtils.isFieldStatic(field)) {
56: LOG.trace("Skipping transient field {}", field);
57: }
58: return;
59: }
60:• if (field.getType().isPrimitive()) {
61: throw new MetamodelInitializationException(
62: "Primitive types cannot be used for entity fields. Field " + field + " in class " + cls);
63: }
64:
65: final Class<?> fieldValueCls = getFieldValueType(field);
66: field.setAccessible(true);
67: final InferenceInfo inference = processInferenceInfo(field);
68:
69:• if (isTypesField(field)) {
70: processTypesField(field, fieldValueCls, inference);
71: return;
72: }
73:• if (isPropertiesField(field)) {
74: processPropertiesField(field, fieldValueCls, inference);
75: return;
76: }
77:
78:• if (isQueryAttribute(field)) {
79: createQueryAttribute(field, fieldValueCls);
80: return;
81: }
82:
83: final PropertyAttributes propertyAtt = PropertyAttributes.create(field, mappingValidator, context);
84: propertyAtt.resolve(field, metamodelBuilder, fieldValueCls);
85:
86:• if (propertyAtt.isKnownOwlProperty()) {
87: final AbstractAttribute<X, ?> a = createAttribute(field, inference, propertyAtt);
88: registerTypeReference(a);
89:• } else if (!isAspectIntegrationField(field)) {
90: final boolean success = processIdentifierField(field);
91:• if (!success) {
92: throw new MetamodelInitializationException(
93: "Unable to process field " + field + ". It is not transient but has no mapping information.");
94: }
95: }
96: }
97:
98: private static Class<?> getFieldValueType(Field field) {
99:• if (Collection.class.isAssignableFrom(field.getType())) {
100: return getSetOrListErasureType((ParameterizedType) field.getGenericType());
101:• } else if (field.getType().isArray()) {
102: throw new MetamodelInitializationException("Array persistent attributes are not supported.");
103: } else {
104: return field.getType();
105: }
106: }
107:
108: private static Class<?> getSetOrListErasureType(final ParameterizedType cls) {
109: final Type[] t = cls.getActualTypeArguments();
110:
111:• if (t.length != 1) {
112: throw new OWLPersistenceException("Only collections with a single generic parameter are supported.");
113: }
114: Type type = t[0];
115:• if (!(type instanceof Class<?>)) {
116: throw new OWLPersistenceException("Only Classes are valid parameters for generic lists and sets.");
117: }
118: return (Class<?>) type;
119: }
120:
121: private InferenceInfo processInferenceInfo(Field field) {
122: final Inferred inferred = field.getAnnotation(Inferred.class);
123:
124: final InferenceInfo inference = new InferenceInfo(inferred);
125:• if (inference.inferred) {
126: metamodelBuilder.addInferredClass(cls);
127: }
128: return inference;
129: }
130:
131: private static boolean isTypesField(Field field) {
132:• return field.getAnnotation(Types.class) != null;
133: }
134:
135: private void processTypesField(Field field, Class<?> fieldValueCls, InferenceInfo inference) {
136: Types tt = field.getAnnotation(Types.class);
137: mappingValidator.validateTypesField(field);
138: et.addDirectTypes(new TypesSpecificationImpl<>(et, tt.fetchType(), field, fieldValueCls, inference.inferred));
139: }
140:
141: private static boolean isPropertiesField(Field field) {
142:• return field.getAnnotation(Properties.class) != null;
143: }
144:
145: private void processPropertiesField(Field field, Class<?> fieldValueCls, InferenceInfo inference) {
146: Properties properties = field.getAnnotation(Properties.class);
147: mappingValidator.validatePropertiesField(field);
148: final PropertiesParametersResolver paramsResolver = new PropertiesParametersResolver(field);
149: et.addOtherProperties(
150: PropertiesSpecificationImpl.declaringType(et).fetchType(properties.fetchType()).javaField(field)
151: .javaType(fieldValueCls).inferred(inference.inferred)
152: .propertyIdType(paramsResolver.getPropertyIdentifierType())
153: .propertyValueType(paramsResolver.getPropertyValueType()).build());
154: }
155:
156: private static boolean isQueryAttribute(Field field) {
157:• return field.getAnnotation(Sparql.class) != null;
158: }
159:
160: private void createQueryAttribute(Field field, Class<?> fieldValueCls) {
161: final Sparql sparqlAnnotation = field.getAnnotation(Sparql.class);
162: final String query = sparqlAnnotation.query();
163: final FetchType fetchType = sparqlAnnotation.fetchType();
164:
165: ParticipationConstraint[] participationConstraints = field.getAnnotationsByType(ParticipationConstraint.class);
166:
167: final AbstractQueryAttribute<X, ?> a;
168:
169: cz.cvut.kbss.jopa.model.metamodel.Type<?> type;
170:
171:• if (ManagedClassProcessor.isManagedType(fieldValueCls)) {
172: type = metamodelBuilder.getEntityClass(fieldValueCls);
173: } else {
174: type = BasicTypeImpl.get(fieldValueCls);
175: }
176:
177: Optional<ConverterWrapper<?, ?>> optionalConverterWrapper = context.getConverterResolver()
178: .resolveConverter(type);
179: ConverterWrapper<?, ?> converterWrapper = null;
180:
181:• if (optionalConverterWrapper.isPresent()) {
182: converterWrapper = optionalConverterWrapper.get();
183: }
184:
185:• if (Collection.class.isAssignableFrom(field.getType())) {
186: a = new PluralQueryAttributeImpl<>(query, sparqlAnnotation.enableReferencingAttributes(), field, et, fetchType, participationConstraints, type, field.getType(), converterWrapper);
187:• } else if (Map.class.isAssignableFrom(field.getType())) {
188: throw new IllegalArgumentException("NOT YET SUPPORTED");
189: } else {
190: a = new SingularQueryAttributeImpl<>(query, sparqlAnnotation.enableReferencingAttributes(), field, et, fetchType, type, participationConstraints, converterWrapper);
191: }
192:
193: et.addDeclaredQueryAttribute(field.getName(), a);
194: }
195:
196: private AbstractAttribute<X, ?> createAttribute(Field field, InferenceInfo inference,
197: PropertyAttributes propertyAttributes) {
198: final AbstractAttribute<X, ?> a;
199:• if (field.getType().isAssignableFrom(Collection.class)) {
200: final AbstractPluralAttribute.PluralAttributeBuilder builder =
201: CollectionAttributeImpl.builder(propertyAttributes).declaringType(et)
202: .field(field)
203: .inferred(inference.inferred).includeExplicit(inference.includeExplicit);
204: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
205: a = (AbstractAttribute<X, ?>) builder.build();
206:• } else if (field.getType().isAssignableFrom(List.class)) {
207: a = createListAttribute(field, inference, propertyAttributes);
208:• } else if (field.getType().isAssignableFrom(Set.class)) {
209: final AbstractPluralAttribute.PluralAttributeBuilder builder =
210: SetAttributeImpl.builder(propertyAttributes).declaringType(et)
211: .field(field)
212: .inferred(inference.inferred).includeExplicit(inference.includeExplicit);
213: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
214: a = (AbstractAttribute<X, ?>) builder.build();
215:• } else if (field.getType().isAssignableFrom(Map.class)) {
216: throw new IllegalArgumentException("NOT YET SUPPORTED");
217: } else {
218: final SingularAttributeImpl.SingularAttributeBuilder builder =
219: SingularAttributeImpl.builder(propertyAttributes).declaringType(et)
220: .field(field)
221: .inferred(inference.inferred).includeExplicit(inference.includeExplicit);
222: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
223: a = (AbstractAttribute<X, ?>) builder.build();
224: }
225: et.addDeclaredAttribute(field.getName(), a);
226: return a;
227: }
228:
229: private AbstractAttribute<X, ?> createListAttribute(Field field,
230: InferenceInfo inference,
231: PropertyAttributes propertyAttributes) {
232: final Sequence os = field.getAnnotation(Sequence.class);
233:• if (os == null) {
234: throw new MetamodelInitializationException("Expected Sequence annotation.");
235: }
236: final ListAttributeImpl.ListAttributeBuilder builder =
237: ListAttributeImpl.builder(propertyAttributes).declaringType(et)
238: .field(field)
239: .inferred(inference.inferred).includeExplicit(inference.includeExplicit)
240: .owlListClass(IRI.create(os.ClassOWLListIRI()))
241: .hasNextProperty(IRI.create(os.ObjectPropertyHasNextIRI()))
242: .hasContentsProperty(IRI.create(os.ObjectPropertyHasContentsIRI()))
243: .sequenceType(os.type());
244: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
245: return builder.build();
246: }
247:
248: private void registerTypeReference(Attribute<X, ?> attribute) {
249:• final Class<?> type = attribute.isCollection() ? ((PluralAttribute<X, ?, ?>) attribute).getBindableJavaType() :
250: attribute.getJavaType();
251:• if (metamodelBuilder.hasManagedType(type)) {
252: metamodelBuilder.registerTypeReference(type, et.getJavaType());
253: }
254: }
255:
256: private boolean processIdentifierField(Field field) {
257: final Id id = field.getAnnotation(Id.class);
258:• if (id == null) {
259: return false;
260: }
261: mappingValidator.validateIdentifierType(field.getType());
262: et.setIdentifier(new IRIIdentifierImpl<>(et, field, id.generated()));
263: return true;
264: }
265:
266: private static boolean isAspectIntegrationField(Field field) {
267: // AspectJ integration fields cannot be declared transitive (they're generated by the AJC), so we have to
268: // skip them manually
269: return field.getType().equals(BeanListenerAspect.Manageable.class);
270: }
271:
272: private static class InferenceInfo {
273: private final boolean inferred;
274: private final boolean includeExplicit;
275:
276: InferenceInfo(Inferred inferredAnnotation) {
277: this.inferred = inferredAnnotation != null;
278: this.includeExplicit = inferredAnnotation == null || inferredAnnotation.includeExplicit();
279: }
280: }
281: }