Skip to content

cbarlin/advanced-record-utils

Repository files navigation

Advanced Record Utils

codecov Reproducible Builds Build Maven Central Version javadoc GitHub License

What is Advanced Record Utils?

Advanced Record Utils is an annotation-processor based code generator that creates a companion *Utils class (e.g., PersonUtils for a Person record) that contains:

  • A "Builder" for the record
  • A "With"er interface
  • A "Merger" utility and interface
  • An "XML" utility and interface for serialisation to XML
  • A "Diff" interface and result class
  • An "All" interface that bundles all the other interfaces together

It's configurable, and does away with a lot of boilerplate. It can also import records from libraries (in case you can't control their source code), and can work recursively down a tree of records that reference other records/interfaces.

For more details, see the documentation!

Goals, non-goals

Goals include:

  • Making working with deeply nested data structures easy
  • Moving work to compile-time where possible
  • Wrap serialisation/de-serialisation into XML and (eventually) JSON
  • JPMS support
  • Opt-in dependencies based on the settings chosen
  • Readable generated source code
  • Reproducible builds
    • The tests that get run by GitHub validate that not only our published JARs are reproducible, but that the code we generate is also reproducible too!

Secondary goals:

  • Keep the dependency tree small - some settings would either require a lot of code... or just delegate to a library that's intended for that use
  • Make generated code generate debug/trace logs where appropriate - if you are debugging something in prod at 3am, you want to be able to easily see what's happening

Non-goals:

  • Actually implement de/serialisation - delegate to a dedicated library (e.g. Java's own StAX)
  • ORM/JPA/JDO etc
  • Schema generation

Quick start

Add the following maven or gradle dependency for the annotations:

<dependency>
    <groupId>io.github.cbarlin</groupId>
    <artifactId>advanced-record-utils-annotations</artifactId>
    <version>${aru.version}</version>
</dependency>
<!-- JSpecify is included as a transitive dependency -->

And the following to your annotation processor paths (note: if using integrations with e.g. avaje-json, make sure this processor is first):

<path>
    <groupId>io.github.cbarlin</groupId>
    <artifactId>advanced-record-utils-processor</artifactId>
    <version>${aru.version}</version>
</path>

If you use java modules, you will need to add:

requires io.github.cbarlin.aru.annotations;
// No explicit 'requires org.jspecify' needed; it's re-exported transitively by the annotations module

Annotate your record like so:

@AdvancedRecordUtils
public record Person(String name, int age, List<String> favouriteColours) { }

And then you have access to a builder!

Person personA = PersonUtils.builder()
  .name("Conrad")
  .age(conradsAge)
  .addFavouriteColours("blue")
  .addFavouriteColours("purple")
  .build();
Person personB = PersonUtils.builder()
  .name("Fred")
  .favouriteColours(List.of("red", "orange"))
  .build();

For more details, see the documentation!

Where did it come from

This project was greatly inspired by Randgalt's Record Builder project, which provides a fantastic foundation for generating record builders and withers. I initially explored contributing to it, aiming to add support for fluent builders in related records. However during development, I realized that my other main need of adding mergers required a significantly different architectural approach.

Advanced Record Utils expands on the core idea of Record Builder by introducing these new features, although it does so by allowing less configuration over the features that Record Builder also has. Advanced Record Utils aims to go "wider" with features, rather than "deeper" like Record Builder has (although there is no reason that ARU can't encompass more features in the future!).

Versioning

Versioning will follow SemVer - with a major.minor.patch structure, and major pre-1 being prone to breaking external code.

Patch:

  • Bug fixes (except those that impact serialisation)
  • Dependency updates

Minor:

  • Additional features (including optional integrations)
  • Refactoring of the processor
  • Different implementations with the same external interface
  • Serialisation bug fixes
  • Added support for new types in serialisation

Major:

  • Different external interfaces
  • Changes to default settings
  • Additional required dependencies
  • Changes to generated serialisations (not just semantic changes)
    • A change to support a dependency that would change serialisations would be minor, not major

With the same settings, changing the minor or patch version of the processor should be completely transparent to a consumer, even if the code the processor generates completely changes. A major version would only be needed if the end-user would be required to change their code or if it could break items external to that consumer (e.g. serialisation). Alterations that do change "internal" implementation details are marked as "minor" as a way of flagging that, while it should externally be the same there is a non-zero risk it isn't.

Desired features:

Some of these may be quite large:

  • Avaje JSONB support (as in, generate their handlers by using Jakarta XML annotations)
    • This includes hooking into e.g. Eclipse Collection support
  • Jackson POJO builder support
  • Memoized operations (using vavr maybe?)
  • XML Deserialisation
  • Map support - the plumbing is there, just need it to be done!

Contributing

Contributions are welcome! Both in the form of raising an issue for ideas, and in the form of code! If you are going to contribute code, please read the Contributing guide as that covers how the code for the processor is designed.

Thanks to

Massive thanks to:

  • Avaje's Prism generation and SPI utils
  • Micronaut's JavaPoet fork
  • The Apache libraries

About

An annotation processor designed to assist with deeply nested record structures

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 5