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: 10 C: 135
93%
M: 2 C: 6
75%
M: 2 C: 3
60%
M: 2 C: 29
94%
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%
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: 93
85%
M: 1 C: 15
94%
M: 1 C: 8
89%
M: 1 C: 24
96%
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%
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) 2019 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
5: * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
6: * version.
7: * <p>
8: * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
9: * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
10: * details. You should have received a copy of the GNU General Public License along with this program. If not, see
11: * <http://www.gnu.org/licenses/>.
12: */
13: package cz.cvut.kbss.jopa.model.metamodel;
14:
15: import cz.cvut.kbss.jopa.exception.MetamodelInitializationException;
16: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
17: import cz.cvut.kbss.jopa.model.BeanListenerAspect;
18: import cz.cvut.kbss.jopa.model.IRI;
19: import cz.cvut.kbss.jopa.model.annotations.*;
20: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
21: import org.slf4j.Logger;
22: import org.slf4j.LoggerFactory;
23:
24: import java.lang.reflect.Field;
25: import java.lang.reflect.ParameterizedType;
26: import java.lang.reflect.Type;
27: import java.util.Collection;
28: import java.util.List;
29: import java.util.Map;
30: import java.util.Set;
31:
32: class ClassFieldMetamodelProcessor<X> {
33:
34: private static final Logger LOG = LoggerFactory.getLogger(ClassFieldMetamodelProcessor.class);
35:
36: private final FieldMappingValidator mappingValidator = new FieldMappingValidator();
37:
38: private final Class<X> cls;
39: private final AbstractIdentifiableType<X> et;
40: private final TypeBuilderContext<X> context;
41: private final MetamodelBuilder metamodelBuilder;
42:
43: ClassFieldMetamodelProcessor(TypeBuilderContext<X> context, MetamodelBuilder metamodelBuilder) {
44: this.cls = context.getType().getJavaType();
45: this.context = context;
46: this.et = context.getType();
47: this.metamodelBuilder = metamodelBuilder;
48: }
49:
50: void processField(Field field) {
51: LOG.trace("processing field: {}", field);
52:• if (EntityPropertiesUtils.isFieldTransient(field)) {
53: // Do not log static fields
54:• if (!EntityPropertiesUtils.isFieldStatic(field)) {
55: LOG.trace("Skipping transient field {}", field);
56: }
57: return;
58: }
59:• if (field.getType().isPrimitive()) {
60: throw new MetamodelInitializationException(
61: "Primitive types cannot be used for entity fields. Field " + field + " in class " + cls);
62: }
63:
64: final Class<?> fieldValueCls = getFieldValueType(field);
65: field.setAccessible(true);
66: final InferenceInfo inference = processInferenceInfo(field);
67:
68:• if (isTypesField(field)) {
69: processTypesField(field, fieldValueCls, inference);
70: return;
71: }
72:• if (isPropertiesField(field)) {
73: processPropertiesField(field, fieldValueCls, inference);
74: return;
75: }
76:
77: final PropertyAttributes propertyAtt = PropertyAttributes.create(field, mappingValidator, context);
78: propertyAtt.resolve(field, metamodelBuilder, fieldValueCls);
79:
80:• if (propertyAtt.isKnownOwlProperty()) {
81: createAttribute(field, inference, propertyAtt);
82:• } else if (!isAspectIntegrationField(field)) {
83: final boolean success = processIdentifierField(field);
84:• if (!success) {
85: throw new MetamodelInitializationException(
86: "Unable to process field " + field + ". It is not transient but has no mapping information.");
87: }
88: }
89: }
90:
91: private static Class<?> getFieldValueType(Field field) {
92:• if (Collection.class.isAssignableFrom(field.getType())) {
93: return getSetOrListErasureType((ParameterizedType) field.getGenericType());
94:• } else if (field.getType().isArray()) {
95: throw new MetamodelInitializationException("Array persistent attributes are not supported.");
96: } else {
97: return field.getType();
98: }
99: }
100:
101: private static Class<?> getSetOrListErasureType(final ParameterizedType cls) {
102: final Type[] t = cls.getActualTypeArguments();
103:
104:• if (t.length != 1) {
105: throw new OWLPersistenceException("Only collections with a single generic parameter are supported.");
106: }
107: Type type = t[0];
108:• if (!(type instanceof Class<?>)) {
109: throw new OWLPersistenceException("Only Classes are valid parameters for generic lists and sets.");
110: }
111: return (Class<?>) type;
112: }
113:
114: private InferenceInfo processInferenceInfo(Field field) {
115: final Inferred inferred = field.getAnnotation(Inferred.class);
116:
117: final InferenceInfo inference = new InferenceInfo(inferred);
118:• if (inference.inferred) {
119: metamodelBuilder.addInferredClass(cls);
120: }
121: return inference;
122: }
123:
124: private static boolean isTypesField(Field field) {
125:• return field.getAnnotation(Types.class) != null;
126: }
127:
128: private void processTypesField(Field field, Class<?> fieldValueCls, InferenceInfo inference) {
129: Types tt = field.getAnnotation(Types.class);
130: mappingValidator.validateTypesField(field);
131: et.addDirectTypes(new TypesSpecificationImpl<>(et, tt.fetchType(), field, fieldValueCls, inference.inferred));
132: }
133:
134: private static boolean isPropertiesField(Field field) {
135:• return field.getAnnotation(Properties.class) != null;
136: }
137:
138: private void processPropertiesField(Field field, Class<?> fieldValueCls, InferenceInfo inference) {
139: Properties properties = field.getAnnotation(Properties.class);
140: mappingValidator.validatePropertiesField(field);
141: final PropertiesParametersResolver paramsResolver = new PropertiesParametersResolver(field);
142: et.addOtherProperties(
143: PropertiesSpecificationImpl.declaringType(et).fetchType(properties.fetchType()).javaField(field)
144: .javaType(fieldValueCls).inferred(inference.inferred)
145: .propertyIdType(paramsResolver.getPropertyIdentifierType())
146: .propertyValueType(paramsResolver.getPropertyValueType()).build());
147: }
148:
149: private void createAttribute(Field field, InferenceInfo inference, PropertyAttributes propertyAttributes) {
150: final AbstractAttribute<X, ?> a;
151:• if (field.getType().isAssignableFrom(List.class)) {
152: final Sequence os = field.getAnnotation(Sequence.class);
153:
154:• if (os == null) {
155: throw new MetamodelInitializationException("Expected Sequence annotation.");
156: }
157: final ListAttributeImpl.ListAttributeBuilder builder =
158: ListAttributeImpl.builder(propertyAttributes).declaringType(et)
159: .field(field)
160: .inferred(inference.inferred).includeExplicit(inference.includeExplicit)
161: .owlListClass(IRI.create(os.ClassOWLListIRI()))
162: .hasNextProperty(IRI.create(os.ObjectPropertyHasNextIRI()))
163: .hasContentsProperty(IRI.create(os.ObjectPropertyHasContentsIRI()))
164: .sequenceType(os.type());
165: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
166: a = builder.build();
167:• } else if (field.getType().isAssignableFrom(Set.class)) {
168: final AbstractPluralAttribute.PluralAttributeBuilder builder =
169: SetAttributeImpl.builder(propertyAttributes).declaringType(et)
170: .field(field)
171: .inferred(inference.inferred).includeExplicit(inference.includeExplicit);
172: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
173: a = (AbstractAttribute<X, ?>) builder.build();
174:• } else if (field.getType().isAssignableFrom(Map.class)) {
175: throw new IllegalArgumentException("NOT YET SUPPORTED");
176: } else {
177: final SingularAttributeImpl.SingularAttributeBuilder builder =
178: SingularAttributeImpl.builder(propertyAttributes).declaringType(et)
179: .field(field)
180: .inferred(inference.inferred).includeExplicit(inference.includeExplicit);
181: context.getConverterResolver().resolveConverter(field, propertyAttributes).ifPresent(builder::converter);
182: a = (AbstractAttribute<X, ?>) builder.build();
183: }
184: et.addDeclaredAttribute(field.getName(), a);
185: }
186:
187: private boolean processIdentifierField(Field field) {
188: final Id id = field.getAnnotation(Id.class);
189:• if (id == null) {
190: return false;
191: }
192: mappingValidator.validateIdentifierType(field.getType());
193: et.setIdentifier(new IRIIdentifierImpl<>(et, field, id.generated()));
194: return true;
195: }
196:
197: private static boolean isAspectIntegrationField(Field field) {
198: // AspectJ integration fields cannot be declared transitive (they're generated by the AJC), so we have to
199: // skip them manually
200: return field.getType().equals(BeanListenerAspect.Manageable.class);
201: }
202:
203: private static class InferenceInfo {
204: private final boolean inferred;
205: private final boolean includeExplicit;
206:
207: InferenceInfo(Inferred inferredAnnotation) {
208: this.inferred = inferredAnnotation != null;
209: this.includeExplicit = inferredAnnotation == null || inferredAnnotation.includeExplicit();
210: }
211: }
212: }