Dynamics
Java library for handling nested dynamic data
Install / Use
/learn @alexheretic/DynamicsREADME
Dynamics

Dynamics is a Java library for handling nested weakly-typed data in a fluent and null-safe way.
Initially developed to help handle JSON and XML messages in a direct way without tedious and repetitive null checking, type conversion & casting. It has become a powerful & productive way of directly dealing with dynamic data without the horribleness that can typically involve.
Weakly-Typed Nested Data Structure Handling
Map nestedMap = ...
// {product={investment={investment-1=12345.33, investment-2=43213.44}, effective=2015-03-07T00:35:11}}
Dynamic.from(nestedMap)
.get("product")
.get("effective")
.convert().intoLocalDateTime(); // java.time.LocalDateTime 2015-03-07T00:35:11
In Detail
An alexh.weak.Dynamic object is a weakly-typed, possible nested structure that allows null-safe child selection, creating the Dynamic wrapper is easy
Dynamic message = Dynamic.from(nestedMap);
Each 'get' call returns a non-null Dynamic instance that represents the child with that key, or the key's absence. Finally the wrapped object target can be accessed with asObject(), or as(Class) to cast.
Dynamic investment1 = message.get("product").get("investment").get("investment-1"); // null & exception safe
investment1.isPresent(); // true
investment1.as(BigDecimal.class); // 12345.33, assuming it is a BigDecimal
This allows a single call to isPresent() to indicate if the required value exists.
message.get("product").get("one").get("two").get("three").get("four").isPresent(); // false
With String keys we can fetch deeply in a single get call by splitting the string into multiple gets and supplying a splitter string. In addition to isPresent() method a Dynamic my be unpacked into an Optional with asOptional() or can be wrapped into an OptionalWeak and handled fluently with maybe()
message.get("product.investment.investment-2", ".").maybe().as(BigDecimal.class);
// Optional[43213.44]
For '.' character splitting Dynamic#dget(String) method is supplied for convenience
message.dget("product.investment.investment-2").maybe().as(BigDecimal.class);
// Optional[43213.44]
Error Describing
Dynamic instances throw descriptive exceptions when data is missing, or not as selected.
// exception message:
// "'holdings' key is missing in path root->product->*holdings*->foo->bar,
// available root->product: Map[effective, investment]"
message.dget("product.holdings.foo.bar").asObject(); // throws
Type Conversion
Aiding permissive reading (desired in servers consuming external messages) Dynamics provides common usage type runtime conversions with the alexh.weak.Converter class.
Converter.convert("1234.4321").intoDecimal(); // BigDecimal 1234.4321
Converter.convert(1234.4321d).intoDecimal(); // BigDecimal 1234.4321 (approx)
Usage is also built into Dynamic instances.
message.get("product").get("effective").convert().intoLocalDateTime();
// LocalDateTime of 2015-03-07T00:35:11
message.get("product").get("effective").maybe().convert().intoLocalDateTime();
// Optional<LocalDateTime>[2015-03-07T00:35:11]
XML Dynamics
XML documents can be wrapped in an XmlDynamic which acts like a normal dynamic with string keys & values but with some special features
<product>
<investment id="inv-1">
<info>
<current>
<name>some name</name>
</current>
</info>
</investment>
<investment id="inv-2" />
</product>
We can select the nested 'name' element value just like a normal Dynamic
Dynamic xml = new XmlDynamic(xmlMessage); // 'xmlMessage' is a string of the above xml
xml.get("product.investment.info.current.name", ".").asString(); // "some name"
Also since XML has certain key name restrictions the pipe character '|' can be used as a splitter without declaration
xml.get("product|investment|info|current|name").asString(); // "some name"
Attributes can be accessed in exactly the same way as elements, or explicitly
xml.get("product|investment|id").asString(); // "inv-1"
xml.get("product|investment|@id").asString(); // "inv-1"
Multiple child elements with the same local-name effectively have [i] appended to them where i is their index
xml.get("product|investment|id").asString(); // "inv-1"
xml.get("product|investment[0]|id").asString(); // "inv-1"
xml.get("product|investment[1]|id").asString(); // "inv-2"
Namespaces are ignored by default, but can be used explicitly using the "::" key separator
<ex:product xmlns:ex="http://example.com/example">
<message>hello</message>
</ex:product>
xmlWithNamespaces.get("product|message").asString();
xmlWithNamespaces.get("http://example.com/example::product|none::message").asString();
// both return "hello"
<br/>
Dynamics is licensed under the Apache 2.0 licence.
Releases
4.0 is the latest release, available at maven central. Requiring JDK 1.8 or later.
<dependency>
<groupId>com.github.alexheretic</groupId>
<artifactId>dynamics</artifactId>
<version>4.0</version>
</dependency>
Changelog
Release 4.x
- Add enhanced ClassCastException messages
Release 3.x
- Add Dynamic#allChildren(), #allChildrenDepthFirst(), #allChildrenBreadthFirst() deep child streaming
- Add XmlDynamic.hasElementName(String) namespace support
- 3.1
- Prevent rare XmlDynamic thread safety issues
Release 2.x
java.util.Collectioninstance support, ie Sets now have children- Minor format change to error messages
- 2.1
- Fix conversions of some zoned iso strings into
ZonedDateTimeinstances
- Fix conversions of some zoned iso strings into
- 2.2
- Improve
java.sql.Timestampstyle toString date times to properly convert with nanosecond accuracy
- Improve
- 2.3
- Fix thread-safety issue with XmlDynamic#children() traversal
Related Skills
node-connect
347.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.6kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
