Progressed on port from dotnet to java

This commit is contained in:
David Noble
2019-09-10 01:30:06 -07:00
parent d3029f55d2
commit 30c7cb9256
8 changed files with 385 additions and 355 deletions

View File

@@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import javax.annotation.Nonnull;
import java.io.IOException;
import static com.google.common.base.Strings.lenientFormat;
@@ -26,7 +27,7 @@ import static com.google.common.base.Strings.lenientFormat;
*/
@JsonDeserialize(using = SchemaId.JsonDeserializer.class)
@JsonSerialize(using = SchemaId.JsonSerializer.class)
public final class SchemaId {
public final class SchemaId implements Comparable<SchemaId> {
public static final int BYTES = Integer.BYTES;
public static final SchemaId INVALID = null;
@@ -46,9 +47,21 @@ public final class SchemaId {
this.value = value;
}
@Override
public int compareTo(@Nonnull SchemaId other) {
return Integer.compare(this.value, other.value);
}
@Override
public boolean equals(Object other) {
return other instanceof SchemaId && this.equals((SchemaId) other);
if (this == other) {
return true;
}
if (other == null || this.getClass() != other.getClass()) {
return false;
}
SchemaId schemaId = (SchemaId) other;
return this.value == schemaId.value;
}
/**

View File

@@ -20,7 +20,6 @@ import com.azure.data.cosmos.serialization.hybridrow.schemas.TuplePropertyType;
import com.azure.data.cosmos.serialization.hybridrow.schemas.TypeKind;
import com.azure.data.cosmos.serialization.hybridrow.schemas.UdtPropertyType;
import com.google.common.base.Strings;
import tangible.ListHelper;
import javax.annotation.Nonnull;
import java.util.List;
@@ -46,7 +45,7 @@ public final class LayoutCompiler {
checkNotNull(ns, "expected non-null ns");
checkNotNull(schema, "expected non-null schema");
checkArgument(schema.type() == TypeKind.Schema);
checkArgument(schema.type() == TypeKind.SCHEMA);
checkArgument(!Strings.isNullOrEmpty(schema.name()));
checkArgument(ns.schemas().contains(schema));
@@ -162,82 +161,82 @@ public final class LayoutCompiler {
switch (logicalType.type()) {
case Null:
case NULL:
return LayoutTypes.NULL;
case Boolean:
case BOOLEAN:
return LayoutTypes.BOOLEAN;
case Int8:
case INT_8:
return LayoutTypes.INT_8;
case Int16:
case INT_16:
return LayoutTypes.INT_16;
case Int32:
case INT_32:
return LayoutTypes.INT_32;
case Int64:
case INT_64:
return LayoutTypes.INT_64;
case UInt8:
case UINT_8:
return LayoutTypes.UINT_8;
case UInt16:
case UINT_16:
return LayoutTypes.UINT_16;
case UInt32:
case UINT_32:
return LayoutTypes.UINT_32;
case UInt64:
case UINT_64:
return LayoutTypes.UINT_64;
case Float32:
case FLOAT_32:
return LayoutTypes.FLOAT_32;
case Float64:
case FLOAT_64:
return LayoutTypes.FLOAT_64;
case Float128:
case FLOAT_128:
return LayoutTypes.FLOAT_128;
case Decimal:
case DECIMAL:
return LayoutTypes.DECIMAL;
case DateTime:
case DATE_TIME:
return LayoutTypes.DATE_TIME;
case UnixDateTime:
case UNIX_DATE_TIME:
return LayoutTypes.UNIX_DATE_TIME;
case Guid:
case GUID:
return LayoutTypes.GUID;
case MongoDbObjectId:
case MONGODB_OBJECT_ID:
throw new UnsupportedOperationException();
// return LayoutTypes.MONGO_DB_OBJECT_ID;
case Utf8:
case UTF_8:
return LayoutTypes.UTF_8;
case Binary:
case BINARY:
return LayoutTypes.BINARY;
case VarInt:
case VAR_INT:
return LayoutTypes.VAR_INT;
case VarUInt:
case VAR_UINT:
return LayoutTypes.VAR_UINT;
case Object:
case OBJECT:
return immutable ? LayoutTypes.IMMUTABLE_OBJECT : LayoutTypes.OBJECT;
case Array: {
case ARRAY: {
assert logicalType instanceof ArrayPropertyType;
ArrayPropertyType ap = (ArrayPropertyType) logicalType;
if (ap.items() != null && (ap.items().type() != TypeKind.Any)) {
if (ap.items() != null && (ap.items().type() != TypeKind.ANY)) {
final Out<TypeArgumentList> out = new Out<>();
@@ -260,7 +259,7 @@ public final class LayoutCompiler {
assert logicalType instanceof SetPropertyType;
SetPropertyType sp = (SetPropertyType) logicalType;
if ((sp.items() != null) && (sp.items().type() != TypeKind.Any)) {
if ((sp.items() != null) && (sp.items().type() != TypeKind.ANY)) {
final Out<TypeArgumentList> out = new Out<>();
@@ -288,7 +287,7 @@ public final class LayoutCompiler {
assert logicalType instanceof MapPropertyType;
MapPropertyType mp = (MapPropertyType) logicalType;
if (mp.keys() != null && (mp.keys().type() != TypeKind.Any) && (mp.values() != null) && (mp.values().type() != TypeKind.Any)) {
if (mp.keys() != null && (mp.keys().type() != TypeKind.ANY) && (mp.values() != null) && (mp.values().type() != TypeKind.ANY)) {
final Out<TypeArgumentList> out = new Out<>();
@@ -322,7 +321,7 @@ public final class LayoutCompiler {
"Unknown property type: %s", logicalType.type())
);
}
case Tuple: {
case TUPLE: {
assert logicalType instanceof TuplePropertyType;
final TuplePropertyType tp = (TuplePropertyType) logicalType;
@@ -389,7 +388,7 @@ public final class LayoutCompiler {
throw new LayoutCompilationException("Unexpected tagged arity");
}
}
case Schema: {
case SCHEMA: {
assert logicalType instanceof UdtPropertyType;
UdtPropertyType up = (UdtPropertyType) logicalType;

View File

@@ -9,7 +9,7 @@ package com.azure.data.cosmos.serialization.hybridrow.schemas;
* Maps are typed or untyped. Within typed maps, all key MUST be the same type, and all values MUST be the same type.
* The type of both key and values is specified via {@link #keys} and {@link #values} respectively. Typed maps may be
* stored more efficiently than untyped maps. When {@link #keys} or {@link #values} is unspecified or marked
* {@link TypeKind#Any}, the map is untyped and its key and/or values may be heterogeneous.
* {@link TypeKind#ANY}, the map is untyped and its key and/or values may be heterogeneous.
*/
public class MapPropertyType extends ScopePropertyType {

View File

@@ -25,12 +25,13 @@ public class Namespace {
/**
* The fully qualified identifier of the namespace.
*/
public final String getName() {
public final String name() {
return this.name;
}
public final void setName(String value) {
public final Namespace name(String value) {
this.name = value;
return this;
}
/**

View File

@@ -42,7 +42,7 @@ public class Schema {
* Initializes a new instance of the {@link Schema} class.
*/
public Schema() {
this.type(TypeKind.Schema);
this.type(TypeKind.SCHEMA);
this.properties = Collections.emptyList();
this.partitionKeys = Collections.emptyList();
this.primaryKeys = Collections.emptyList();
@@ -209,7 +209,7 @@ public class Schema {
/**
* The type of this schema
* <p>
* This value MUST be {@link TypeKind#Schema}.
* This value MUST be {@link TypeKind#SCHEMA}.
*/
public final TypeKind type() {
return this.type;

View File

@@ -3,126 +3,222 @@
package com.azure.data.cosmos.serialization.hybridrow.schemas;
import com.azure.data.cosmos.core.Json;
import com.azure.data.cosmos.serialization.hybridrow.SchemaId;
import com.google.common.base.Strings;
import org.checkerframework.checker.nullness.qual.NonNull;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.lenientFormat;
public final class SchemaValidator {
HashMap<SchemaId, Schema> ids
HashMap<SchemaId, Schema> ids>schemas,
HashMap<SchemaId, Schema> ids)
HashMap<SchemaId, Schema> ids
{
for (Schema s : ns.getSchemas()) {
SchemaValidator.Visit(s, schemas, ids);
}
}>schemas,
private static class SchemaIdentification implements Comparable<SchemaIdentification> {
{
ValidateAssert.AreEqual(s.getType(), TypeKind.Schema, String.format("The type of a schema MUST be %1$s: %2$s"
, TypeKind.Schema, s.getType()));
HashMap<String, Property> pathDupCheck = new HashMap<String, Property>(s.getProperties().size());
for (Property p : s.getProperties()) {
ValidateAssert.DuplicateCheck(p.path(), p, pathDupCheck, "Property path", "Schema");
private final SchemaId id;
private final String name;
private SchemaIdentification(@Nonnull final String name, @Nonnull final SchemaId id) {
checkNotNull(name, "expected non-null name");
checkNotNull(id, "expected non-null id");
this.name = name;
this.id = id;
}
for (PartitionKey pk : s.getPartitionKeys()) {
ValidateAssert.Exists(pk.path(), pathDupCheck, "Partition key column", "Schema");
@Override
public int compareTo(@Nonnull SchemaIdentification other) {
checkNotNull(other, "expected non-null other");
int result = Integer.compare(this.id.value(), other.id.value());
return result == 0 ? this.name().compareTo(other.name()) : result;
}
for (PrimarySortKey ps : s.getPrimarySortKeys()) {
ValidateAssert.Exists(ps.path(), pathDupCheck, "Primary sort key column", "Schema");
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (null == other || this.getClass() != other.getClass()) {
return false;
}
SchemaIdentification that = (SchemaIdentification) other;
return this.id.equals(that.id) && this.name.equals(that.name);
}
for (StaticKey sk : s.getStaticKeys()) {
ValidateAssert.Exists(sk.path(), pathDupCheck, "Static key column", "Schema");
@Override
public int hashCode() {
return Objects.hash(this.id, this.name);
}
for (Property p : s.getProperties()) {
SchemaValidator.Visit(p, s, schemas, ids);
public SchemaId id() {
return this.id;
}
})
{
ValidateAssert.IsValidIdentifier(p.getPath(), "Property path");
SchemaValidator.Visit(p.getPropertyType(), null, schemas, ids);
public String name() {
return this.name;
}
@Override
public String toString() {
return Json.toString(this);
}
public static SchemaIdentification of(@NonNull String name, @NonNull SchemaId id) {
return new SchemaIdentification(name, id);
}
}
public static void Validate(@NonNull final Namespace namespace) {
checkNotNull(namespace, "expected non-null namespace");
final int initialCapacity = namespace.schemas().size();
final Map<SchemaIdentification, Schema> nameDupCheck = new HashMap<>(initialCapacity);
final Map<String, Integer> nameVersioningCheck = new HashMap<>(initialCapacity);
final Map<SchemaId, Schema> idDupCheck = new HashMap<>(initialCapacity);
for (Schema schema : namespace.schemas()) {
SchemaIdentification identification = SchemaIdentification.of(schema.name(), schema.schemaId());
Assert.isValidIdentifier(identification.name(), "Schema name");
Assert.isValidSchemaId(identification.id(), "Schema id");
Assert.duplicateCheck(identification.id(), schema, idDupCheck, "Schema id", "Namespace");
Assert.duplicateCheck(identification, schema, nameDupCheck, "Schema reference", "Namespace");
// Count the versions of each schema by name.
nameVersioningCheck.TryGetValue(schema.name(), out int count);
nameVersioningCheck.put(schema.name(), count + 1);
}
// Enable id-less Schema references for all types with a unique version in the namespace
for (Schema schema : namespace.schemas()) {
if (nameVersioningCheck.get(schema.name()) == 1) {
Assert.duplicateCheck(SchemaIdentification.of(schema.name(), SchemaId.INVALID), schema, nameDupCheck, "Schema reference", "Namespace");
}
}
SchemaValidator.visit(namespace, nameDupCheck, idDupCheck);
}
/// <summary>Visit an entire namespace and validate its constraints.</summary>
/// <param name="ns">The <see cref="Namespace" /> to validate.</param>
/// <param name="schemas">A map from schema names within the namespace to their schemas.</param>
/// <param name="ids">A map from schema ids within the namespace to their schemas.</param>
private static void visit(Namespace ns, Map<SchemaIdentification, Schema> schemas, Map<SchemaId, Schema> ids) {
for (Schema schema : ns.schemas()) {
SchemaValidator.visit(schema, schemas, ids);
}
}
/// <summary>Visit a single schema and validate its constraints.</summary>
/// <param name="schema">The <see cref="Schema" /> to validate.</param>
/// <param name="schemas">A map from schema names within the namespace to their schemas.</param>
/// <param name="ids">A map from schema ids within the namespace to their schemas.</param>
private static void visit(Schema schema, Map<SchemaIdentification, Schema> schemas, Map<SchemaId, Schema> ids) {
Assert.areEqual(
schema.type(), TypeKind.SCHEMA, lenientFormat("The type of a schema MUST be %s: %s", TypeKind.SCHEMA, schema.type())
);
HashMap<String, Property> pathDupCheck = new HashMap<>(schema.properties().size());
for (Property p : schema.properties()) {
Assert.duplicateCheck(p.path(), p, pathDupCheck, "Property path", "Schema");
}
for (PartitionKey pk : schema.partitionKeys()) {
Assert.exists(pk.path(), pathDupCheck, "Partition key column", "Schema");
}
for (PrimarySortKey ps : schema.primarySortKeys()) {
Assert.exists(ps.path(), pathDupCheck, "Primary sort key column", "Schema");
}
for (StaticKey sk : schema.staticKeys()) {
Assert.exists(sk.path(), pathDupCheck, "Static key column", "Schema");
}
for (Property p : schema.properties()) {
SchemaValidator.visit(p, schema, schemas, ids);
}
}
private static void visit(
Property p, Schema s, Map<SchemaIdentification, Schema> schemas, Map<SchemaId, Schema> ids) {
Assert.isValidIdentifier(p.path(), "Property path");
SchemaValidator.visit(p.propertyType(), null, schemas, ids);
}
private static void visit(
PropertyType p,
PropertyType parent,
Map<SchemaIdentification, Schema> schemas,
Map<SchemaId, Schema> ids)
{
switch (p)
{
switch (p) {
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case PrimitivePropertyType pp:
case PrimitivePropertyType
pp:
ValidateAssert.IsTrue(pp.Length >= 0, "Length MUST be positive");
if (parent != null) {
ValidateAssert.AreEqual(pp.Storage, StorageKind.SPARSE, String.format("Nested fields MUST have " +
"storage %1$s", StorageKind.SPARSE));
case PrimitivePropertyType pp:
Assert.isTrue(pp.Length >= 0, "Length MUST be positive");
if (parent != null)
{
Assert.areEqual(pp.Storage, StorageKind.Sparse, $"Nested fields MUST have storage {StorageKind.Sparse}");
}
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case ArrayPropertyType ap:
case ArrayPropertyType
ap:
if (ap.Items != null) {
SchemaValidator.Visit(ap.Items, p, schemas, ids);
}
case ArrayPropertyType ap:
if (ap.Items != null)
{
SchemaValidator.visit(ap.Items, p, schemas, ids);
}
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case MapPropertyType mp:
case MapPropertyType
mp:
SchemaValidator.Visit(mp.keySet(), p, schemas, ids);
SchemaValidator.Visit(mp.Values, p, schemas, ids);
case MapPropertyType mp:
SchemaValidator.visit(mp.Keys, p, schemas, ids);
SchemaValidator.visit(mp.Values, p, schemas, ids);
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case SetPropertyType sp:
case SetPropertyType
sp:
SchemaValidator.Visit(sp.Items, p, schemas, ids);
case SetPropertyType sp:
SchemaValidator.visit(sp.Items, p, schemas, ids);
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case TaggedPropertyType gp:
case TaggedPropertyType
gp:
for (PropertyType item : gp.Items) {
SchemaValidator.Visit(item, p, schemas, ids);
}
case TaggedPropertyType gp:
for (PropertyType item : gp.Items)
{
SchemaValidator.visit(item, p, schemas, ids);
}
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case TuplePropertyType tp:
case TuplePropertyType
tp:
for (PropertyType item : tp.Items) {
SchemaValidator.Visit(item, p, schemas, ids);
}
break;
case TuplePropertyType tp:
for (PropertyType item : tp.Items)
{
SchemaValidator.visit(item, p, schemas, ids);
}
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case ObjectPropertyType op:
case ObjectPropertyType
op:
HashMap<String, Property> pathDupCheck = new HashMap<String, Property>(op.Properties.Count);
for (Property nested : op.Properties) {
ValidateAssert.DuplicateCheck(nested.path(), nested, pathDupCheck, "Property path", "Object");
SchemaValidator.Visit(nested.propertyType(), p, schemas, ids);
}
break;
case ObjectPropertyType op:
Map<String, Property> pathDupCheck = new HashMap<>(op.Properties.Count);
for (Property nested : op.Properties)
{
Assert.duplicateCheck(nested.path(), nested, pathDupCheck, "Property path", "Object");
SchemaValidator.visit(nested.propertyType(), p, schemas, ids);
}
break;
// TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements:
//ORIGINAL LINE: case UdtPropertyType up:
case UdtPropertyType
up:
ValidateAssert.Exists((up.Name, up.SchemaId), schemas, "Schema reference", "Namespace")
if (SchemaId.opNotEquals(up.SchemaId,
SchemaId.INVALID)) {
Schema s = ValidateAssert.Exists(up.SchemaId, ids, "Schema id", "Namespace");
ValidateAssert.AreEqual(up.Name, s.name(), String.format("Schema name '%1$s' does not match " +
"the name of schema with id '%2$s': %3$s", up.Name, up.SchemaId, s.name()));
break;
case UdtPropertyType up:
Assert.exists((up.Name, up.SchemaId), schemas, "Schema reference", "Namespace");
if (up.SchemaId != SchemaId.Invalid)
{
Schema s = Assert.exists(up.SchemaId, ids, "Schema id", "Namespace");
Assert.areEqual(
up.Name,
s.Name,
$"Schema name '{up.Name}' does not match the name of schema with id '{up.SchemaId}': {s.Name}");
}
break;
@@ -130,146 +226,79 @@ HashMap<SchemaId, Schema> ids
Contract.Fail("Unknown property type");
break;
}
}>schemas,
}
public static void Validate(Namespace ns) {
HashMap<String, Integer> nameVersioningCheck = new HashMap<String, Integer>(ns.schemas().size());
HashMap< (String, SchemaId),
Schema > nameDupCheck = new HashMap<(String, SchemaId), Schema > (ns.schemas().size());
HashMap<SchemaId, Schema> idDupCheck = new HashMap<SchemaId, Schema>(ns.schemas().size());
for (Schema s : ns.schemas()) {
ValidateAssert.IsValidSchemaId(s.schemaId().clone(), "Schema id");
ValidateAssert.IsValidIdentifier(s.name(), "Schema name");
ValidateAssert.DuplicateCheck(s.schemaId().clone(), s, idDupCheck, "Schema id", "Namespace");
ValidateAssert.DuplicateCheck((s.name(), s.schemaId().clone()), s, nameDupCheck, "Schema reference"
, "Namespace")
private static class Assert {
// Count the versions of each schema by name.
int count;
count = nameVersioningCheck.get(s.name());
nameVersioningCheck.put(s.name(), count + 1);
}
// Enable id-less Schema references for all types with a unique version in the namespace.
for (Schema s : ns.schemas()) {
if (nameVersioningCheck.get(s.name()).equals(1)) {
ValidateAssert.DuplicateCheck((s.name(), SchemaId.INVALID), s, nameDupCheck, "Schema reference",
"Namespace")
/// <summary>Validate <paramref name="key" /> does not already appear within the given scope.</summary>
/// <typeparam name="TKey">The type of the keys within the scope.</typeparam>
/// <typeparam name="TValue">The type of the values within the scope.</typeparam>
/// <param name="key">The key to check.</param>
/// <param name="value">The value to add to the scope if there is no duplicate.</param>
/// <param name="scope">The set of existing values within the scope.</param>
/// <param name="label">Diagnostic label describing <paramref name="key" />.</param>
/// <param name="scopeLabel">Diagnostic label describing <paramref name="scope" />.</param>
static <TKey, TValue> void duplicateCheck(
TKey key, TValue value, Map<TKey, TValue> scope, String label, String scopeLabel) {
if (scope.containsKey(key)) {
throw new SchemaException(lenientFormat("%s must be unique within a %s: %s", label, scopeLabel, key));
}
scope.put(key, value);
}
SchemaValidator.Visit(ns, nameDupCheck, idDupCheck);
})
/// <summary>Validate <paramref name="key" /> does appear within the given scope.</summary>
/// <typeparam name="TKey">The type of the keys within the scope.</typeparam>
/// <typeparam name="TValue">The type of the values within the scope.</typeparam>
/// <param name="key">The key to check.</param>
/// <param name="scope">The set of existing values within the scope.</param>
/// <param name="label">Diagnostic label describing <paramref name="key" />.</param>
/// <param name="scopeLabel">Diagnostic label describing <paramref name="scope" />.</param>
static <TKey, TValue> TValue exists(TKey key, Map<TKey, TValue> scope, String label, String scopeLabel) {
TValue value = scope.get(key);
if (value == null) {
throw new SchemaException(lenientFormat("%s must exist within a %s: %s", label, scopeLabel, key));
}
return value;
}
/**
* Visit an entire namespace and validate its constraints.
*
* @param ns The {@link Namespace} to validate.
* @param schemas A map from schema names within the namespace to their schemas.
* @param ids A map from schema ids within the namespace to their schemas.
*/
private static void Visit(Namespace ns, HashMap<(String, SchemaId),Schema
/**
* Visit a single schema and validate its constraints.
*
* @param s The {@link Schema} to validate.
* @param schemas A map from schema names within the namespace to their schemas.
* @param ids A map from schema ids within the namespace to their schemas.
*/
private static void Visit(Schema s, HashMap<(String, SchemaId),Schema>schemas,
private static void Visit(Property p, Schema s, HashMap<(String, SchemaId),Schema)
private static void Visit(PropertyType p, PropertyType parent, HashMap<(String, SchemaId),Schema
private static class ValidateAssert {
/**
* Validate two values are equal.
* <typeparam name="T">Type of the values to compare.</typeparam>
*
* @param left The left value to compare.
* @param right The right value to compare.
* @param message Diagnostic message if the comparison fails.
*/
public static <T> void AreEqual(T left, T right, String message) {
/// <summary>Validate two values are equal.</summary>
/// <typeparam name="T">Type of the values to compare.</typeparam>
/// <param name="left">The left value to compare.</param>
/// <param name="right">The right value to compare.</param>
/// <param name="message">Diagnostic message if the comparison fails.</param>
static <T> void areEqual(T left, T right, String message) {
if (!left.equals(right)) {
throw new SchemaException(message);
}
}
/**
* Validate <paramref name="key" /> does not already appear within the given scope.
* <typeparam name="TKey">The type of the keys within the scope.</typeparam>
* <typeparam name="TValue">The type of the values within the scope.</typeparam>
*
* @param key The key to check.
* @param value The value to add to the scope if there is no duplicate.
* @param scope The set of existing values within the scope.
* @param label Diagnostic label describing <paramref name="key" />.
* @param scopeLabel Diagnostic label describing <paramref name="scope" />.
*/
public static <TKey, TValue> void DuplicateCheck(TKey key, TValue value, HashMap<TKey, TValue> scope, String label, String scopeLabel) {
if (scope.containsKey(key)) {
throw new SchemaException(String.format("%1$s must be unique within a %2$s: %3$s", label, scopeLabel, key));
}
scope.put(key, value);
}
/**
* Validate <paramref name="key" /> does appear within the given scope.
* <typeparam name="TKey">The type of the keys within the scope.</typeparam>
* <typeparam name="TValue">The type of the values within the scope.</typeparam>
*
* @param key The key to check.
* @param scope The set of existing values within the scope.
* @param label Diagnostic label describing <paramref name="key" />.
* @param scopeLabel Diagnostic label describing <paramref name="scope" />.
*/
public static <TKey, TValue> TValue Exists(TKey key, HashMap<TKey, TValue> scope, String label, String scopeLabel) {
TValue value;
if (!(scope.containsKey(key) && (value = scope.get(key)) == value)) {
throw new SchemaException(String.format("%1$s must exist within a %2$s: %3$s", label, scopeLabel, key));
}
return value;
}
/**
* Validate a predicate is true.
*
* @param predicate The predicate to check.
* @param message Diagnostic message if the comparison fails.
*/
public static void IsTrue(boolean predicate, String message) {
/// <summary>Validate a predicate is true.</summary>
/// <param name="predicate">The predicate to check.</param>
/// <param name="message">Diagnostic message if the comparison fails.</param>
static void isTrue(boolean predicate, String message) {
if (!predicate) {
throw new SchemaException(message);
}
}
/**
* Validate <paramref name="identifier" /> contains only characters valid in a schema
* identifier.
*
* @param identifier The identifier to check.
* @param label Diagnostic label describing <paramref name="identifier" />.
*/
public static void IsValidIdentifier(String identifier, String label) {
if (tangible.StringHelper.isNullOrWhiteSpace(identifier)) {
throw new SchemaException(String.format("%1$s must be a valid identifier: %2$s", label, identifier));
/// <summary>
/// Validate <paramref name="identifier" /> contains only characters valid in a schema
/// identifier.
/// </summary>
/// <param name="identifier">The identifier to check.</param>
/// <param name="label">Diagnostic label describing <paramref name="identifier" />.</param>
static void isValidIdentifier(String identifier, String label) {
if (Strings.isNullOrEmpty(identifier)) {
throw new SchemaException(lenientFormat("%s must be a valid identifier: %s", label, identifier));
}
}
/**
* Validate <paramref name="id" /> is a valid {@link SchemaId}.
*
* @param id The id to check.
* @param label Diagnostic label describing <paramref name="id" />.
*/
public static void IsValidSchemaId(SchemaId id, String label) {
if (SchemaId.opEquals(id.clone(), SchemaId.INVALID)) {
throw new SchemaException(String.format("%1$s cannot be 0", label));
/// <summary>Validate <paramref name="id" /> is a valid <see cref="SchemaId" />.</summary>
/// <param name="id">The id to check.</param>
/// <param name="label">Diagnostic label describing <paramref name="id" />.</param>
static void isValidSchemaId(SchemaId id, String label) {
if (id == SchemaId.INVALID) {
throw new SchemaException(lenientFormat("%s cannot be 0", label));
}
}
}

View File

@@ -3,166 +3,150 @@
package com.azure.data.cosmos.serialization.hybridrow.schemas;
// TODO: DANOBLE: Fixup JSON-serialized naming for agreement with the dotnet code
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
/**
* Describes the logical type of a property.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [JsonConverter(typeof(StringEnumConverter), true)] public enum TypeKind
public enum TypeKind {
/**
* Reserved.
*/
Invalid(0),
INVALID(0),
/**
* The literal null.
* <p>
* When used as a fixed column, only a presence bit is allocated. When used as a sparse
* column, a sparse value with 0-length payload is written.
* When used as a fixed column, only a presence bit is allocated. When used as a sparse column, a sparse value with
* 0-length payload is written.
*/
Null(1),
NULL(1),
/**
* A boolean property. Boolean properties are allocated a single bit when schematized within
* a row.
* A boolean property.
* <p>
* Boolean properties are allocated a single bit when schematized within a row.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "bool")] Boolean,
Boolean(2),
BOOLEAN(2),
/**
* 8-bit signed integer.
*/
Int8(3),
INT_8(3),
/**
* 16-bit signed integer.
*/
Int16(4),
INT_16(4),
/**
* 32-bit signed integer.
*/
Int32(5),
INT_32(5),
/**
* 64-bit signed integer.
*/
Int64(6),
INT_64(6),
/**
* 8-bit unsigned integer.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "uint8")] UInt8,
UInt8(7),
UINT_8(7),
/**
* 16-bit unsigned integer.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "uint16")] UInt16,
//C# TO JAVA CONVERTER WARNING: Unsigned integer types have no direct equivalent in Java:
//ORIGINAL LINE: [EnumMember(Value = "uint16")] UInt16,
UInt16(8),
UINT_16(8),
/**
* 32-bit unsigned integer.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "uint32")] UInt32,
//C# TO JAVA CONVERTER WARNING: Unsigned integer types have no direct equivalent in Java:
//ORIGINAL LINE: [EnumMember(Value = "uint32")] UInt32,
UInt32(9),
UINT_32(9),
/**
* 64-bit unsigned integer.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "uint64")] UInt64,
//C# TO JAVA CONVERTER WARNING: Unsigned integer types have no direct equivalent in Java:
//ORIGINAL LINE: [EnumMember(Value = "uint64")] UInt64,
UInt64(10),
UINT_64(10),
/**
* Variable length encoded signed integer.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "varint")] VarInt,
VarInt(11),
VAR_INT(11),
/**
* Variable length encoded unsigned integer.
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "varuint")] VarUInt,
VarUInt(12),
VAR_UINT(12),
/**
* 32-bit IEEE 754 floating point value.
*/
Float32(13),
FLOAT_32(13),
/**
* 64-bit IEEE 754 floating point value.
*/
Float64(14),
FLOAT_64(14),
/**
* 128-bit IEEE 754-2008 floating point value.
*/
Float128(15),
FLOAT_128(15),
/**
* 128-bit floating point value. See {@link decimal}
* 128-bit floating point value.
*
* @see java.math.BigDecimal
*/
Decimal(16),
DECIMAL(16),
/**
* 64-bit date/time value in 100ns increments from C# epoch. See {@link System.DateTime}
* 64-bit date/time value in 100ns increments from C# epoch.
*
* @see java.time.OffsetDateTime
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "datetime")] DateTime,
DateTime(17),
DATE_TIME(17),
/**
* 64-bit date/time value in milliseconds increments from Unix epoch. See {@link UnixDateTime}
* 64-bit date/time value in milliseconds increments from Unix epoch.
*
* @see com.azure.data.cosmos.serialization.hybridrow.UnixDateTime
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "unixdatetime")] UnixDateTime,
UnixDateTime(18),
UNIX_DATE_TIME(18),
/**
* 128-bit globally unique identifier (in little-endian byte order).
*/
Guid(19),
GUID(19),
/**
* 12-byte MongoDB Object Identifier (in little-endian byte order).
*/
// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes:
//ORIGINAL LINE: [EnumMember(Value = "mongodbobjectid")] MongoDbObjectId,
MongoDbObjectId(20),
MONGODB_OBJECT_ID(20),
/**
* Zero to MAX_ROW_SIZE bytes encoded as UTF-8 code points.
*/
Utf8(21),
UTF_8(21),
/**
* Zero to MAX_ROW_SIZE untyped bytes.
*/
Binary(22),
BINARY(22),
/**
* An object property.
*/
Object(23),
OBJECT(23),
/**
* An array property, either typed or untyped.
*/
Array(24),
ARRAY(24),
/**
* A set property, either typed or untyped.
@@ -177,50 +161,54 @@ public enum TypeKind {
/**
* A tuple property. Tuples are typed, finite, ordered, sets.
*/
Tuple(27),
TUPLE(27),
/**
* A tagged property. Tagged properties pair one or more typed values with an API-specific uint8 type code.
* A tagged property.
* <p>
* Tagged properties pair one or more typed values with an API-specific uint8 type code.
*/
TAGGED(28),
/**
* A row with schema.
* <p>
* May define either a top-level table schema or a UDT (nested row).
*/
Schema(29),
SCHEMA(29),
/**
* An untyped sparse field.
* May only be used to define the type within a nested scope (e.g. {@link Object} or {@link Array}.
* <p>
* May only be used to define the type within a nested scope.
*/
Any(30);
ANY(30);
public static final int SIZE = java.lang.Integer.SIZE;
private static java.util.HashMap<Integer, TypeKind> mappings;
private int intValue;
public static final int BYTES = Integer.BYTES;
private static Int2ObjectMap<TypeKind> mappings;
private int value;
TypeKind(int value) {
intValue = value;
getMappings().put(value, this);
this.value = value;
mappings().put(value, this);
}
public int getValue() {
return intValue;
public int value() {
return this.value;
}
public static TypeKind forValue(int value) {
return getMappings().get(value);
public static TypeKind from(int value) {
return mappings().get(value);
}
private static java.util.HashMap<Integer, TypeKind> getMappings() {
private static Int2ObjectMap<TypeKind> mappings() {
if (mappings == null) {
synchronized (TypeKind.class) {
if (mappings == null) {
mappings = new java.util.HashMap<Integer, TypeKind>();
mappings = new Int2ObjectOpenHashMap<>();
}
}
}
return mappings;
}
}
}

View File

@@ -84,7 +84,7 @@ public class SchemaUnitTests {
Assert.AreEqual(1, n1.getSchemas().size(), "Json: {0}", json);
Assert.AreEqual("emptyTable", n1.getSchemas().get(0).getName(), "Json: {0}", json);
Assert.AreEqual(new SchemaId(-1), n1.getSchemas().get(0).getSchemaId().clone(), "Json: {0}", json);
Assert.AreEqual(TypeKind.Schema, n1.getSchemas().get(0).getType(), "Json: {0}", json);
Assert.AreEqual(TypeKind.SCHEMA, n1.getSchemas().get(0).getType(), "Json: {0}", json);
Assert.AreEqual(true, n1.getSchemas().get(0).getOptions().getDisallowUnschematized(), "Json: {0}", json);
Assert.IsNotNull(n1.getSchemas().get(0).getProperties().size(), "Json: {0}", json);
Assert.AreEqual(0, n1.getSchemas().get(0).getProperties().size(), "Json: {0}", json);
@@ -106,7 +106,7 @@ public class SchemaUnitTests {
Assert.AreEqual(1, n1.getSchemas().size(), "Json: {0}", json);
Assert.AreEqual("myUDT", n1.getSchemas().get(0).getName(), "Json: {0}", json);
Assert.AreEqual(new SchemaId(1), n1.getSchemas().get(0).getSchemaId().clone(), "Json: {0}", json);
Assert.AreEqual(TypeKind.Schema, n1.getSchemas().get(0).getType(), "Json: {0}", json);
Assert.AreEqual(TypeKind.SCHEMA, n1.getSchemas().get(0).getType(), "Json: {0}", json);
Assert.AreEqual(false, n1.getSchemas().get(0).getOptions().getDisallowUnschematized(), "Json: {0}", json);
Assert.AreEqual(2, n1.getSchemas().get(0).getProperties().size(), "Json: {0}", json);
@@ -136,8 +136,8 @@ public class SchemaUnitTests {
Storage = _Storage;
}
}
Object[] expectedProps = new Object[] { AnonymousType("a", TypeKind.Int8, StorageKind.FIXED),
AnonymousType2("b", TypeKind.Utf8, StorageKind.VARIABLE) };
Object[] expectedProps = new Object[] { AnonymousType("a", TypeKind.INT_8, StorageKind.FIXED),
AnonymousType2("b", TypeKind.UTF_8, StorageKind.VARIABLE) };
for (int i = 0; i < n1.getSchemas().get(0).getProperties().size(); i++) {
Property p = n1.getSchemas().get(0).getProperties().get(i);
@@ -448,27 +448,27 @@ public class SchemaUnitTests {
}
}
// TODO: C# TO JAVA CONVERTER: There is no Java equivalent to the C# 'dynamic' keyword:
dynamic[] expectedSchemas = { AnonymousType("{'type': 'bool', 'storage': 'fixed'}", TypeKind.Boolean),
AnonymousType2("{'type': 'int8', 'storage': 'fixed'}", TypeKind.Int8), AnonymousType3("{'type': 'int16', " +
"'storage': 'fixed'}", TypeKind.Int16), AnonymousType4("{'type': 'int32', 'storage': 'fixed'}",
TypeKind.Int32), AnonymousType5("{'type': 'int64', 'storage': 'fixed'}", TypeKind.Int64), AnonymousType6(
"{'type': 'uint8', 'storage': 'fixed'}", TypeKind.UInt8), AnonymousType7("{'type': 'uint16', " +
"'storage': 'fixed'}", TypeKind.UInt16), AnonymousType8("{'type': 'uint32', 'storage': 'fixed'}",
TypeKind.UInt32), AnonymousType9("{'type': 'uint64', 'storage': 'fixed'}", TypeKind.UInt64),
AnonymousType10("{'type': 'float32', 'storage': 'fixed'}", TypeKind.Float32), AnonymousType11("{'type': " +
"'float64', 'storage': 'fixed'}", TypeKind.Float64), AnonymousType12("{'type': 'float128', 'storage': " +
"'fixed'}", TypeKind.Float128), AnonymousType13("{'type': 'decimal', 'storage': 'fixed'}",
TypeKind.Decimal), AnonymousType14("{'type': 'datetime', 'storage': 'fixed'}", TypeKind.DateTime),
AnonymousType15("{'type': 'unixdatetime', 'storage': 'fixed'}", TypeKind.UnixDateTime), AnonymousType16(
"{'type': 'guid', 'storage': 'fixed'}", TypeKind.Guid), AnonymousType17("{'type': 'mongodbobjectid', " +
"'storage': 'fixed'}", TypeKind.MongoDbObjectId), AnonymousType18("{'type': 'varint', 'storage': " +
"'variable'}", TypeKind.VarInt), AnonymousType19("{'type': 'varuint', 'storage': 'variable'}",
TypeKind.VarUInt), AnonymousType20("{'type': 'utf8', 'storage': 'fixed', 'length': 2}", TypeKind.Utf8, 2)
, AnonymousType21("{'type': 'binary', 'storage': 'fixed', 'length': 2}", TypeKind.Binary, 2),
AnonymousType22("{'type': 'utf8', 'storage': 'variable', 'length': 100}", TypeKind.Utf8, 100),
AnonymousType23("{'type': 'binary', 'storage': 'variable', 'length': 100}", TypeKind.Binary, 100),
AnonymousType24("{'type': 'utf8', 'sparse': 'variable', 'length': 1000}", TypeKind.Utf8, 1000),
AnonymousType25("{'type': 'binary', 'sparse': 'variable', 'length': 1000}", TypeKind.Binary, 1000) };
dynamic[] expectedSchemas = { AnonymousType("{'type': 'bool', 'storage': 'fixed'}", TypeKind.BOOLEAN),
AnonymousType2("{'type': 'int8', 'storage': 'fixed'}", TypeKind.INT_8), AnonymousType3("{'type': 'int16', " +
"'storage': 'fixed'}", TypeKind.INT_16), AnonymousType4("{'type': 'int32', 'storage': 'fixed'}",
TypeKind.INT_32), AnonymousType5("{'type': 'int64', 'storage': 'fixed'}", TypeKind.INT_64), AnonymousType6(
"{'type': 'uint8', 'storage': 'fixed'}", TypeKind.UINT_8), AnonymousType7("{'type': 'uint16', " +
"'storage': 'fixed'}", TypeKind.UINT_16), AnonymousType8("{'type': 'uint32', 'storage': 'fixed'}",
TypeKind.UINT_32), AnonymousType9("{'type': 'uint64', 'storage': 'fixed'}", TypeKind.UINT_64),
AnonymousType10("{'type': 'float32', 'storage': 'fixed'}", TypeKind.FLOAT_32), AnonymousType11("{'type': " +
"'float64', 'storage': 'fixed'}", TypeKind.FLOAT_64), AnonymousType12("{'type': 'float128', 'storage': " +
"'fixed'}", TypeKind.FLOAT_128), AnonymousType13("{'type': 'decimal', 'storage': 'fixed'}",
TypeKind.DECIMAL), AnonymousType14("{'type': 'datetime', 'storage': 'fixed'}", TypeKind.DATE_TIME),
AnonymousType15("{'type': 'unixdatetime', 'storage': 'fixed'}", TypeKind.UNIX_DATE_TIME), AnonymousType16(
"{'type': 'guid', 'storage': 'fixed'}", TypeKind.GUID), AnonymousType17("{'type': 'mongodbobjectid', " +
"'storage': 'fixed'}", TypeKind.MONGODB_OBJECT_ID), AnonymousType18("{'type': 'varint', 'storage': " +
"'variable'}", TypeKind.VAR_INT), AnonymousType19("{'type': 'varuint', 'storage': 'variable'}",
TypeKind.VAR_UINT), AnonymousType20("{'type': 'utf8', 'storage': 'fixed', 'length': 2}", TypeKind.UTF_8, 2)
, AnonymousType21("{'type': 'binary', 'storage': 'fixed', 'length': 2}", TypeKind.BINARY, 2),
AnonymousType22("{'type': 'utf8', 'storage': 'variable', 'length': 100}", TypeKind.UTF_8, 100),
AnonymousType23("{'type': 'binary', 'storage': 'variable', 'length': 100}", TypeKind.BINARY, 100),
AnonymousType24("{'type': 'utf8', 'sparse': 'variable', 'length': 1000}", TypeKind.UTF_8, 1000),
AnonymousType25("{'type': 'binary', 'sparse': 'variable', 'length': 1000}", TypeKind.BINARY, 1000) };
for (dynamic expected : expectedSchemas) {
String columnSchema = String.format("{'path': 'a', 'type': %1$s", expected.Json
@@ -517,8 +517,8 @@ class AnonymousType4 {
public String Json;
public String Name;
// TODO: C# TO JAVA CONVERTER: There is no Java equivalent to the C# 'dynamic' keyword:
dynamic[] expectedSchemas = { AnonymousType("{'type': 'int8' }", TypeKind.Int8), AnonymousType2("{'type': " +
"'array', 'items': {'type': 'int32'}}", TypeKind.Int32), AnonymousType3("{'type': 'object', 'properties': " +
dynamic[] expectedSchemas = { AnonymousType("{'type': 'int8' }", TypeKind.INT_8), AnonymousType2("{'type': " +
"'array', 'items': {'type': 'int32'}}", TypeKind.INT_32), AnonymousType3("{'type': 'object', 'properties': " +
"null}", 0), AnonymousType4("{'type': 'schema', 'name': 'myUDT'}", "myUDT") };
public AnonymousType4(String _Json, String _Name) {
@@ -601,8 +601,8 @@ class AnonymousType4 {
publ TO JAVA CONVERTER TODO TASK: There is no Java equivalent to the C# 'dynamic' keyword:
dynamic[] expectedSchemas = { AnonymousType("{'path': 'b', 'type': {'type': 'int8', 'storage': 'fixed'}}",
TypeKind.Int8), AnonymousType2("{'path': 'b', 'type': {'type': 'array', 'items': {'type': 'int32'}}}",
TypeKind.Int32), AnonymousType3("{'path': 'b', 'type': {'type': 'object', 'properties': [{'path': 'c', " +
TypeKind.INT_8), AnonymousType2("{'path': 'b', 'type': {'type': 'array', 'items': {'type': 'int32'}}}",
TypeKind.INT_32), AnonymousType3("{'path': 'b', 'type': {'type': 'object', 'properties': [{'path': 'c', " +
"'type': {'type': 'bool'}}]}}", 1), AnonymousType4("{'path': 'b', 'type': {'type': 'schema', 'name': " +
"'myUDT'}}", "myUDT") };