Skip to contentMethod: supports(String)
1: /*
2: * JB4JSON-LD
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jsonld.deserialization;
19:
20: import cz.cvut.kbss.jsonld.JsonLd;
21: import cz.cvut.kbss.jsonld.common.BeanAnnotationProcessor;
22: import cz.cvut.kbss.jsonld.deserialization.util.DataTypeTransformer;
23: import cz.cvut.kbss.jsonld.exception.UnknownPropertyException;
24:
25: import java.lang.reflect.Field;
26: import java.util.Map;
27:
28: abstract class InstanceContext<T> {
29:
30: /**
31: * Blank node id start, as per <a href="https://www.w3.org/TR/turtle/#BNodes">https://www.w3.org/TR/turtle/#BNodes</a>
32: */
33: private static final String BLANK_NODE_ID_START = "_:";
34:
35: T instance;
36:
37: private String identifier;
38:
39: final Map<String, Object> knownInstances;
40:
41: InstanceContext(T instance, Map<String, Object> knownInstances) {
42: this.instance = instance;
43: this.knownInstances = knownInstances;
44: }
45:
46: T getInstance() {
47: return instance;
48: }
49:
50: @SuppressWarnings("unchecked")
51: Class<T> getInstanceType() {
52: return (Class<T>) instance.getClass();
53: }
54:
55: /**
56: * Sets identifier of the instance specified by this context.
57: *
58: * @param value Identifier value
59: */
60: void setIdentifierValue(String value) {
61: final Field idField = getFieldForProperty(JsonLd.ID);
62: final boolean blankNode = isBlankNodeIdentifier(value);
63: if (idField == null) {
64: if (blankNode) {
65: return;
66: } else {
67: throw UnknownPropertyException.create(JsonLd.ID, getInstanceType());
68: }
69: }
70: if (blankNode && !idField.getType().equals(String.class)) {
71: return;
72: }
73: setFieldValue(idField, value);
74: this.identifier = value;
75: knownInstances.put(value, instance);
76: }
77:
78: private static boolean isBlankNodeIdentifier(String identifier) {
79: return identifier.startsWith(BLANK_NODE_ID_START);
80: }
81:
82: /**
83: * Gets the instance identifier.
84: * <p>
85: * Note that the identifier may not be available.
86: *
87: * @return Identifier value, or {@code null} if it is not available (it has not been set or is not applicable in
88: * this context)
89: * @see #setIdentifierValue(String)
90: */
91: String getIdentifier() {
92: return identifier;
93: }
94:
95: // These methods are intended for overriding, because the behaviour is supported only by some context implementations
96:
97: /**
98: * Gets a Java field mapped by the specified property.
99: * <p>
100: * This applies to singular object contexts only.
101: *
102: * @param property Property IRI
103: * @return Field mapped by the specified property. Can be {@code null}
104: */
105: Field getFieldForProperty(String property) {
106: throw new UnsupportedOperationException("Not supported by this type of instance context.");
107: }
108:
109: /**
110: * Sets value of the specified field on the instance represented by this context
111: *
112: * @param field The field to set
113: * @param value The value to set
114: */
115: void setFieldValue(Field field, Object value) {
116: // Do nothing
117: }
118:
119: /**
120: * Adds item to the collection represented by this context.
121: *
122: * @param item Item to add
123: */
124: void addItem(Object item) {
125: // Do nothing
126: }
127:
128: /**
129: * Gets type of the element of a collection represented by this context.
130: *
131: * @return Collection element type
132: */
133: Class<?> getItemType() {
134: throw new UnsupportedOperationException("Not supported by this type of instance context.");
135: }
136:
137: Object resolveAssignableValue(Class<?> targetType, Object value) {
138: if (value != null && !targetType.isAssignableFrom(value.getClass())) {
139: if (knownInstances.containsKey(value.toString())) {
140: final Object known = knownInstances.get(value.toString());
141: if (!targetType.isAssignableFrom(known.getClass())) {
142: return DataTypeTransformer.transformValue(value, targetType);
143: } else {
144: return known;
145: }
146: } else {
147: return DataTypeTransformer.transformValue(value, targetType);
148: }
149: }
150: return value;
151: }
152:
153: /**
154: * Whether the specified property is mapped by a field in this context.
155: * <p>
156: * Note that if the context represents an instance with a {@link cz.cvut.kbss.jopa.model.annotations.Properties}
157: * field, every property is considered mapped
158: *
159: * @param property The property to check
160: * @return {@code true} if a field mapping the property exists in this context, {@code false} otherwise
161: */
162: boolean isPropertyMapped(String property) {
163: // Default behavior
164: return false;
165: }
166:
167: /**
168: * Checks whether the specified property is supported by this context.
169: * <p>
170: * A property is supported by a context for deserialization if it is mapped and the mapped field does not have
171: * read-only access.
172: *
173: * @param property The property to check
174: * @return Whether property is supported by this context
175: * @see #isPropertyMapped(String)
176: * @see cz.cvut.kbss.jsonld.annotation.JsonLdProperty.Access#READ_ONLY
177: */
178: boolean supports(String property) {
179: // Default behavior
180: return false;
181: }
182:
183: /**
184: * Checks whether the class represented by this context contains a {@link cz.cvut.kbss.jopa.model.annotations.Properties}
185: * field.
186: *
187: * @return Whether the represented class has properties field
188: */
189: boolean hasPropertiesField() {
190: return BeanAnnotationProcessor.hasPropertiesField(getInstanceType());
191: }
192:
193: /**
194: * Called when this context is being closed
195: */
196: void close() {
197: // Do nothing by default
198: }
199: }