From 1e8e7bdc147d07cb34f505aecbba520294feca76 Mon Sep 17 00:00:00 2001 From: Linary Date: Tue, 12 Mar 2019 19:23:14 +0800 Subject: [PATCH] Let VertexAPI use simplified property serializer (#332) Implement #307 Change-Id: I7e47b75160ff240157aec30c1e9b4690a3412e4e --- hugegraph-api/pom.xml | 17 +- .../baidu/hugegraph/api/job/GremlinAPI.java | 51 ++- .../hugegraph/api/metrics/MetricsAPI.java | 2 +- .../baidu/hugegraph/metric/MetricsModule.java | 268 ++++++++++++++++ .../hugegraph/metric/ServerReporter.java | 27 +- .../hugegraph/serializer/JsonSerializer.java | 18 +- .../baidu/hugegraph/version/ApiVersion.java | 3 +- .../hugegraph/io/HugeGraphSONModule.java | 159 ++++++++-- .../com/baidu/hugegraph/util/JsonUtil.java | 66 +++- .../baidu/hugegraph/unit/UnitTestSuite.java | 2 + .../baidu/hugegraph/unit/core/FakeObject.java | 97 ++++++ .../hugegraph/unit/core/JsonUtilTest.java | 290 ++++++++++++++++++ 12 files changed, 914 insertions(+), 86 deletions(-) create mode 100644 hugegraph-api/src/main/java/com/baidu/hugegraph/metric/MetricsModule.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/FakeObject.java create mode 100644 hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/JsonUtilTest.java diff --git a/hugegraph-api/pom.xml b/hugegraph-api/pom.xml index 2da1f4dea8..74ac2d4195 100644 --- a/hugegraph-api/pom.xml +++ b/hugegraph-api/pom.xml @@ -48,21 +48,6 @@ io.dropwizard.metrics metrics-jersey2 - - - io.dropwizard.metrics - metrics-json - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-databind - - - @@ -101,7 +86,7 @@ - 0.33.0.0 + 0.34.0.0 diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/job/GremlinAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/job/GremlinAPI.java index 13db6b7840..5f76c7f7e3 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/job/GremlinAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/job/GremlinAPI.java @@ -176,30 +176,46 @@ private static class GremlinRequest implements Checkable { @JsonProperty private Map aliases = new HashMap<>(); - public void aliase(String key, String value) { - this.aliases.put(key, value); + public String gremlin() { + return this.gremlin; } - public void binding(String name, Object value) { - this.bindings.put(name, value); + public void gremlin(String gremlin) { + this.gremlin = gremlin; } public Map bindings() { return this.bindings; } + public void bindings(Map bindings) { + this.bindings = bindings; + } + + public void binding(String name, Object value) { + this.bindings.put(name, value); + } + public String language() { return this.language; } - public String gremlin() { - return this.gremlin; + public void language(String language) { + this.language = language; } public Map aliases() { return this.aliases; } + public void aliases(Map aliases) { + this.aliases = aliases; + } + + public void aliase(String key, String value) { + this.aliases.put(key, value); + } + public String name() { // Get the first line of script as the name String firstLine = this.gremlin.split("\r\n|\r|\n", 2)[0]; @@ -236,11 +252,30 @@ public void checkCreate(boolean isBatch) { } public String toJson() { - return JsonUtil.toJson(this); + Map map = new HashMap<>(); + map.put("gremlin", this.gremlin); + map.put("bindings", this.bindings); + map.put("language", this.language); + map.put("aliases", this.aliases); + return JsonUtil.toJson(map); } public static GremlinRequest fromJson(String json) { - return JsonUtil.fromJson(json, GremlinRequest.class); + @SuppressWarnings("unchecked") + Map map = JsonUtil.fromJson(json, Map.class); + String gremlin = (String) map.get("gremlin"); + @SuppressWarnings("unchecked") + Map bindings = (Map) map.get("bindings"); + String language = (String) map.get("language"); + @SuppressWarnings("unchecked") + Map aliases = (Map) map.get("aliases"); + + GremlinRequest request = new GremlinRequest(); + request.gremlin(gremlin); + request.bindings(bindings); + request.language(language); + request.aliases(aliases); + return request; } } } diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/metrics/MetricsAPI.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/metrics/MetricsAPI.java index 91e290ac63..629090196c 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/api/metrics/MetricsAPI.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/api/metrics/MetricsAPI.java @@ -38,6 +38,7 @@ import com.baidu.hugegraph.backend.store.BackendMetrics; import com.baidu.hugegraph.backend.tx.GraphTransaction; import com.baidu.hugegraph.core.GraphManager; +import com.baidu.hugegraph.metric.MetricsModule; import com.baidu.hugegraph.metric.ServerReporter; import com.baidu.hugegraph.metric.SystemMetrics; import com.baidu.hugegraph.util.InsertionOrderUtil; @@ -45,7 +46,6 @@ import com.baidu.hugegraph.util.Log; import com.codahale.metrics.Metric; import com.codahale.metrics.annotation.Timed; -import com.codahale.metrics.json.MetricsModule; @Singleton @Path("metrics") diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/MetricsModule.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/MetricsModule.java new file mode 100644 index 0000000000..27c6759178 --- /dev/null +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/MetricsModule.java @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package com.baidu.hugegraph.metric; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator; +import org.apache.tinkerpop.shaded.jackson.core.Version; +import org.apache.tinkerpop.shaded.jackson.databind.Module; +import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider; +import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleSerializers; +import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Histogram; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Snapshot; +import com.codahale.metrics.Timer; + +/** + * Copy from com.codahale.metrics.json.MetricsModule + */ +public class MetricsModule extends Module { + + private static final Version VERSION = new Version(1, 0, 0, "", + "com.baidu.hugegraph", + "hugegraph-api"); + + private static class GaugeSerializer extends StdSerializer { + + private GaugeSerializer() { + super(Gauge.class); + } + + @Override + public void serialize(Gauge gauge, JsonGenerator json, + SerializerProvider provider) throws IOException { + json.writeStartObject(); + final Object value; + try { + value = gauge.getValue(); + json.writeObjectField("value", value); + } catch (RuntimeException e) { + json.writeObjectField("error", e.toString()); + } + json.writeEndObject(); + } + } + + private static class CounterSerializer extends StdSerializer { + + private CounterSerializer() { + super(Counter.class); + } + + @Override + public void serialize(Counter counter, JsonGenerator json, + SerializerProvider provider) throws IOException { + json.writeStartObject(); + json.writeNumberField("count", counter.getCount()); + json.writeEndObject(); + } + } + + private static class HistogramSerializer extends StdSerializer { + + private final boolean showSamples; + + private HistogramSerializer(boolean showSamples) { + super(Histogram.class); + this.showSamples = showSamples; + } + + @Override + public void serialize(Histogram histogram, JsonGenerator json, + SerializerProvider provider) throws IOException { + json.writeStartObject(); + final Snapshot snapshot = histogram.getSnapshot(); + json.writeNumberField("count", histogram.getCount()); + json.writeNumberField("max", snapshot.getMax()); + json.writeNumberField("mean", snapshot.getMean()); + json.writeNumberField("min", snapshot.getMin()); + json.writeNumberField("p50", snapshot.getMedian()); + json.writeNumberField("p75", snapshot.get75thPercentile()); + json.writeNumberField("p95", snapshot.get95thPercentile()); + json.writeNumberField("p98", snapshot.get98thPercentile()); + json.writeNumberField("p99", snapshot.get99thPercentile()); + json.writeNumberField("p999", snapshot.get999thPercentile()); + + if (showSamples) { + json.writeObjectField("values", snapshot.getValues()); + } + + json.writeNumberField("stddev", snapshot.getStdDev()); + json.writeEndObject(); + } + } + + private static class MeterSerializer extends StdSerializer { + + private final String rateUnit; + private final double rateFactor; + + public MeterSerializer(TimeUnit rateUnit) { + super(Meter.class); + this.rateFactor = rateUnit.toSeconds(1); + this.rateUnit = calculateRateUnit(rateUnit, "events"); + } + + @Override + public void serialize(Meter meter, JsonGenerator json, + SerializerProvider provider) throws IOException { + json.writeStartObject(); + json.writeNumberField("count", meter.getCount()); + json.writeNumberField("m15_rate", meter.getFifteenMinuteRate() * rateFactor); + json.writeNumberField("m1_rate", meter.getOneMinuteRate() * rateFactor); + json.writeNumberField("m5_rate", meter.getFiveMinuteRate() * rateFactor); + json.writeNumberField("mean_rate", meter.getMeanRate() * rateFactor); + json.writeStringField("units", rateUnit); + json.writeEndObject(); + } + } + + private static class TimerSerializer extends StdSerializer { + + private final String rateUnit; + private final double rateFactor; + private final String durationUnit; + private final double durationFactor; + private final boolean showSamples; + + private TimerSerializer(TimeUnit rateUnit, TimeUnit durationUnit, + boolean showSamples) { + super(Timer.class); + this.rateUnit = calculateRateUnit(rateUnit, "calls"); + this.rateFactor = rateUnit.toSeconds(1); + this.durationUnit = durationUnit.toString().toLowerCase(Locale.US); + this.durationFactor = 1.0 / durationUnit.toNanos(1); + this.showSamples = showSamples; + } + + @Override + public void serialize(Timer timer, JsonGenerator json, + SerializerProvider provider) throws IOException { + json.writeStartObject(); + final Snapshot snapshot = timer.getSnapshot(); + json.writeNumberField("count", timer.getCount()); + json.writeNumberField("max", snapshot.getMax() * durationFactor); + json.writeNumberField("mean", snapshot.getMean() * durationFactor); + json.writeNumberField("min", snapshot.getMin() * durationFactor); + + json.writeNumberField("p50", snapshot.getMedian() * durationFactor); + json.writeNumberField("p75", snapshot.get75thPercentile() * durationFactor); + json.writeNumberField("p95", snapshot.get95thPercentile() * durationFactor); + json.writeNumberField("p98", snapshot.get98thPercentile() * durationFactor); + json.writeNumberField("p99", snapshot.get99thPercentile() * durationFactor); + json.writeNumberField("p999", snapshot.get999thPercentile() * durationFactor); + + if (showSamples) { + final long[] values = snapshot.getValues(); + final double[] scaledValues = new double[values.length]; + for (int i = 0; i < values.length; i++) { + scaledValues[i] = values[i] * durationFactor; + } + json.writeObjectField("values", scaledValues); + } + + json.writeNumberField("stddev", snapshot.getStdDev() * durationFactor); + json.writeNumberField("m15_rate", timer.getFifteenMinuteRate() * rateFactor); + json.writeNumberField("m1_rate", timer.getOneMinuteRate() * rateFactor); + json.writeNumberField("m5_rate", timer.getFiveMinuteRate() * rateFactor); + json.writeNumberField("mean_rate", timer.getMeanRate() * rateFactor); + json.writeStringField("duration_units", durationUnit); + json.writeStringField("rate_units", rateUnit); + json.writeEndObject(); + } + } + + private static class MetricRegistrySerializer + extends StdSerializer { + + private final MetricFilter filter; + + private MetricRegistrySerializer(MetricFilter filter) { + super(MetricRegistry.class); + this.filter = filter; + } + + @Override + public void serialize(MetricRegistry registry, JsonGenerator json, + SerializerProvider provider) throws IOException { + json.writeStartObject(); + json.writeStringField("version", VERSION.toString()); + json.writeObjectField("gauges", registry.getGauges(filter)); + json.writeObjectField("counters", registry.getCounters(filter)); + json.writeObjectField("histograms", registry.getHistograms(filter)); + json.writeObjectField("meters", registry.getMeters(filter)); + json.writeObjectField("timers", registry.getTimers(filter)); + json.writeEndObject(); + } + } + + private final TimeUnit rateUnit; + private final TimeUnit durationUnit; + private final boolean showSamples; + private final MetricFilter filter; + + public MetricsModule(TimeUnit rateUnit, TimeUnit durationUnit, + boolean showSamples) { + this(rateUnit, durationUnit, showSamples, MetricFilter.ALL); + } + + public MetricsModule(TimeUnit rateUnit, TimeUnit durationUnit, + boolean showSamples, MetricFilter filter) { + this.rateUnit = rateUnit; + this.durationUnit = durationUnit; + this.showSamples = showSamples; + this.filter = filter; + } + + @Override + public String getModuleName() { + return "metrics"; + } + + @Override + public Version version() { + return VERSION; + } + + @Override + public void setupModule(Module.SetupContext context) { + context.addSerializers(new SimpleSerializers(Arrays.asList( + new GaugeSerializer(), + new CounterSerializer(), + new HistogramSerializer(showSamples), + new MeterSerializer(rateUnit), + new TimerSerializer(rateUnit, durationUnit, showSamples), + new MetricRegistrySerializer(filter) + ))); + } + + private static String calculateRateUnit(TimeUnit unit, String name) { + final String s = unit.toString().toLowerCase(Locale.US); + return name + '/' + s.substring(0, s.length() - 1); + } +} diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/ServerReporter.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/ServerReporter.java index 6966df6102..e0a4888f90 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/ServerReporter.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/metric/ServerReporter.java @@ -36,18 +36,17 @@ import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.ScheduledReporter; import com.codahale.metrics.Timer; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; public class ServerReporter extends ScheduledReporter { - + private static volatile ServerReporter instance = null; - @SuppressWarnings("rawtypes") - private Map gauges; - private Map counters; - private Map histograms; - private Map meters; - private Map timers; + private SortedMap gauges; + private SortedMap counters; + private SortedMap histograms; + private SortedMap meters; + private SortedMap timers; public static synchronized ServerReporter instance(MetricRegistry registry) { if (instance == null) { @@ -72,18 +71,17 @@ private ServerReporter(MetricRegistry registry) { private ServerReporter(MetricRegistry registry, TimeUnit rateUnit, TimeUnit durationUnit, MetricFilter filter) { super(registry, "server-reporter", filter, rateUnit, durationUnit); - this.gauges = ImmutableMap.of(); - this.counters = ImmutableMap.of(); - this.histograms = ImmutableMap.of(); - this.meters = ImmutableMap.of(); - this.timers = ImmutableMap.of(); + this.gauges = ImmutableSortedMap.of(); + this.counters = ImmutableSortedMap.of(); + this.histograms = ImmutableSortedMap.of(); + this.meters = ImmutableSortedMap.of(); + this.timers = ImmutableSortedMap.of(); } public Map timers() { return Collections.unmodifiableMap(this.timers); } - @SuppressWarnings("rawtypes") public Map gauges() { return Collections.unmodifiableMap(this.gauges); } @@ -101,7 +99,6 @@ public Map meters() { } @Override - @SuppressWarnings("rawtypes") public void report(SortedMap gauges, SortedMap counters, SortedMap histograms, diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/serializer/JsonSerializer.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/serializer/JsonSerializer.java index b21b22049d..fa77febad3 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/serializer/JsonSerializer.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/serializer/JsonSerializer.java @@ -43,12 +43,13 @@ import com.baidu.hugegraph.traversal.algorithm.CustomizedCrosspointsTraverser.CrosspointsPaths; import com.baidu.hugegraph.traversal.algorithm.HugeTraverser; import com.baidu.hugegraph.traversal.optimize.TraversalUtil; +import com.baidu.hugegraph.util.JsonUtil; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; public class JsonSerializer implements Serializer { - private GraphSONWriter writer; + private final GraphSONWriter writer; private static final int BUF_SIZE = 128; private static final int LBUF_SIZE = 1024; @@ -70,7 +71,7 @@ private String writeObject(Object object) { private String writeList(String label, List list) { try (ByteArrayOutputStream out = new ByteArrayOutputStream(LBUF_SIZE)) { out.write(String.format("{\"%s\": ", label).getBytes(API.CHARSET)); - this.writer.writeObject(out, list); + out.write(JsonUtil.toJson(list).getBytes(API.CHARSET)); out.write("}".getBytes(API.CHARSET)); return out.toString(API.CHARSET); } catch (Exception e) { @@ -78,7 +79,8 @@ private String writeList(String label, List list) { } } - private String writeList(String label, Iterator itor, boolean paging) { + private String writeIterator(String label, Iterator itor, + boolean paging) { try (ByteArrayOutputStream out = new ByteArrayOutputStream(LBUF_SIZE)) { out.write("{".getBytes(API.CHARSET)); @@ -92,7 +94,7 @@ private String writeList(String label, Iterator itor, boolean paging) { } else { first = false; } - this.writer.writeObject(out, itor.next()); + out.write(JsonUtil.toJson(itor.next()).getBytes(API.CHARSET)); } out.write("]".getBytes(API.CHARSET)); @@ -181,7 +183,7 @@ public String writeVertex(Vertex vertex) { @Override public String writeVertices(Iterator vertices, boolean paging) { - return writeList("vertices", vertices, paging); + return this.writeIterator("vertices", vertices, paging); } @Override @@ -191,7 +193,7 @@ public String writeEdge(Edge edge) { @Override public String writeEdges(Iterator edges, boolean paging) { - return writeList("edges", edges, paging); + return this.writeIterator("edges", edges, paging); } @Override @@ -218,7 +220,7 @@ public String writePaths(String name, Collection paths, } else { results = ImmutableMap.of(name, pathList, "vertices", vertices); } - return writeObject(results); + return JsonUtil.toJson(results); } @Override @@ -238,7 +240,7 @@ public String writeCrosspoints(CrosspointsPaths paths, results = ImmutableMap.of("crosspoints", paths.crosspoints(), "paths", pathList, "vertices", iterator); - return writeObject(results); + return JsonUtil.toJson(results); } @Override diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java index 52359f2a06..9ef7222e22 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/version/ApiVersion.java @@ -77,10 +77,11 @@ public final class ApiVersion { * [0.31] Issue-182: Support restore graph in restoring and merging mode * [0.32] Issue-250: Keep depth and degree consistent for traverser api * [0.33] Issue-305: Implement customized paths and crosspoints RESTful API + * [0.34] Issue-307: Let VertexAPI use simplified property serializer */ // The second parameter of Version.of() is for IDE running without JAR - public static final Version VERSION = Version.of(ApiVersion.class, "0.33"); + public static final Version VERSION = Version.of(ApiVersion.class, "0.34"); public static final void check() { // Check version of hugegraph-core. Firstly do check from version 0.3 diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/io/HugeGraphSONModule.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/io/HugeGraphSONModule.java index e2ea7f0377..5e34cbade8 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/io/HugeGraphSONModule.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/io/HugeGraphSONModule.java @@ -31,6 +31,7 @@ import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator; import org.apache.tinkerpop.shaded.jackson.core.JsonParser; import org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext; +import org.apache.tinkerpop.shaded.jackson.databind.JsonSerializer; import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider; import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer; import org.apache.tinkerpop.shaded.jackson.databind.jsontype.TypeSerializer; @@ -38,6 +39,7 @@ import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer; import org.apache.tinkerpop.shaded.jackson.databind.ser.std.UUIDSerializer; +import com.baidu.hugegraph.HugeException; import com.baidu.hugegraph.backend.id.EdgeId; import com.baidu.hugegraph.backend.id.Id; import com.baidu.hugegraph.backend.id.IdGenerator; @@ -47,6 +49,10 @@ import com.baidu.hugegraph.schema.IndexLabel; import com.baidu.hugegraph.schema.PropertyKey; import com.baidu.hugegraph.schema.VertexLabel; +import com.baidu.hugegraph.structure.HugeEdge; +import com.baidu.hugegraph.structure.HugeElement; +import com.baidu.hugegraph.structure.HugeProperty; +import com.baidu.hugegraph.structure.HugeVertex; import com.baidu.hugegraph.type.define.HugeKeys; @SuppressWarnings("serial") @@ -63,7 +69,7 @@ public class HugeGraphSONModule extends TinkerPopJacksonModule { new GraphSONSchemaSerializer(); private static final String DF = "yyyy-MM-dd HH:mm:ss.SSS"; - public static final SafeDateFormat DATE_FORMAT = new SafeDateFormat(DF); + private static final SafeDateFormat DATE_FORMAT = new SafeDateFormat(DF); static { TYPE_DEFINITIONS = new ConcurrentHashMap<>(); @@ -83,6 +89,10 @@ public class HugeGraphSONModule extends TinkerPopJacksonModule { TYPE_DEFINITIONS.put(EdgeLabel.class, "EdgeLabel"); TYPE_DEFINITIONS.put(IndexLabel.class, "IndexLabel"); + // HugeGraph vertex/edge serializer + TYPE_DEFINITIONS.put(HugeVertex.class, "HugeVertex"); + TYPE_DEFINITIONS.put(HugeEdge.class, "HugeEdge"); + // HugeGraph shard serializer TYPE_DEFINITIONS.put(Shard.class, "Shard"); } @@ -117,6 +127,9 @@ private HugeGraphSONModule() { addSerializer(EdgeLabel.class, new EdgeLabelSerializer()); addSerializer(IndexLabel.class, new IndexLabelSerializer()); + addSerializer(HugeVertex.class, new HugeVertexSerializer()); + addSerializer(HugeEdge.class, new HugeEdgeSerializer()); + addSerializer(Shard.class, new ShardSerializer()); } @@ -141,7 +154,7 @@ public OptionalSerializer() { @Override public void serialize(Optional optional, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { if (optional.isPresent()) { jsonGenerator.writeObject(optional.get()); @@ -151,7 +164,7 @@ public void serialize(Optional optional, } } - private static class IdSerializer extends StdSerializer { + public static class IdSerializer extends StdSerializer { public IdSerializer(Class clazz) { super(clazz); @@ -160,7 +173,7 @@ public IdSerializer(Class clazz) { @Override public void serialize(T value, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { if (value.number()) { jsonGenerator.writeNumber(value.asLong()); @@ -172,18 +185,18 @@ public void serialize(T value, @Override public void serializeWithType(T value, JsonGenerator jsonGenerator, - SerializerProvider serializers, + SerializerProvider provider, TypeSerializer typeSer) throws IOException { typeSer.writeTypePrefixForScalar(value, jsonGenerator); - this.serialize(value, jsonGenerator, serializers); + this.serialize(value, jsonGenerator, provider); typeSer.writeTypeSuffixForScalar(value, jsonGenerator); } } @SuppressWarnings("unchecked") - private static class IdDeserializer - extends StdDeserializer { + public static class IdDeserializer + extends StdDeserializer { public IdDeserializer(Class clazz) { super(clazz); @@ -219,8 +232,8 @@ private static void writeEntry(JsonGenerator jsonGenerator, jsonGenerator.writeEndObject(); } - private static class PropertyKeySerializer - extends StdSerializer { + public static class PropertyKeySerializer + extends StdSerializer { public PropertyKeySerializer() { super(PropertyKey.class); @@ -229,14 +242,14 @@ public PropertyKeySerializer() { @Override public void serialize(PropertyKey pk, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { writeEntry(jsonGenerator, schemaSerializer.writePropertyKey(pk)); } } - private static class VertexLabelSerializer - extends StdSerializer { + public static class VertexLabelSerializer + extends StdSerializer { public VertexLabelSerializer() { super(VertexLabel.class); @@ -245,13 +258,13 @@ public VertexLabelSerializer() { @Override public void serialize(VertexLabel vl, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { writeEntry(jsonGenerator, schemaSerializer.writeVertexLabel(vl)); } } - private static class EdgeLabelSerializer extends StdSerializer { + public static class EdgeLabelSerializer extends StdSerializer { public EdgeLabelSerializer() { super(EdgeLabel.class); @@ -260,14 +273,14 @@ public EdgeLabelSerializer() { @Override public void serialize(EdgeLabel el, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { writeEntry(jsonGenerator, schemaSerializer.writeEdgeLabel(el)); } } - private static class IndexLabelSerializer - extends StdSerializer { + public static class IndexLabelSerializer + extends StdSerializer { public IndexLabelSerializer() { super(IndexLabel.class); @@ -276,13 +289,117 @@ public IndexLabelSerializer() { @Override public void serialize(IndexLabel il, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { writeEntry(jsonGenerator, schemaSerializer.writeIndexLabel(il)); } } - private static class ShardSerializer extends StdSerializer { + protected static abstract class HugeElementSerializer + extends StdSerializer { + + public HugeElementSerializer(Class clazz) { + super(clazz); + } + + public void writeIdField(String fieldName, Id id, + JsonGenerator generator) + throws IOException { + generator.writeFieldName(fieldName); + if (id.number()) { + generator.writeNumber(id.asLong()); + } else { + generator.writeString(id.asString()); + } + } + + public void writePropertiesField(Map> properties, + JsonGenerator generator, + SerializerProvider provider) + throws IOException { + // Start write properties + generator.writeFieldName("properties"); + generator.writeStartObject(); + + for (HugeProperty property : properties.values()) { + String key = property.key(); + Object val = property.value(); + try { + generator.writeFieldName(key); + if (val != null) { + JsonSerializer serializer = + provider.findValueSerializer(val.getClass()); + serializer.serialize(val, generator, provider); + } else { + generator.writeNull(); + } + } catch (IOException e) { + throw new HugeException( + "Failed to serialize property(%s: %s) " + + "for vertex '%s'", key, val, property.element()); + } + }; + // End wirte properties + generator.writeEndObject(); + } + } + + public static class HugeVertexSerializer + extends HugeElementSerializer { + + public HugeVertexSerializer() { + super(HugeVertex.class); + } + + @Override + public void serialize(HugeVertex vertex, JsonGenerator generator, + SerializerProvider provider) + throws IOException { + generator.writeStartObject(); + + this.writeIdField("id", vertex.id(), generator); + generator.writeStringField("label", vertex.label()); + generator.writeStringField("type", "vertex"); + + this.writePropertiesField(vertex.getProperties(), generator, + provider); + + generator.writeEndObject(); + } + } + + public static class HugeEdgeSerializer + extends HugeElementSerializer { + + public HugeEdgeSerializer() { + super(HugeEdge.class); + } + + @Override + public void serialize(HugeEdge edge, JsonGenerator generator, + SerializerProvider provider) + throws IOException { + generator.writeStartObject(); + + // Write id, label, type + this.writeIdField("id", edge.id(), generator); + generator.writeStringField("label", edge.label()); + generator.writeStringField("type", "edge"); + + HugeVertex outVertex = (HugeVertex) edge.outVertex(); + HugeVertex inVertex = (HugeVertex) edge.inVertex(); + this.writeIdField("outV", outVertex.id(), generator); + generator.writeStringField("outVLabel", outVertex.label()); + this.writeIdField("inV", inVertex.id(), generator); + generator.writeStringField("inVLabel", inVertex.label()); + + this.writePropertiesField(edge.getProperties(), generator, provider); + + generator.writeEndObject(); + } + } + + public static class ShardSerializer extends StdSerializer { public ShardSerializer() { super(Shard.class); @@ -290,7 +407,7 @@ public ShardSerializer() { @Override public void serialize(Shard shard, JsonGenerator jsonGenerator, - SerializerProvider serializer) + SerializerProvider provider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("start", shard.start()); diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/util/JsonUtil.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/util/JsonUtil.java index 701d28a89d..18f0eee712 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/util/JsonUtil.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/util/JsonUtil.java @@ -22,19 +22,37 @@ import java.io.IOException; import java.util.Date; +import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator; +import org.apache.tinkerpop.shaded.jackson.core.JsonParser; +import org.apache.tinkerpop.shaded.jackson.core.JsonProcessingException; +import org.apache.tinkerpop.shaded.jackson.core.type.TypeReference; +import org.apache.tinkerpop.shaded.jackson.databind.DeserializationContext; +import org.apache.tinkerpop.shaded.jackson.databind.Module; +import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper; +import org.apache.tinkerpop.shaded.jackson.databind.ObjectReader; +import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider; +import org.apache.tinkerpop.shaded.jackson.databind.deser.std.StdDeserializer; +import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule; +import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer; + import com.baidu.hugegraph.backend.BackendException; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.baidu.hugegraph.backend.id.EdgeId; +import com.baidu.hugegraph.backend.id.IdGenerator; +import com.baidu.hugegraph.backend.store.Shard; +import com.baidu.hugegraph.io.HugeGraphSONModule.EdgeLabelSerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.HugeEdgeSerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.HugeVertexSerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.IdSerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.IndexLabelSerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.PropertyKeySerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.ShardSerializer; +import com.baidu.hugegraph.io.HugeGraphSONModule.VertexLabelSerializer; +import com.baidu.hugegraph.schema.EdgeLabel; +import com.baidu.hugegraph.schema.IndexLabel; +import com.baidu.hugegraph.schema.PropertyKey; +import com.baidu.hugegraph.schema.VertexLabel; +import com.baidu.hugegraph.structure.HugeEdge; +import com.baidu.hugegraph.structure.HugeVertex; public final class JsonUtil { @@ -44,6 +62,22 @@ public final class JsonUtil { SimpleModule module = new SimpleModule(); module.addSerializer(Date.class, new DateSerializer()); module.addDeserializer(Date.class, new DateDeserializer()); + + module.addSerializer(IdGenerator.StringId.class, + new IdSerializer<>(IdGenerator.StringId.class)); + module.addSerializer(IdGenerator.LongId.class, + new IdSerializer<>(IdGenerator.LongId.class)); + module.addSerializer(EdgeId.class, new IdSerializer<>(EdgeId.class)); + + module.addSerializer(PropertyKey.class, new PropertyKeySerializer()); + module.addSerializer(VertexLabel.class, new VertexLabelSerializer()); + module.addSerializer(EdgeLabel.class, new EdgeLabelSerializer()); + module.addSerializer(IndexLabel.class, new IndexLabelSerializer()); + + module.addSerializer(HugeVertex.class, new HugeVertexSerializer()); + module.addSerializer(HugeEdge.class, new HugeEdgeSerializer()); + + module.addSerializer(Shard.class, new ShardSerializer()); mapper.registerModule(module); } @@ -116,10 +150,10 @@ public DateSerializer() { } @Override - public void serialize(Date date, JsonGenerator jsonGenerator, + public void serialize(Date date, JsonGenerator generator, SerializerProvider provider) throws IOException { - jsonGenerator.writeNumber(date.getTime()); + generator.writeNumber(date.getTime()); } } @@ -132,10 +166,10 @@ public DateDeserializer() { } @Override - public Date deserialize(JsonParser jsonParser, + public Date deserialize(JsonParser parser, DeserializationContext context) throws IOException { - Long number = jsonParser.readValueAs(Long.class); + Long number = parser.readValueAs(Long.class); return new Date(number); } } diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java index eb7022121a..bb9a6b949e 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/UnitTestSuite.java @@ -28,6 +28,7 @@ import com.baidu.hugegraph.unit.core.BackendMutationTest; import com.baidu.hugegraph.unit.core.ConditionQueryFlattenTest; import com.baidu.hugegraph.unit.core.EdgeIdTest; +import com.baidu.hugegraph.unit.core.JsonUtilTest; import com.baidu.hugegraph.unit.core.VersionTest; import com.baidu.hugegraph.unit.rocksdb.RocksDBCountersTest; import com.baidu.hugegraph.unit.rocksdb.RocksDBSessionsTest; @@ -42,6 +43,7 @@ ConditionQueryFlattenTest.class, EdgeIdTest.class, AnalyzerTest.class, + JsonUtilTest.class, RocksDBSessionsTest.class, RocksDBCountersTest.class diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/FakeObject.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/FakeObject.java new file mode 100644 index 0000000000..39dda5cb7f --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/FakeObject.java @@ -0,0 +1,97 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package com.baidu.hugegraph.unit.core; + +import org.mockito.Mockito; + +import com.baidu.hugegraph.HugeGraph; +import com.baidu.hugegraph.backend.id.Id; +import com.baidu.hugegraph.schema.EdgeLabel; +import com.baidu.hugegraph.schema.IndexLabel; +import com.baidu.hugegraph.schema.PropertyKey; +import com.baidu.hugegraph.schema.VertexLabel; +import com.baidu.hugegraph.type.HugeType; +import com.baidu.hugegraph.type.define.Cardinality; +import com.baidu.hugegraph.type.define.DataType; +import com.baidu.hugegraph.type.define.Frequency; +import com.baidu.hugegraph.type.define.IdStrategy; +import com.baidu.hugegraph.type.define.IndexType; + +public final class FakeObject { + + private final HugeGraph graph; + + public FakeObject() { + this.graph = Mockito.mock(HugeGraph.class); + } + + public HugeGraph graph() { + return this.graph; + } + + public PropertyKey newPropertyKey(Id id, String name) { + return newPropertyKey(id, name, DataType.TEXT, Cardinality.SINGLE); + } + + public PropertyKey newPropertyKey(Id id, String name, + DataType dataType) { + return newPropertyKey(id, name, dataType, Cardinality.SINGLE); + } + + public PropertyKey newPropertyKey(Id id, String name, + DataType dataType, + Cardinality cardinality) { + PropertyKey schema = new PropertyKey(this.graph, id, name); + schema.dataType(dataType); + schema.cardinality(cardinality); + return schema; + } + + public VertexLabel newVertexLabel(Id id, String name, + IdStrategy idStrategy, + Id... properties) { + VertexLabel schema = new VertexLabel(this.graph, id, name); + schema.idStrategy(idStrategy); + schema.properties(properties); + return schema; + } + + public EdgeLabel newEdgeLabel(Id id, String name, Frequency frequency, + Id sourceLabel, Id targetLabel, + Id... properties) { + EdgeLabel schema = new EdgeLabel(this.graph, id, name); + schema.frequency(frequency); + schema.sourceLabel(sourceLabel); + schema.targetLabel(targetLabel); + schema.properties(properties); + return schema; + } + + public IndexLabel newIndexLabel(Id id, String name, HugeType baseType, + Id baseValue, IndexType indexType, + Id... fields) { + IndexLabel schema = new IndexLabel(this.graph, id, name); + schema.baseType(baseType); + schema.baseValue(baseValue); + schema.indexType(indexType); + schema.indexFields(fields); + return schema; + } +} diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/JsonUtilTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/JsonUtilTest.java new file mode 100644 index 0000000000..3886906df7 --- /dev/null +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/unit/core/JsonUtilTest.java @@ -0,0 +1,290 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package com.baidu.hugegraph.unit.core; + +import java.util.Arrays; +import java.util.Map; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import com.baidu.hugegraph.backend.id.EdgeId; +import com.baidu.hugegraph.backend.id.Id; +import com.baidu.hugegraph.backend.id.IdGenerator; +import com.baidu.hugegraph.schema.EdgeLabel; +import com.baidu.hugegraph.schema.IndexLabel; +import com.baidu.hugegraph.schema.PropertyKey; +import com.baidu.hugegraph.schema.VertexLabel; +import com.baidu.hugegraph.structure.HugeEdge; +import com.baidu.hugegraph.structure.HugeEdgeProperty; +import com.baidu.hugegraph.structure.HugeProperty; +import com.baidu.hugegraph.structure.HugeVertex; +import com.baidu.hugegraph.structure.HugeVertexProperty; +import com.baidu.hugegraph.testutil.Assert; +import com.baidu.hugegraph.testutil.Utils; +import com.baidu.hugegraph.testutil.Whitebox; +import com.baidu.hugegraph.type.HugeType; +import com.baidu.hugegraph.type.define.Cardinality; +import com.baidu.hugegraph.type.define.DataType; +import com.baidu.hugegraph.type.define.Directions; +import com.baidu.hugegraph.type.define.Frequency; +import com.baidu.hugegraph.type.define.IdStrategy; +import com.baidu.hugegraph.type.define.IndexType; +import com.baidu.hugegraph.unit.BaseUnitTest; +import com.baidu.hugegraph.util.JsonUtil; +import com.google.common.collect.ImmutableMap; + +public class JsonUtilTest extends BaseUnitTest { + + @Before + public void setup() { + // pass + } + + @After + public void teardown() { + // pass + } + + @Test + public void testSerializeStringId() { + Id id = IdGenerator.of("123456"); + String json = JsonUtil.toJson(id); + Assert.assertEquals("\"123456\"", json); + } + + @Test + public void testSerializeLongId() { + Id id = IdGenerator.of(123456L); + String json = JsonUtil.toJson(id); + Assert.assertEquals("123456", json); + } + + @Test + public void testSerializePropertyKey() { + FakeObject fakeObject = new FakeObject(); + PropertyKey name = fakeObject.newPropertyKey(IdGenerator.of(1), "name"); + String json = JsonUtil.toJson(name); + Assert.assertEquals("{\"id\":1,\"name\":\"name\"," + + "\"data_type\":\"TEXT\"," + + "\"cardinality\":\"SINGLE\"," + + "\"properties\":[],\"user_data\":{}}", json); + + PropertyKey rate = fakeObject.newPropertyKey(IdGenerator.of(2), "rate", + DataType.INT, + Cardinality.LIST); + json = JsonUtil.toJson(rate); + Assert.assertEquals("{\"id\":2,\"name\":\"rate\"," + + "\"data_type\":\"INT\",\"cardinality\":\"LIST\"," + + "\"properties\":[],\"user_data\":{}}", json); + } + + @Test + public void testSerializeVertexLabel() { + FakeObject fakeObject = new FakeObject(); + PropertyKey name = fakeObject.newPropertyKey(IdGenerator.of(1), "name"); + PropertyKey age = fakeObject.newPropertyKey(IdGenerator.of(2), "age", + DataType.INT, + Cardinality.SINGLE); + PropertyKey city = fakeObject.newPropertyKey(IdGenerator.of(3), "city"); + + VertexLabel vl = fakeObject.newVertexLabel(IdGenerator.of(1), "person", + IdStrategy.CUSTOMIZE_NUMBER, + name.id(), age.id(), + city.id()); + Mockito.when(fakeObject.graph().mapPkId2Name(vl.properties())) + .thenReturn(Arrays.asList(name.name(), age.name(), city.name())); + + String json = JsonUtil.toJson(vl); + Assert.assertEquals("{\"id\":1,\"name\":\"person\"," + + "\"id_strategy\":\"CUSTOMIZE_NUMBER\"," + + "\"primary_keys\":[],\"nullable_keys\":[]," + + "\"index_labels\":[]," + + "\"properties\":[\"name\",\"age\",\"city\"]," + + "\"enable_label_index\":true,\"user_data\":{}}", + json); + } + + @Test + public void testSerializeEdgeLabel() { + FakeObject fakeObject = new FakeObject(); + PropertyKey name = fakeObject.newPropertyKey(IdGenerator.of(1), "name"); + PropertyKey age = fakeObject.newPropertyKey(IdGenerator.of(2), "age", + DataType.INT, + Cardinality.SINGLE); + PropertyKey city = fakeObject.newPropertyKey(IdGenerator.of(3), "city"); + PropertyKey date = fakeObject.newPropertyKey(IdGenerator.of(4), "date", + DataType.DATE); + PropertyKey weight = fakeObject.newPropertyKey(IdGenerator.of(5), + "weight", + DataType.DOUBLE); + + VertexLabel vl = fakeObject.newVertexLabel(IdGenerator.of(1), "person", + IdStrategy.CUSTOMIZE_NUMBER, + name.id(), age.id(), + city.id()); + + EdgeLabel el = fakeObject.newEdgeLabel(IdGenerator.of(1), "knows", + Frequency.SINGLE, + vl.id(), vl.id(), + date.id(), weight.id()); + + Mockito.when(fakeObject.graph().vertexLabel(vl.id())).thenReturn(vl); + Mockito.when(fakeObject.graph().mapPkId2Name(el.properties())) + .thenReturn(Arrays.asList(date.name(), weight.name())); + + String json = JsonUtil.toJson(el); + Assert.assertEquals("{\"id\":1,\"name\":\"knows\"," + + "\"source_label\":\"person\"," + + "\"target_label\":\"person\"," + + "\"frequency\":\"SINGLE\",\"sort_keys\":[]," + + "\"nullable_keys\":[],\"index_labels\":[]," + + "\"properties\":[\"date\",\"weight\"]," + + "\"enable_label_index\":true," + + "\"user_data\":{}}", json); + } + + @Test + public void testSerializeIndexLabel() { + FakeObject fakeObject = new FakeObject(); + PropertyKey name = fakeObject.newPropertyKey(IdGenerator.of(1), "name"); + PropertyKey age = fakeObject.newPropertyKey(IdGenerator.of(2), "age", + DataType.INT, + Cardinality.SINGLE); + PropertyKey city = fakeObject.newPropertyKey(IdGenerator.of(3), "city"); + + VertexLabel vl = fakeObject.newVertexLabel(IdGenerator.of(1), "person", + IdStrategy.CUSTOMIZE_NUMBER, + name.id(), age.id(), + city.id()); + + IndexLabel il = fakeObject.newIndexLabel(IdGenerator.of(1), + "personByAgeAndCity", + HugeType.VERTEX_LABEL, + vl.id(), + IndexType.SECONDARY, + age.id(), city.id()); + + Mockito.when(fakeObject.graph().vertexLabel(vl.id())).thenReturn(vl); + Mockito.when(fakeObject.graph().mapPkId2Name(il.indexFields())) + .thenReturn(Arrays.asList(age.name(), city.name())); + + String json = JsonUtil.toJson(il); + Assert.assertEquals("{\"id\":1," + + "\"name\":\"personByAgeAndCity\"," + + "\"base_type\":\"VERTEX_LABEL\"," + + "\"base_value\":\"person\"," + + "\"index_type\":\"SECONDARY\"," + + "\"fields\":[\"age\",\"city\"]}", json); + } + + @Test + public void testSerializeEdgeId() { + Id id = new EdgeId(IdGenerator.of("1:marko"), Directions.OUT, + IdGenerator.of(1), "", + IdGenerator.of("1:josh")); + String json = JsonUtil.toJson(id); + Assert.assertEquals("\"S1:marko>1>>S1:josh\"", json); + } + + @Test + public void testSerializeVertexWithNumberId() { + FakeObject fakeObject = new FakeObject(); + PropertyKey name = fakeObject.newPropertyKey(IdGenerator.of(1), "name"); + PropertyKey age = fakeObject.newPropertyKey(IdGenerator.of(2), "age", + DataType.INT, + Cardinality.SINGLE); + PropertyKey city = fakeObject.newPropertyKey(IdGenerator.of(3), "city"); + + VertexLabel vl = fakeObject.newVertexLabel(IdGenerator.of(1), "person", + IdStrategy.CUSTOMIZE_NUMBER, + name.id(), age.id(), + city.id()); + + Id id = IdGenerator.of(123456L); + HugeVertex vertex = new HugeVertex(fakeObject.graph(), id, vl); + + Map> properties = ImmutableMap.of( + name.id(), new HugeVertexProperty<>(vertex, name, "marko"), + age.id(), new HugeVertexProperty<>(vertex, age, 29), + city.id(), new HugeVertexProperty<>(vertex, city, "Beijing") + ); + Whitebox.setInternalState(vertex, "properties", properties); + + String json = JsonUtil.toJson(vertex); + Assert.assertEquals("{\"id\":123456,\"label\":\"person\"," + + "\"type\":\"vertex\",\"properties\":{\"" + + "name\":\"marko\",\"age\":29," + + "\"city\":\"Beijing\"}}", json); + } + + @Test + public void testSerializeEdge() { + FakeObject fakeObject = new FakeObject(); + PropertyKey name = fakeObject.newPropertyKey(IdGenerator.of(1), "name"); + PropertyKey age = fakeObject.newPropertyKey(IdGenerator.of(2), "age", + DataType.INT, + Cardinality.SINGLE); + PropertyKey city = fakeObject.newPropertyKey(IdGenerator.of(3), "city"); + PropertyKey date = fakeObject.newPropertyKey(IdGenerator.of(4), "date", + DataType.DATE); + PropertyKey weight = fakeObject.newPropertyKey(IdGenerator.of(5), + "weight", + DataType.DOUBLE); + + VertexLabel vl = fakeObject.newVertexLabel(IdGenerator.of(1), "person", + IdStrategy.CUSTOMIZE_NUMBER, + name.id(), age.id(), + city.id()); + + EdgeLabel el = fakeObject.newEdgeLabel(IdGenerator.of(1), "knows", + Frequency.SINGLE, + vl.id(), vl.id(), + date.id(), weight.id()); + + HugeVertex source = new HugeVertex(fakeObject.graph(), + IdGenerator.of(123456), vl); + HugeVertex target = new HugeVertex(fakeObject.graph(), + IdGenerator.of(987654), vl); + + Id id = EdgeId.parse("L123456>1>>L987654"); + HugeEdge edge = new HugeEdge(fakeObject.graph(), id, el); + Whitebox.setInternalState(edge, "sourceVertex", source); + Whitebox.setInternalState(edge, "targetVertex", target); + + Map> properties = ImmutableMap.of( + date.id(), new HugeEdgeProperty<>(edge, date, + Utils.date("2019-03-12")), + weight.id(), new HugeEdgeProperty<>(edge, weight, 0.8) + ); + Whitebox.setInternalState(edge, "properties", properties); + + long dateTime = Utils.date("2019-03-12").getTime(); + String json = JsonUtil.toJson(edge); + Assert.assertEquals(String.format("{\"id\":\"L123456>1>>L987654\"," + + "\"label\":\"knows\",\"type\":\"edge\"," + + "\"outV\":123456,\"outVLabel\":\"person\"," + + "\"inV\":987654,\"inVLabel\":\"person\"," + + "\"properties\":{\"date\":%s," + + "\"weight\":0.8}}", dateTime), json); + } +}