Interface Encoding<T>
- Type Parameters:
T
- The associated Java type
- All Superinterfaces:
Comparator<T>
,NaturalSortAware
,Serializable
- All Known Implementing Classes:
AbstractEncoding
,ArrayEncoding
,Base64ArrayEncoding
,BigDecimalEncoding
,BigIntegerEncoding
,BitSetEncoding
,BooleanArrayEncoding
,BooleanEncoding
,ByteArrayEncoding
,ByteEncoding
,CharacterArrayEncoding
,CharacterEncoding
,Concat2Encoding
,Concat3Encoding
,Concat4Encoding
,Concat5Encoding
,ConvertedEncoding
,DateEncoding
,DoubleArrayEncoding
,DoubleEncoding
,DoubleSummaryStatisticsEncoding
,DurationEncoding
,EnumValueEncoding
,FileEncoding
,FloatArrayEncoding
,FloatEncoding
,Inet4AddressEncoding
,Inet6AddressEncoding
,InetAddressEncoding
,InstantEncoding
,IntegerArrayEncoding
,IntegerEncoding
,IntegralArrayEncoding
,IntegralEncoding
,InternetAddressEncoding
,IntSummaryStatisticsEncoding
,LocalDateEncoding
,LocalDateTimeEncoding
,LocalTimeEncoding
,LongArrayEncoding
,LongEncoding
,LongSummaryStatisticsEncoding
,MonthDayEncoding
,NullSafeEncoding
,NumberEncoding
,ObjectArrayEncoding
,ObjIdEncoding
,OffsetDateTimeEncoding
,OffsetTimeEncoding
,PatternEncoding
,PeriodEncoding
,PrimitiveEncoding
,PrimitiveWrapperEncoding
,ReferenceEncoding
,ShortArrayEncoding
,ShortEncoding
,StringConvertedEncoding
,StringEncoding
,Tuple2Encoding
,Tuple3Encoding
,Tuple4Encoding
,Tuple5Encoding
,TupleEncoding
,UnsignedIntEncoding
,URIEncoding
,UUIDEncoding
,VoidEncoding
,YearEncoding
,YearMonthEncoding
,ZonedDateTimeEncoding
,ZoneIdEncoding
,ZoneOffsetEncoding
Encoding
's are used to map between instances of some Java type and the byte[]
encodings of those instances
stored in a Permazen database. The byte[]
encoding defines the database sort order (via unsigned lexicographical
ordering), and this same ordering is reflected in Java via compare()
.
An Encoding
also defines a mapping between Java instances and String
values.
Instances may have an associated EncodingId
, which is a globally unique URN-style identifier that allows the encoding
to be referred to by name (e.g., in an EncodingRegistry
). Encodings with no EncodingId
are called anonymous.
Encoding
s must satsify these requirements:
- Instances have an associated Java type which can represent any of the encoding's supported values. However, an encoding
is not required to support every instance of the Java type. For example, there can be an encoding of
Integer
that only supports non-negative values. - Instances totally order their supported Java values via
compare()
. If the associated Java type itself implementsComparable
, then the two orderings do not necessarily have to agree, but they should if possible. In that case,NaturalSortAware.sortsNaturally()
should return true. null
may or may not be a supported value; seesupportsNull()
. If so, it must be fully supported value just like any other; for example, it must be handled bycompare()
(typically null values sort last). Note that this is an additional requirement beyond whatComparator
strictly requires.- There is a default value. For types that support null, the default value must be null,
and for types that don't support null, obviously the default value must not be null; however, an exception can be made
for encodings that don't support null but don't need default values, e.g., anonymous encodings that are always wrapped
within a
NullSafeEncoding
. - All non-null values can be encoded/decoded into a
String
without losing information; seetoString()
andfromString()
. - All values, including null if supported, can be encoded/decoded into a self-delimiting binary string (i.e.,
byte[]
array) without losing information. Moreover, these binary strings, when sorted lexicographically using unsigned comparison, sort consistently with the encoding's total ordering of the corresponding Java values; seeread()
andwrite()
. - An
Encoding
's string and binary encodings and sort ordering is guaranteed to never change, unless theEncodingId
is also changed, which effectvely defines a new encoding. However, in such scenarios automatic schema migrations are easily handled by adding appropriate logic toconvert()
.
Two Encoding
instances should be equal according to equals()
only when they behave identically
with respect to all of the above.
Instances must be stateless (and therefore also thread safe).
- See Also:
-
Field Summary
Modifier and TypeFieldDescriptionstatic final int
The maximum number of supported array dimensions (255). -
Method Summary
Modifier and TypeMethodDescriptionint
Order two values.default <S> T
default T
decode
(byte[] bytes) Decode a valid from the givenbyte[]
array.default byte[]
Encode the given value into abyte[]
array.fromString
(String string) Parse a non-null value previously encoded bytoString(T)
.Get the default value for this encoding.default byte[]
Get the default value for this encoding encoded as abyte[]
array.Get the globally unique encoding ID that identifies this encoding, if any.Get the fixed width of this encoding, if any.default KeyRange
getKeyRange
(Bounds<? extends T> bounds) Calculate theKeyRange
that includes exactly those encoded values that lie within the given bounds.Get the Java type corresponding to this encoding's values.boolean
Determine whether any of this encoding's encoded values start with a0x00
byte.boolean
Determine whether any of this encoding's encoded values start with a0xff
byte.read
(ByteReader reader) Read a value from the given input.void
skip
(ByteReader reader) Read and discard abyte[]
encoded value from the given input.boolean
Determine whether this encoding supports null values.Encode a non-null value as aString
for later decoding byfromString()
.default T
Verify the given object is a valid instance of thisEncoding
's Java type and cast it to that type.default void
validateAndWrite
(ByteWriter writer, Object obj) Convenience method that both validates and encodes a value.void
write
(ByteWriter writer, T value) Write a value to the given output.Methods inherited from interface java.util.Comparator
equals, reversed, thenComparing, thenComparing, thenComparing, thenComparingDouble, thenComparingInt, thenComparingLong
Methods inherited from interface io.permazen.util.NaturalSortAware
sortsNaturally
-
Field Details
-
MAX_ARRAY_DIMENSIONS
static final int MAX_ARRAY_DIMENSIONSThe maximum number of supported array dimensions (255).- See Also:
-
-
Method Details
-
getEncodingId
EncodingId getEncodingId()Get the globally unique encoding ID that identifies this encoding, if any.Once associated with a specific encoding, an encoding ID must never be changed or reused. If an
Encoding
's encoding changes in any way, then its encoding ID must also change. This applies only to the encoding itself, and not the associated Java type. For example, anEncoding
's associated Java type can change over time, e.g., if the Java class changes package or class name.- Returns:
- this encoding's unique ID, or null if this encoding is anonymous
-
getTypeToken
Get the Java type corresponding to this encoding's values.- Returns:
- the Java type used to represent this encoding's values
-
read
Read a value from the given input.- Parameters:
reader
- byte input- Returns:
- decoded value (possibly null)
- Throws:
IllegalArgumentException
- if invalid input is encounteredIndexOutOfBoundsException
- if input is truncatedIllegalArgumentException
- ifreader
is null
-
write
Write a value to the given output.- Parameters:
writer
- byte outputvalue
- value to write (possibly null)- Throws:
IllegalArgumentException
- ifvalue
is null and this encoding does not support nullIllegalArgumentException
- ifwriter
is null
-
getDefaultValueBytes
default byte[] getDefaultValueBytes()Get the default value for this encoding encoded as abyte[]
array.The implementation in
Encoding
returns the binary encoding of the value returned bygetDefaultValue()
.- Returns:
- encoded default value
- Throws:
UnsupportedOperationException
- if this encoding does not have a default value
-
getDefaultValue
T getDefaultValue()Get the default value for this encoding.If this encoding supports null values, then this must return null.
- Returns:
- default value
- Throws:
UnsupportedOperationException
- if this encoding does not have a default value
-
skip
Read and discard abyte[]
encoded value from the given input.If the value skipped over is invalid, this method may, but is not required to, throw
IllegalArgumentException
.If the value skipped over is truncated, this method must throw
IndexOutOfBoundsException
.- Parameters:
reader
- byte input- Throws:
IllegalArgumentException
- if invalid input is encounteredIndexOutOfBoundsException
- if input is truncatedIllegalArgumentException
- ifreader
is null
-
toString
Encode a non-null value as aString
for later decoding byfromString()
.Each of the characters in the returned
String
, when decoded as 32-bit Unicode codepoints, must contain only valid XML characters (seeXMLUtil.isValidChar(int)
).- Parameters:
value
- actual value, never null- Returns:
- string encoding of
value
acceptable tofromString()
- Throws:
IllegalArgumentException
- ifvalue
is null- See Also:
-
fromString
Parse a non-null value previously encoded bytoString(T)
.- Parameters:
string
- non-null value previously encoded as aString
bytoString(T)
- Returns:
- actual value
- Throws:
IllegalArgumentException
- if the input is invalidIllegalArgumentException
- ifstring
is null
-
convert
Attempt to convert a value from the givenEncoding
into a value of thisEncoding
.For a non-null
value
, the implementation inEncoding
first checks whether thevalue
is already a valid value for this encoding; if so, the value is returned. Otherwise, it invokesencoding.
toString(value)
to convertvalue
into aString
, and then attempts to parse that string viathis.
fromString()
; if the parse fails, anIllegalArgumentException
is thrown. Note this means that any value will convert successfully to aString
, as long as it doesn't contain an invalid escape sequence (seeStringEncoding.toString(java.lang.String)
).If
value
is null, the implementation inEncoding
returns null, unless this encoding does not support null values, in which case anIllegalArgumentException
is thrown.Permazen's built-in encodings include the following conversions:
- Non-boolean Primitive types:
- Convert from other non-boolean primitive types as if by the corresponding Java cast
- Convert from boolean by converting to zero (if false) or one (if true)
- Boolean: converts from other primitive types as if by
value != 0
- A
char[]
array and aString
are convertible to each other - A
char
and aString
of length one are convertible to each other (otherString
s are not) - Arrays: converted by converting each array element individually (if possible)
- Type Parameters:
S
- source encoding- Parameters:
encoding
- theEncoding
ofvalue
value
- the value to convert- Returns:
value
converted to this instance's type- Throws:
IllegalArgumentException
- if the conversion fails
- Non-boolean Primitive types:
-
validate
Verify the given object is a valid instance of thisEncoding
's Java type and cast it to that type.Note that this method must throw
IllegalArgumentException
, notClassCastException
orNullPointerException
, ifobj
does not have the correct type, or is an unsupported value - including null if null is not supported.This method is allowed to perform widening conversions of the object that lose no information, e.g., from
Integer
toLong
.The implementation in
Encoding
first verifies the value is not null if this instance does not allow null values, and then attempts to cast the value using this instance's raw Java type. Subclasses should override this method to implement any other restrictions.- Parameters:
obj
- object to validate- Returns:
obj
cast to this encoding's type- Throws:
IllegalArgumentException
- ifobj
in not of type TIllegalArgumentException
- ifobj
is null and this encoding does not support null valuesIllegalArgumentException
- ifobj
is in any other way not supported by thisEncoding
-
compare
Order two values.This method must provide a total ordering of all supported Java values that is consistent with the database ordering, i.e., the unsigned lexicographical ordering of the corresponding
byte[]
encoded values.If null is a supported Java value, then the this method must accept null parameters without throwing an exception (note, this is a stronger requirement than the
Comparator
interface normally requires).Note: by convention, null values usually sort last.
- Specified by:
compare
in interfaceComparator<T>
- Throws:
IllegalArgumentException
- ifvalue1
orvalue2
is null and this encoding does not support null
-
supportsNull
boolean supportsNull()Determine whether this encoding supports null values.- Returns:
- true if null is a valid value, otherwise false
-
hasPrefix0x00
boolean hasPrefix0x00()Determine whether any of this encoding's encoded values start with a0x00
byte. Certain optimizations are possible when this is not the case. It is safe for this method to always return true.Note: changing the result of this method may result in an incompatible encoding if this encoding is wrapped in another class.
- Returns:
- true if an encoded value starting with
0x00
exists
-
hasPrefix0xff
boolean hasPrefix0xff()Determine whether any of this encoding's encoded values start with a0xff
byte. Certain optimizations are possible when this is not the case. It is safe for this method to always return true.Note: changing the result of this method may result in an incompatible encoding if this encoding is wrapped in another class.
- Returns:
- true if an encoded value starting with
0xff
exists
-
getFixedWidth
OptionalInt getFixedWidth()Get the fixed width of this encoding, if any.Some encodings encode every value into the same number of bytes. For such encodings, this method returns that number. For variable width encodings, this method must return empty.
- Returns:
- the number of bytes of every encoded value, or empty if the encoding length varies
-
validateAndWrite
Convenience method that both validates and encodes a value.Equivalent to:
this.write(writer, this.validate(obj))
- Parameters:
writer
- byte outputobj
- object to validate- Throws:
IllegalArgumentException
- ifobj
in not of type TIllegalArgumentException
- ifobj
is null and this encoding does not support null valuesIllegalArgumentException
- ifobj
is in any other way not supported by thisEncoding
IllegalArgumentException
- ifwriter
is null
-
getKeyRange
Calculate theKeyRange
that includes exactly those encoded values that lie within the given bounds.- Parameters:
bounds
- bounds to impose- Returns:
KeyRange
corresponding tobounds
- Throws:
IllegalArgumentException
- ifbounds
is null
-
encode
Encode the given value into abyte[]
array.The implementation in
Encoding
creates a temporaryByteWriter
and then delegates towrite()
.- Parameters:
value
- value to encode, possibly null- Returns:
- encoded value
- Throws:
IllegalArgumentException
- ifobj
is invalid
-
decode
Decode a valid from the givenbyte[]
array.The implementation in
Encoding
creates a temporaryByteReader
and then delegates toread()
.- Parameters:
bytes
- encoded value- Returns:
- decoded value, possibly null
- Throws:
IllegalArgumentException
- ifbytes
is null, invalid, or contains trailing garbage
-