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