Skip to content

Package: ClassFieldMetamodelProcessor$InferenceInfo

ClassFieldMetamodelProcessor$InferenceInfo

nameinstructionbranchcomplexitylinemethod
ClassFieldMetamodelProcessor.InferenceInfo(Inferred)
M: 1 C: 19
95%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 4
100%
M: 0 C: 1
100%

Coverage

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.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.IRI;
20: import cz.cvut.kbss.jopa.model.annotations.*;
21: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
22: import org.slf4j.Logger;
23: import org.slf4j.LoggerFactory;
24:
25: import java.lang.reflect.Field;
26: import java.lang.reflect.ParameterizedType;
27: import java.lang.reflect.Type;
28: import java.util.Collection;
29: import java.util.List;
30: import java.util.Map;
31: import java.util.Set;
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: final PropertyAttributes propertyAtt = PropertyAttributes.create(field, mappingValidator, context);
79: propertyAtt.resolve(field, metamodelBuilder, fieldValueCls);
80:
81: if (propertyAtt.isKnownOwlProperty()) {
82: createAttribute(field, inference, propertyAtt);
83: } else {
84: final boolean success = processIdentifierField(field);
85: if (!success) {
86: throw new MetamodelInitializationException(
87: "Unable to process field " + field + ". It is not transient but has no mapping information.");
88: }
89: }
90: }
91:
92: private Class<?> getFieldValueType(Field field) {
93: if (Collection.class.isAssignableFrom(field.getType())) {
94: return getSetOrListErasureType((ParameterizedType) field.getGenericType());
95: } else if (field.getType().isArray()) {
96: throw new MetamodelInitializationException("Array persistent attributes are not supported.");
97: } else {
98: return field.getType();
99: }
100: }
101:
102: private static Class<?> getSetOrListErasureType(final ParameterizedType cls) {
103: final Type[] t = cls.getActualTypeArguments();
104:
105: if (t.length != 1) {
106: throw new OWLPersistenceException("Only collections with a single generic parameter are supported.");
107: }
108: Type type = t[0];
109: if (!(type instanceof Class<?>)) {
110: throw new OWLPersistenceException("Only Classes are valid parameters for generic lists and sets.");
111: }
112: return (Class<?>) type;
113: }
114:
115: private InferenceInfo processInferenceInfo(Field field) {
116: final Inferred inferred = field.getAnnotation(Inferred.class);
117:
118: final InferenceInfo inference = new InferenceInfo(inferred);
119: if (inference.inferred) {
120: metamodelBuilder.addInferredClass(cls);
121: }
122: return inference;
123: }
124:
125: private boolean isTypesField(Field field) {
126: return field.getAnnotation(Types.class) != null;
127: }
128:
129: private void processTypesField(Field field, Class<?> fieldValueCls, InferenceInfo inference) {
130: Types tt = field.getAnnotation(Types.class);
131: mappingValidator.validateTypesField(field);
132: et.addDirectTypes(new TypesSpecificationImpl<>(et, tt.fetchType(), field, fieldValueCls, inference.inferred));
133: }
134:
135: private boolean isPropertiesField(Field field) {
136: return field.getAnnotation(Properties.class) != null;
137: }
138:
139: private void processPropertiesField(Field field, Class<?> fieldValueCls, InferenceInfo inference) {
140: Properties properties = field.getAnnotation(Properties.class);
141: mappingValidator.validatePropertiesField(field);
142: final PropertiesParametersResolver paramsResolver = new PropertiesParametersResolver(field);
143: et.addOtherProperties(
144: PropertiesSpecificationImpl.declaringType(et).fetchType(properties.fetchType()).javaField(field)
145: .javaType(fieldValueCls).inferred(inference.inferred)
146: .propertyIdType(paramsResolver.getPropertyIdentifierType())
147: .propertyValueType(paramsResolver.getPropertyValueType()).build());
148: }
149:
150: private void createAttribute(Field field, InferenceInfo inference, PropertyAttributes propertyAttributes) {
151: final Attribute<X, ?> a;
152: if (field.getType().isAssignableFrom(List.class)) {
153: final Sequence os = field.getAnnotation(Sequence.class);
154:
155: if (os == null) {
156: throw new MetamodelInitializationException("Expected Sequence annotation.");
157: }
158: a = ListAttributeImpl.iri(propertyAttributes.getIri()).declaringType(et).field(field)
159: .elementType(propertyAttributes.getType())
160: .attributeType(propertyAttributes.getPersistentAttributeType())
161: .cascadeTypes(propertyAttributes.getCascadeTypes())
162: .fetchType(propertyAttributes.getFetchType()).inferred(inference.inferred)
163: .includeExplicit(inference.includeExplicit)
164: .owlListClass(IRI.create(os.ClassOWLListIRI()))
165: .hasNextProperty(IRI.create(os.ObjectPropertyHasNextIRI()))
166: .hasContentsProperty(IRI.create(os.ObjectPropertyHasContentsIRI()))
167: .sequenceType(os.type())
168: .participationConstraints(propertyAttributes.getParticipationConstraints())
169: .nonEmpty(propertyAttributes.isNonEmpty()).build();
170: } else if (field.getType().isAssignableFrom(Set.class)) {
171: a = SetAttributeImpl.iri(propertyAttributes.getIri()).declaringType(et).field(field)
172: .elementType(propertyAttributes.getType())
173: .attributeType(propertyAttributes.getPersistentAttributeType())
174: .fetchType(propertyAttributes.getFetchType())
175: .cascadeTypes(propertyAttributes.getCascadeTypes()).inferred(inference.inferred)
176: .includeExplicit(inference.includeExplicit)
177: .participationConstraints(propertyAttributes.getParticipationConstraints())
178: .nonEmpty(propertyAttributes.isNonEmpty()).build();
179: } else if (field.getType().isAssignableFrom(Map.class)) {
180: throw new IllegalArgumentException("NOT YET SUPPORTED");
181: } else {
182: a = SingularAttributeImpl.iri(propertyAttributes.getIri()).name(field.getName()).identifier(false)
183: .declaringType(et).type(propertyAttributes.getType()).field(field)
184: .cascadeTypes(propertyAttributes.getCascadeTypes())
185: .attributeType(propertyAttributes.getPersistentAttributeType())
186: .fetchType(propertyAttributes.getFetchType()).inferred(inference.inferred)
187: .includeExplicit(inference.includeExplicit)
188: .constraints(propertyAttributes.getParticipationConstraints())
189: .nonEmpty(propertyAttributes.isNonEmpty()).build();
190: }
191: et.addDeclaredAttribute(field.getName(), a);
192: }
193:
194: private boolean processIdentifierField(Field field) {
195: final Id id = field.getAnnotation(Id.class);
196: if (id == null) {
197: return false;
198: }
199: mappingValidator.validateIdentifierType(field.getType());
200: et.setIdentifier(new IRIIdentifierImpl(field, id.generated()));
201: return true;
202: }
203:
204: private static class InferenceInfo {
205: private final boolean inferred;
206: private final boolean includeExplicit;
207:
208: InferenceInfo(Inferred inferredAnnotation) {
209:• this.inferred = inferredAnnotation != null;
210:• this.includeExplicit = inferredAnnotation == null || inferredAnnotation.includeExplicit();
211: }
212: }
213: }