Skip to content

Commit a56ca88

Browse files
committed
[Enhancement #66] Implement serialization of numeric values with datatype for ContextBuildingJsonLdSerializer.
1 parent 3410516 commit a56ca88

12 files changed

+142
-29
lines changed

src/main/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializer.java

+17-11
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,22 @@
3333
import cz.cvut.kbss.jsonld.serialization.serializer.ObjectGraphValueSerializers;
3434
import cz.cvut.kbss.jsonld.serialization.serializer.ValueSerializer;
3535
import cz.cvut.kbss.jsonld.serialization.serializer.ValueSerializers;
36-
import cz.cvut.kbss.jsonld.serialization.serializer.context.*;
36+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingDefaultValueSerializer;
37+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingIdentifierSerializer;
38+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingIndividualSerializer;
39+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingMultilingualStringSerializer;
40+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingNumberSerializer;
41+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingObjectPropertyValueSerializer;
42+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingPluralMultilingualStringSerializer;
43+
import cz.cvut.kbss.jsonld.serialization.serializer.context.ContextBuildingTypesSerializer;
3744
import cz.cvut.kbss.jsonld.serialization.serializer.context.datetime.ContextBuildingTemporalAmountSerializer;
3845
import cz.cvut.kbss.jsonld.serialization.serializer.context.datetime.ContextBuildingTemporalSerializer;
3946
import cz.cvut.kbss.jsonld.serialization.serializer.datetime.DateSerializer;
4047
import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser;
4148
import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContextFactory;
4249

43-
import java.time.*;
50+
import java.time.Duration;
51+
import java.time.Period;
4452
import java.util.Collection;
4553
import java.util.Date;
4654
import java.util.Optional;
@@ -69,19 +77,16 @@ protected ValueSerializers initSerializers() {
6977
valueSerializers.registerTypesSerializer(new ContextBuildingTypesSerializer());
7078
valueSerializers.registerIndividualSerializer(new ContextBuildingIndividualSerializer());
7179
final ContextBuildingTemporalSerializer ts = new ContextBuildingTemporalSerializer();
72-
valueSerializers.registerSerializer(LocalDate.class, ts);
7380
// Register the same temporal serializer for each of the types it supports (needed for key-based map access)
74-
valueSerializers.registerSerializer(LocalDate.class, ts);
75-
valueSerializers.registerSerializer(LocalTime.class, ts);
76-
valueSerializers.registerSerializer(OffsetTime.class, ts);
77-
valueSerializers.registerSerializer(LocalDateTime.class, ts);
78-
valueSerializers.registerSerializer(OffsetDateTime.class, ts);
79-
valueSerializers.registerSerializer(ZonedDateTime.class, ts);
80-
valueSerializers.registerSerializer(Instant.class, ts);
81+
ContextBuildingTemporalSerializer.getSupportedTypes()
82+
.forEach(cls -> valueSerializers.registerSerializer(cls, ts));
8183
valueSerializers.registerSerializer(Date.class, new DateSerializer(ts));
8284
final ContextBuildingTemporalAmountSerializer tas = new ContextBuildingTemporalAmountSerializer();
8385
valueSerializers.registerSerializer(Duration.class, tas);
8486
valueSerializers.registerSerializer(Period.class, tas);
87+
final ContextBuildingNumberSerializer ns = new ContextBuildingNumberSerializer();
88+
ContextBuildingNumberSerializer.getSupportedTypes()
89+
.forEach(cls -> valueSerializers.registerSerializer(cls, ns));
8590
return valueSerializers;
8691
}
8792

@@ -114,7 +119,8 @@ private void ensureContextNodeNotPresent(CompositeNode<?> root, JsonNode rootCtx
114119

115120
private JsonLdTreeBuilder initTreeBuilder(ObjectGraphTraverser traverser,
116121
JsonLdContextFactory jsonLdContextFactory) {
117-
final ContextBuildingObjectPropertyValueSerializer opSerializer = new ContextBuildingObjectPropertyValueSerializer(traverser);
122+
final ContextBuildingObjectPropertyValueSerializer opSerializer =
123+
new ContextBuildingObjectPropertyValueSerializer(traverser);
118124
opSerializer.configure(configuration());
119125
return new JsonLdTreeBuilder(new ObjectGraphValueSerializers(serializers, opSerializer), jsonLdContextFactory);
120126
}

src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/compact/NumberSerializer.java

+11-7
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,24 @@ public class NumberSerializer implements ValueSerializer<Number> {
1919
@Override
2020
public JsonNode serialize(Number value, SerializationContext<Number> ctx) {
2121
Objects.requireNonNull(value);
22+
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, getDatatype(value));
23+
}
24+
25+
protected String getDatatype(Number value) {
2226
if (value instanceof Integer) {
23-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.INT);
27+
return XSD.INT;
2428
} else if (value instanceof Long) {
25-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.LONG);
29+
return XSD.LONG;
2630
} else if (value instanceof Double) {
27-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.DOUBLE);
31+
return XSD.DOUBLE;
2832
} else if (value instanceof Float) {
29-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.FLOAT);
33+
return XSD.FLOAT;
3034
} else if (value instanceof Short) {
31-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.SHORT);
35+
return XSD.SHORT;
3236
} else if (value instanceof BigInteger) {
33-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.INTEGER);
37+
return XSD.INTEGER;
3438
} else if (value instanceof BigDecimal) {
35-
return SerializerUtils.createdTypedValueNode(ctx.getTerm(), value, XSD.DECIMAL);
39+
return XSD.DECIMAL;
3640
} else {
3741
throw new IllegalArgumentException("Unsupported numeric literal type " + value.getClass());
3842
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package cz.cvut.kbss.jsonld.serialization.serializer.context;
2+
3+
import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory;
4+
import cz.cvut.kbss.jsonld.serialization.model.JsonNode;
5+
import cz.cvut.kbss.jsonld.serialization.model.ObjectNode;
6+
import cz.cvut.kbss.jsonld.serialization.serializer.SerializerUtils;
7+
import cz.cvut.kbss.jsonld.serialization.serializer.compact.NumberSerializer;
8+
import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext;
9+
10+
/**
11+
* Serializes numeric values and builds a corresponding context item for them.
12+
*/
13+
public class ContextBuildingNumberSerializer extends NumberSerializer {
14+
15+
@Override
16+
public JsonNode serialize(Number value, SerializationContext<Number> ctx) {
17+
if (ctx.getTerm() != null && ctx.getFieldName() != null) {
18+
final ObjectNode termDef =
19+
SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(), getDatatype(value));
20+
ctx.registerTermMapping(ctx.getFieldName(), termDef);
21+
}
22+
return JsonNodeFactory.createLiteralNode(ctx.getTerm(), value);
23+
}
24+
}

