dynamic-object-1.4.0
This is a major release with loads of new features:
- Fressian support has been added. Fressian is essentially binary Edn: a self-describing, extensible data encoding that offers high performance and compact output. (more)
- DynamicObject is now implemented with invokedynamic-proxy, instead of conventional reflection-based Java proxies. Benchmarking has shown that default method invocations on the latest version of DynamicObject are up to 95% faster than the previous version. Additional JMH data is available here.
- The
DynamicObject
interface now implementsjava.util.Map
by delegating to the underlying Clojure map. This makes callingDynamicObject#getMap
redundant for many use cases, and creates a migration path from maps to DynamicObjects. (Needless to say, the mutating methods likeput
will throw anUnsupportedOperationException
.) - All DynamicObject instances now implement Clojure's map interfaces, such as
IPersistentMap
. This means that a DynamicObject instance, when passed to Clojure code, looks and behaves exactly like an ordinary Clojure map. (The main exception is transient support, which has not been added.) - DynamicObject nesting no longer involves wrapping and unwrapping of Clojure maps. In previous versions, a nested DynamicObject was stored as a Clojure map in the parent hash map; now, DynamicObjects are never unwrapped. This makes type-based dispatch (e.g. for Fressian writers and pretty-printing) much more robust and reliable.
- DynamicObject's
:type
metadata has been abolished. Metadata is no longer used to controlprint-method
dispatch, or to identify unwrapped DynamicObjects. - Support for pretty-printing has been improved substantially: calling
toFormattedString
orprettyPrint
will produce machine-readable output. In previous versions, pretty-printing of DynamicObjects resulted in reader tags being dropped. (Clojure'sdefrecord
has the same problem.)
Internal changes:
- Classes that are not part of the public API have been moved to the
internal
package. This leaves a total of eight classes (two interfaces, three classes, three annotations) in the public package. - As part of the invokedynamic-proxy changes, reflection has been decoupled from invocation (1, 2, 3). The
DynamicObjectInstance
class has been introduced; this class is a de facto abstract base class for all DynamicObject types. All calls on aDynamicObject
interface (excepting static methods) now delegate to this class, according to a call site binding determined by the invocation handler. (Note that thanks to indy-proxy, methods can now be added to theDynamicObject
interface without changing the invocation handler. This is how support for theMap
interface was added.) - Reflective proxy support has been removed, and
DynamicObjectInvocationHandler
has been eliminated. Its replacement isInvokeDynamicInvocationHandler
, which only runs once per Method (i.e. on the first invocation of a given method for a given DynamicObject type). RecordPrinter
has been removed. Printing of all DynamicObject types, whether tagged or not, is now delegated toDynamicObjectPrintMethod
orDynamicObjectPrettyPrint
, both of which are defined inEdnSerialization
.- The massive
DynamicObjects
(plural) class has been broken up into the following classes:Instances
,Serialization
,EdnSerialization
, andFressianSerialization
. - The
Metadata
class has been removed. DynamicObject no longer uses metadata in its implementation. - As a matter of convention, the type variable
D
is now used for all DynamicObject types;T
is still used for type variables that do not have a DynamicObject upper bound.