Skip to content

Method: getCurrentContextType()

1: /**
2: * Copyright (C) 2017 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.jsonld.deserialization;
16:
17: import cz.cvut.kbss.jsonld.JsonLd;
18: import cz.cvut.kbss.jsonld.common.BeanAnnotationProcessor;
19: import cz.cvut.kbss.jsonld.common.BeanClassProcessor;
20: import cz.cvut.kbss.jsonld.common.CollectionType;
21: import cz.cvut.kbss.jsonld.exception.JsonLdDeserializationException;
22:
23: import java.lang.reflect.Field;
24: import java.util.*;
25:
26: /**
27: * Default implementation of the JSON-LD deserializer, which takes values parsed from a JSON-LD document and builds Java
28: * instances from them.
29: */
30: public class DefaultInstanceBuilder implements InstanceBuilder {
31:
32: // Identifiers to instances
33: private final Map<String, Object> knownInstances = new HashMap<>();
34: private final Stack<InstanceContext> openInstances = new Stack<>();
35:
36: private InstanceContext currentInstance;
37:
38: // TODO Add support for polymorphism
39: @Override
40: public void openObject(String property) {
41: Objects.requireNonNull(property);
42: final Field targetField = currentInstance.getFieldForProperty(property);
43: assert targetField != null;
44: final Class<?> type = targetField.getType();
45: final InstanceContext<?> ctx;
46: if (BeanClassProcessor.isIdentifierType(type)) { // This will be useful for Enhancement #5
47: ctx = new NodeReferenceContext<>(currentInstance, targetField, knownInstances);
48: } else {
49: assert BeanAnnotationProcessor.isOwlClassEntity(type);
50: final Object instance = BeanClassProcessor.createInstance(type);
51: ctx = new SingularObjectContext<>(instance,
52: BeanAnnotationProcessor.mapSerializableFields(type), knownInstances);
53: currentInstance.setFieldValue(targetField, instance);
54: }
55: openInstances.push(currentInstance);
56: this.currentInstance = ctx;
57: }
58:
59: @Override
60: public <T> void openObject(Class<T> cls) {
61: if (BeanClassProcessor.isIdentifierType(cls)) { // This will be useful for Enhancement #5
62: final InstanceContext<T> context = new NodeReferenceContext<>(currentInstance, knownInstances);
63: assert currentInstance != null;
64: openInstances.push(currentInstance);
65: this.currentInstance = context;
66: } else {
67: final T instance = BeanClassProcessor.createInstance(cls);
68: final InstanceContext<T> context = new SingularObjectContext<>(instance,
69: BeanAnnotationProcessor.mapSerializableFields(cls), knownInstances);
70: replaceCurrentContext(instance, context);
71: }
72: }
73:
74: private <T> void replaceCurrentContext(T instance, InstanceContext<?> ctx) {
75: if (currentInstance != null) {
76: currentInstance.addItem(instance);
77: openInstances.push(currentInstance);
78: }
79: this.currentInstance = ctx;
80: }
81:
82: @Override
83: public void closeObject() {
84: currentInstance.close();
85: if (!openInstances.isEmpty()) {
86: this.currentInstance = openInstances.pop();
87: }
88: }
89:
90: @Override
91: public void openCollection(String property) {
92: Objects.requireNonNull(property);
93: final Field targetField = currentInstance.getFieldForProperty(property);
94: final InstanceContext<?> ctx;
95: if (targetField == null) {
96: if (BeanAnnotationProcessor.hasPropertiesField(currentInstance.getInstanceType()) &&
97: !JsonLd.TYPE.equals(property)) {
98: ctx = buildPropertiesContext(property);
99: } else {
100: ctx = new DummyCollectionInstanceContext(knownInstances);
101: }
102: } else {
103: verifyPluralAttribute(property, targetField);
104: final Collection<?> instance = BeanClassProcessor.createCollection(targetField);
105: if (JsonLd.TYPE.equals(property)) {
106: ctx = new TypesContext(instance, knownInstances,
107: BeanClassProcessor.getCollectionItemType(targetField), currentInstance.getInstanceType());
108: } else {
109: ctx = new CollectionInstanceContext<>(instance, BeanClassProcessor.getCollectionItemType(targetField),
110: knownInstances);
111: }
112: currentInstance.setFieldValue(targetField, instance);
113: }
114: openInstances.push(currentInstance);
115: this.currentInstance = ctx;
116: }
117:
118: private InstanceContext<?> buildPropertiesContext(String property) {
119: final Field propsField = BeanAnnotationProcessor.getPropertiesField(currentInstance.getInstanceType());
120: BeanClassProcessor.verifyPropertiesFieldType(propsField);
121: Map<?, ?> propertiesMap =
122: (Map<?, ?>) BeanClassProcessor.getFieldValue(propsField, currentInstance.getInstance());
123: if (propertiesMap == null) {
124: propertiesMap = new HashMap<>();
125: currentInstance.setFieldValue(propsField, propertiesMap);
126: }
127: return new PropertiesInstanceContext(propertiesMap, property, propsField);
128: }
129:
130: private void verifyPluralAttribute(String property, Field field) {
131: if (!isPlural(property)) {
132: throw JsonLdDeserializationException.singularAttributeCardinalityViolated(property, field);
133: }
134: }
135:
136: @Override
137: public void openCollection(CollectionType collectionType) {
138: final Collection<?> collection = BeanClassProcessor.createCollection(collectionType);
139: final InstanceContext<?> context = new CollectionInstanceContext<>(collection, knownInstances);
140: replaceCurrentContext(collection, context);
141: }
142:
143: @Override
144: public void closeCollection() {
145: if (!openInstances.isEmpty()) {
146: currentInstance = openInstances.pop();
147: }
148: }
149:
150: @Override
151: public void addValue(String property, Object value) {
152: assert currentInstance != null;
153: if (JsonLd.ID.equals(property)) {
154: currentInstance.setIdentifierValue(value);
155: return;
156: }
157: final Field targetField = currentInstance.getFieldForProperty(property);
158: assert targetField != null;
159: // This is in case there is only one value in the JSON-LD array, because then it might be treated as single valued attribute
160: if (BeanClassProcessor.isCollection(targetField)) {
161: openCollection(property);
162: addValue(value);
163: closeCollection();
164: } else {
165: currentInstance.setFieldValue(targetField, value);
166: }
167: }
168:
169: @Override
170: public void addValue(Object value) {
171: assert currentInstance != null;
172: currentInstance.addItem(value);
173: }
174:
175: @Override
176: public void addNodeReference(String property, String nodeId) {
177: final Field field = currentInstance.getFieldForProperty(property);
178: assert field != null;
179: final Class<?> type = field.getType();
180: if (BeanClassProcessor.isIdentifierType(type)) {
181: currentInstance.setFieldValue(field, nodeId);
182: } else {
183: currentInstance.setFieldValue(field, getKnownInstance(nodeId));
184: }
185: }
186:
187: private Object getKnownInstance(String nodeId) {
188: if (!knownInstances.containsKey(nodeId)) {
189: throw new JsonLdDeserializationException(
190: "Node with IRI " + nodeId + " cannot be referenced, because it has not been encountered yet.");
191: }
192: return knownInstances.get(nodeId);
193: }
194:
195: @Override
196: public void addNodeReference(String nodeId) {
197: final Class<?> targetType = getCurrentCollectionElementType();
198: if (BeanClassProcessor.isIdentifierType(targetType)) {
199: currentInstance.addItem(nodeId);
200: } else {
201: currentInstance.addItem(getKnownInstance(nodeId));
202: }
203: }
204:
205: @Override
206: public Object getCurrentRoot() {
207: return currentInstance != null ? currentInstance.getInstance() : null;
208: }
209:
210: @Override
211: public Class<?> getCurrentCollectionElementType() {
212: try {
213: return currentInstance.getItemType();
214: } catch (UnsupportedOperationException e) {
215: throw new JsonLdDeserializationException("The current instance is not a collection.", e);
216: }
217: }
218:
219: @Override
220: public boolean isPlural(String property) {
221: assert isPropertyMapped(property);
222: final Field mappedField = currentInstance.getFieldForProperty(property);
223: return mappedField == null || BeanClassProcessor.isCollection(mappedField);
224: }
225:
226: @Override
227: public boolean isPropertyMapped(String property) {
228: return currentInstance.isPropertyMapped(property) || JsonLd.TYPE.equals(property);
229: }
230:
231: @Override
232: public Class<?> getCurrentContextType() {
233: return currentInstance.getInstanceType();
234: }
235: }