Skip to content

Hibernate Accessor

What is it?

A library that provides efficient field/property access and instance creation for main Hibernate projects.

It provides a single API (AccessorFactory) with pluggable strategies for reading and writing object state and for instantiating objects via constructors.

Requires Java 17 or later.

Getting started

Add the core module to your project:

<dependency>
    <groupId>org.hibernate.accessor</groupId>
    <artifactId>hibernate-accessor</artifactId>
    <version>0.1.0.Alpha2</version>
</dependency>

The core module includes the reflection-, lambda-, and method-handle-based strategies. For the bytecode-generating strategies, add the corresponding module instead (each transitively includes the core):

<!-- ASM-based strategy -->
<dependency>
    <groupId>org.hibernate.accessor</groupId>
    <artifactId>hibernate-accessor-asm</artifactId>
    <version>0.1.0.Alpha2</version>
</dependency>

<!-- ByteBuddy-based strategy -->
<dependency>
    <groupId>org.hibernate.accessor</groupId>
    <artifactId>hibernate-accessor-bytebuddy</artifactId>
    <version>0.1.0.Alpha2</version>
</dependency>

Usage

Obtaining a factory

Built-in strategies are available via static factory methods:

// Reflection-based (simplest, no extra setup)
AccessorFactory factory = AccessorFactory.reflection();

// Method-handle-based (mostly better performance, requires a MethodHandles.Lookup)
AccessorFactory factory = AccessorFactory.methodHandle(MethodHandles.lookup());

// Lambda-based (better performance, requires a MethodHandles.Lookup)
AccessorFactory factory = AccessorFactory.lambda(MethodHandles.lookup());

// ASM-based (generates one bulk accessor class per entity with switch-based dispatch)
AccessorFactory factory = AsmAccessorFactory.factory(MethodHandles.lookup());

// ByteBuddy-based (same approach as ASM, using ByteBuddy's shaded ASM)
AccessorFactory factory = ByteBuddyAccessorFactory.factory(MethodHandles.lookup());

Reading and writing fields

Field nameField = Person.class.getDeclaredField("name");

ValueReader<?> reader = factory.valueReader(nameField);
ValueWriter writer = factory.valueWriter(nameField);

Person person = new Person();
writer.set(person, "Alice");

Object name = reader.get(person);  // "Alice"

Reading and writing via getter/setter methods

Method getter = Person.class.getDeclaredMethod("getName");
Method setter = Person.class.getDeclaredMethod("setName", String.class);

ValueReader<?> reader = factory.valueReader(getter);
ValueWriter writer = factory.valueWriter(setter);

writer.set(person, "Bob");
Object name = reader.get(person);  // "Bob"

Bulk (multi-value) access

Read or write several members in a single call. Each member may be a Field or a getter/setter Method, and values are read/written in the order the members are specified. The first argument is the concrete class whose instances will be accessed; each member must be declared on that class or one of its supertypes.

Field name = Person.class.getDeclaredField("name");
Field age = Person.class.getDeclaredField("age");

MultiValueReader reader = factory.multiValueReader(Person.class, name, age);
MultiValueWriter writer = factory.multiValueWriter(Person.class, name, age);

writer.set(person, new Object[] { "Alice", 30 });

Object[] values = reader.get(person);  // { "Alice", 30 }

For the ASM and ByteBuddy strategies this generates a single bulk accessor class per entity with TABLESWITCH dispatch, so all members are handled by one generated class.

Instantiating objects

Constructor<Person> ctor = Person.class.getDeclaredConstructor();
Instantiator<Person> instantiator = factory.instantiator(ctor);

Person person = instantiator.create();

For constructors that take arguments:

Constructor<Person> ctor = Person.class.getDeclaredConstructor(String.class, int.class);
Instantiator<Person> instantiator = factory.instantiator(ctor);

Person person = instantiator.create("Alice", 30);

Configuration

Every factory method also accepts a AccessorConfiguration, which carries the MethodHandles.Lookup along with additional properties:

AccessorConfiguration configuration = new AccessorConfiguration(
        MethodHandles.lookup(),
        Map.of(AccessorConfiguration.DUMP_BYTECODE_DIR, "build/generated-accessors")
);

AccessorFactory factory = AsmAccessorFactory.factory(configuration);

Supported properties:

Property Constant Purpose
hibernate.accessor.lookup AccessorConfiguration.LOOKUP The MethodHandles.Lookup used for access control.
hibernate.accessor.bytecode.dump.dir AccessorConfiguration.DUMP_BYTECODE_DIR Directory to dump generated bytecode to (for debugging the ASM/ByteBuddy strategies).

Strategies

Strategy Factory method Mechanism Notes
Reflection AccessorFactory.reflection() java.lang.reflect Simplest. Shared singleton instance.
Lambda AccessorFactory.lambda(lookup) LambdaMetafactory Better throughput after warm-up. Requires a MethodHandles.Lookup with appropriate access.
Method handle AccessorFactory.methodHandle(lookup) java.lang.invoke.MethodHandle Better throughput than reflection. Requires a MethodHandles.Lookup with appropriate access.
ASM AsmAccessorFactory.factory(lookup) ASM bytecode generation Generates one class per entity with TABLESWITCH dispatch on field/method index. Requires a MethodHandles.Lookup and a dependency on hibernate-accessor-asm (which brings org.ow2.asm:asm).
ByteBuddy ByteBuddyAccessorFactory.factory(lookup) ByteBuddy bytecode generation Same generated-class approach as ASM, using ByteBuddy's shaded ASM. Requires a MethodHandles.Lookup and a dependency on hibernate-accessor-bytebuddy.

About

A library that provides efficient field/property access and instance creation for main Hibernate projects

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages