2.0.0#26
Merged
Merged
Conversation
Adds the structura-writers module with YAML serialization support: - StructuraWriters: static API to write a Loadable to a file or generate defaults - LoadableSerializer: converts a record to YAML (kebab-case keys, nested records, collections, custom writers) - DefaultInstanceFactory: instantiates a record from @default* annotations and zero-values - CustomWriterRegistry: singleton registry for custom Writer<T> serializers - Basic test coverage for the write/saveDefault/serializer/factory paths
- LoadableSerializer now handles @options(inline=true) record flattening, standard @polymorphic (discriminator inside nested map), @polymorphic(inline=true) (discriminator at parent level), and fully-inline polymorphic (@options(inline=true) + @polymorphic(inline=true)) - useKey and isKey serialization left as TODO for next iteration - Add StructuraWriter SPI interface in core; Structura.write() and Structura.saveDefault() discover the implementation via ServiceLoader — throws StructuraException if structura-writers is absent from classpath - Add YamlStructuraWriter as the SPI provider + META-INF/services registration - Expand WriterTestModels with Animal/DbEngine polymorphic fixtures - Add inline and polymorphic unit tests to LoadableSerializerTest
Resolves the useKey TODO in the serializer: when @polymorphic(useKey = true) is declared on an interface, the discriminator value becomes the YAML key rather than a field written under a separate discriminator key. Three cases handled: - Single polymorphic field: discriminator value replaces the field name as key - List<T>: serialized as a YAML map keyed by discriminator value - Map<String, T>: concrete fields written directly under the existing map key, no redundant type discriminator injected Added ItemMeta/FoodMeta/PotionMeta fixtures and three new tests covering each of the above cases.
Records annotated with @options(isKey=true) on one of their components are now serialized as YAML maps when they appear inside a List field. The key component's value becomes the map key, and the remaining fields are written as a nested map under it. Added Permission/PermissionConfig (single non-key field) and Route/RouteConfig (multiple non-key fields) fixtures, plus two tests verifying that the key field is correctly promoted and not duplicated inside the nested map.
Optional null fields annotated with @options(optional=true) were being written as explicit nulls in YAML. They are now silently skipped, matching the reader's behaviour of treating absent keys as optional. Also adds test coverage for three previously untested paths in the serializer: @options(name=...) custom key override, enum → kebab-case conversion, and LocalDate/LocalDateTime ISO-8601 formatting. Corresponding fixtures (MixedOptionalConfig, CustomNameConfig, EnvConfig, ScheduleConfig) added to WriterTestModels.
- LoadableSerializer: handle @options(isKey=true) inside Map values — the key component is stripped from each nested field map, symmetric with the existing List behaviour. Update class Javadoc to reflect all currently supported features (was still listing useKey/isKey as TODO). - StructuraWriters.write(): create parent directories before writing so callers can pass deep paths (e.g. plugins/foo/config.yml) without having to create the directory tree themselves. - StructuraWritersTest: add polymorphic standard + inline round-trip tests (write then Structura.load and assert concrete type), a test verifying parent directory creation, and saveDefault coverage for optional fields with no @default* annotation. - WriterTestModels: add Endpoint/EndpointMapConfig for Map isKey tests and OptionalOnlyConfig for the saveDefault optional-omission test.
Move @options(isKey=true) handling from serializeCollection/serializeMap into toMap() itself via toMapWithKeyComponent(). This mirrors the approach in the parallel implementation and fixes two gaps: - Simple key (String/primitive): toMap() now returns { keyValue: {fields} } so serializeCollection() just putAll(), and serializeMap() extracts the inner value — no more manual field stripping spread across helpers. - Complex key (record type as isKey field): key sub-record fields are flattened alongside other fields at the same level. Lists of complex-key records are serialized as YAML lists (not maps) since there is no unique scalar key to distinguish entries. Also adds isPolymorphicWithUseKey() and findComponentIndex() helpers, improves the lookupRegisteredName() error message, and covers the new complex key cases with two tests + ServerCoordinates/ComplexKeyEntry fixtures.
Demonstrates the full read/write cycle in a real Paper plugin: - MainConfig — standard config with @default* and an optional field - DatabaseConfig — @polymorphic(inline=true) driver (MySQL / SQLite) - RewardsConfig — List<Reward> with @polymorphic (item/money/command) On first enable, saveDefault() generates all three config files from annotations. /mctest reload re-reads from disk, /mctest save writes the current in-memory state back, /mctest info prints all values in chat. PolymorphicRegistry setup is done once in onEnable() before any load.
saveDefault() cannot determine which concrete type to instantiate for polymorphic interface fields (DatabaseDriver, Reward). Split loadOrDefault into two helpers: loadOrSaveDefault for fully-annotated configs and loadOrWrite for configs that require an explicit fallback instance.
…cycle 5-step console demo: saveDefault, load, modify+write, round-trip verify, polymorphic backend switch (Local → S3). No Minecraft dependency.
Feat/structura writers
Restructure into published modules: - core (root) -> fr.traqueur.structura:structura-core - writer module -> fr.traqueur.structura:structura-writer - new bom module -> fr.traqueur.structura:structura-bom Build/publishing: - manual maven-publish (groupez repo) + publishAll task; example excluded from publishing - snakeyaml promoted to api (transitive), aligned to 2.6 - Gradle 8.14 -> 9.5.1, JUnit 6.1.0 + explicit junit-platform-launcher - version 1.7.0 -> 2.0.0 (coordinates changed: breaking) Writer API: - remove the static StructuraWriters facade; Structura is the sole entry point (logic folded into the YamlStructuraWriter SPI implementation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.