src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/datetime/ContextBuildingEpochBasedDateTimeSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class ContextBuildingEpochBasedDateTimeSerializer extends EpochBasedDateT
2828

2929
@Override
3030
public JsonNode serialize(OffsetDateTime value, SerializationContext<TemporalAccessor> ctx) {
31-
if (ctx.getTerm() != null) {
31+
if (ctx.getTerm() != null && ctx.getFieldName() != null) {
3232
ctx.registerTermMapping(ctx.getFieldName(), ctx.getTerm());
3333
}
3434
return super.serialize(value, ctx);

src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/datetime/ContextBuildingIsoDateTimeSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class ContextBuildingIsoDateTimeSerializer extends IsoDateTimeSerializer
3232

3333
@Override
3434
public JsonNode serialize(OffsetDateTime value, SerializationContext<TemporalAccessor> ctx) {
35-
if (ctx.getTerm() != null) {
35+
if (ctx.getTerm() != null && ctx.getFieldName() != null) {
3636
final ObjectNode termDef =
3737
SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(), XSD.DATETIME);
3838
ctx.registerTermMapping(ctx.getFieldName(), termDef);

src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/datetime/ContextBuildingLocalDateSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class ContextBuildingLocalDateSerializer extends LocalDateSerializer {
3232

3333
@Override
3434
public JsonNode serialize(LocalDate value, SerializationContext<TemporalAccessor> ctx) {
35-
if (ctx.getTerm() != null) {
35+
if (ctx.getTerm() != null && ctx.getFieldName() != null) {
3636
final ObjectNode termDef =
3737
SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(), XSD.DATE);
3838
ctx.registerTermMapping(ctx.getFieldName(), termDef);

src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/datetime/ContextBuildingTemporalAmountSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class ContextBuildingTemporalAmountSerializer implements ValueSerializer<
3131

3232
@Override
3333
public JsonNode serialize(TemporalAmount value, SerializationContext<TemporalAmount> ctx) {
34-
if (ctx.getTerm() != null) {
34+
if (ctx.getTerm() != null && ctx.getFieldName() != null) {
3535
final ObjectNode termDef = SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(),
3636
XSD.DURATION);
3737
ctx.registerTermMapping(ctx.getFieldName(), termDef);

src/main/java/cz/cvut/kbss/jsonld/serialization/serializer/context/datetime/ContextBuildingTimeSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class ContextBuildingTimeSerializer extends cz.cvut.kbss.jsonld.serializa
3131

3232
@Override
3333
public JsonNode serialize(OffsetTime value, SerializationContext<TemporalAccessor> ctx) {
34-
if (ctx.getTerm() != null) {
34+
if (ctx.getTerm() != null && ctx.getFieldName() != null) {
3535
final ObjectNode termDef =
3636
SerializerUtils.createTypedTermDefinition(ctx.getFieldName(), ctx.getTerm(), XSD.TIME);
3737
ctx.registerTermMapping(ctx.getFieldName(), termDef);

src/test/java/cz/cvut/kbss/jsonld/environment/model/GenericMember.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ public void toRdf(Model model, ValueFactory vf, Set<URI> visited) {
6262
visited.add(uri);
6363
final IRI id = vf.createIRI(uri.toString());
6464
model.add(id, RDF.TYPE, vf.createIRI(Vocabulary.GENERIC_MEMBER));
65-
if (memberOf != null && memberOf instanceof GeneratesRdf) {
66-
final GeneratesRdf org = (GeneratesRdf) memberOf;
65+
if (memberOf != null && memberOf instanceof GeneratesRdf org) {
6766
model.add(id, vf.createIRI(Vocabulary.IS_MEMBER_OF), vf.createIRI(org.getUri().toString()));
6867
org.toRdf(model, vf, visited);
6968
}

src/test/java/cz/cvut/kbss/jsonld/serialization/ContextBuildingJsonLdSerializerTest.java

+18
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,22 @@ void serializationAddsToContextMappingForCollectionValuedAnnotationPropertyAttri
409409
final JsonObject context = json.getJsonObject(JsonLd.CONTEXT);
410410
assertThat(context, hasKey("origins"));
411411
}
412+
413+
@Test
414+
@Override
415+
void serializationIncludesDatatypeOfNumericLiterals() {
416+
final Product p = new Product();
417+
p.price = 155.15;
418+
p.name = "Test product";
419+
p.uri = Generator.generateUri();
420+
421+
final JsonObject json = serializeAndRead(p).asJsonObject();
422+
assertThat(json, hasKey(JsonLd.CONTEXT));
423+
assertEquals(JsonValue.ValueType.OBJECT, json.get(JsonLd.CONTEXT).getValueType());
424+
final JsonObject context = json.getJsonObject(JsonLd.CONTEXT);
425+
assertThat(context, hasKey("price"));
426+
final JsonObject keyCtx = context.getJsonObject("price");
427+
assertEquals(XSD.DOUBLE, keyCtx.getString(JsonLd.TYPE));
428+
assertEquals("https://schema.org/price", keyCtx.getString(JsonLd.ID));
429+
}
412430
}

src/test/java/cz/cvut/kbss/jsonld/serialization/JsonLdSerializerTestBase.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -497,15 +497,15 @@ void serializationIncludesDatatypeOfNumericLiterals() throws Exception {
497497
}
498498

499499
@OWLClass(iri = Vocabulary.DEFAULT_PREFIX + "Product")
500-
private static class Product implements GeneratesRdf {
500+
static class Product implements GeneratesRdf {
501501
@Id
502-
private URI uri;
502+
URI uri;
503503

504504
@OWLAnnotationProperty(iri = DC.Terms.TITLE)
505-
private String name;
505+
String name;
506506

507507
@OWLDataProperty(iri = "https://schema.org/price")
508-
private Double price;
508+
Double price;
509509

510510
@Override
511511
public URI getUri() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package cz.cvut.kbss.jsonld.serialization.serializer.context;
2+
3+
import cz.cvut.kbss.jopa.vocabulary.XSD;
4+
import cz.cvut.kbss.jsonld.JsonLd;
5+
import cz.cvut.kbss.jsonld.serialization.JsonNodeFactory;
6+
import cz.cvut.kbss.jsonld.serialization.context.JsonLdContext;
7+
import cz.cvut.kbss.jsonld.serialization.context.MappingJsonLdContext;
8+
import cz.cvut.kbss.jsonld.serialization.model.JsonNode;
9+
import cz.cvut.kbss.jsonld.serialization.model.ObjectNode;
10+
import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContext;
11+
import org.junit.jupiter.params.ParameterizedTest;
12+
import org.junit.jupiter.params.provider.Arguments;
13+
import org.junit.jupiter.params.provider.MethodSource;
14+
15+
import java.math.BigDecimal;
16+
import java.math.BigInteger;
17+
import java.util.Optional;
18+
import java.util.stream.Stream;
19+
20+
import static org.hamcrest.MatcherAssert.assertThat;
21+
import static org.hamcrest.Matchers.hasItems;
22+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
23+
import static org.junit.jupiter.api.Assertions.assertTrue;
24+
25+
class ContextBuildingNumberSerializerTest {
26+
27+
private final ContextBuildingNumberSerializer sut = new ContextBuildingNumberSerializer();
28+
29+
@ParameterizedTest
30+
@MethodSource("serializationData")
31+
void serializeSerializesNumberAsTypedValueNode(Number value, String expectedDatatype) throws Exception {
32+
final JsonLdContext ctx = new MappingJsonLdContext();
33+
sut.serialize(value,
34+
new SerializationContext<>("http://example.com/number",
35+
TestEntity.class.getDeclaredField("numberField"), value,
36+
ctx));
37+
final Optional<JsonNode> mapping = ctx.getTermMapping("numberField");
38+
assertTrue(mapping.isPresent());
39+
assertInstanceOf(ObjectNode.class, mapping.get());
40+
final ObjectNode objectNode = (ObjectNode) mapping.get();
41+
assertThat(objectNode.getItems(),
42+
hasItems(JsonNodeFactory.createLiteralNode(JsonLd.ID, "http://example.com/number"),
43+
JsonNodeFactory.createLiteralNode(JsonLd.TYPE, expectedDatatype)));
44+
}
45+
46+
static Stream<Arguments> serializationData() {
47+
return Stream.of(
48+
Arguments.of((short) 1, XSD.SHORT),
49+
Arguments.of(1, XSD.INT),
50+
Arguments.of(1L, XSD.LONG),
51+
Arguments.of(1.0f, XSD.FLOAT),
52+
Arguments.of(1.0, XSD.DOUBLE),
53+
Arguments.of(BigInteger.valueOf(1), XSD.INTEGER),
54+
Arguments.of(BigDecimal.valueOf(1.1), XSD.DECIMAL)
55+
);
56+
}
57+
58+
private static class TestEntity {
59+
60+
private Number numberField;
61+
}
62+
}

0 commit comments

Comments
 (0)