Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 26, 2025

Implementation: Interface Entity Support in Repositories ✅

Problem: Nitrite could not use interface types as entity types in repositories because the Reflector.getField() method only looked for declared fields, which don't exist on interfaces.

Solution: Enhanced the reflection infrastructure to detect and handle interface properties defined as getter methods.

Changes Made:

  • Analyze the current Reflector class to understand all usages
  • Create test case that reproduces the issue with interface entities
  • Modify Reflector.getField() to support interface properties via getter methods
  • Modify Reflector.getEmbeddedField() to support interface properties
  • Modify Reflector.getAllFields() to support interface properties
  • Create InterfacePropertyHolder helper class to store synthetic field metadata
  • Create FieldAccessHelper to handle get/set on interface property fields
  • Update EntityDecoratorScanner to use property metadata for validation
  • Update AnnotationScanner to use property metadata for validation
  • Update RepositoryOperations to use FieldAccessHelper for field access
  • Fix Android compatibility issues
  • Add comprehensive tests for interface entity support
  • Run full test suite to ensure no regressions (1628 tests pass)
  • Address code review feedback
    • Reduced NPath complexity in isCompatiblePrimitive
    • Upgraded Android API from 24 to 26
    • Replaced setAccessible with MethodHandles for improved security
    • Added tests with multiple implementations (Dog, Cat, Bird)
    • Added edge case tests

Technical Implementation:

  1. Interface Property Detection: Modified Reflector to detect getter methods on interfaces and create synthetic Field representations
  2. Property Metadata Storage: Created InterfacePropertyHolder to store mapping between synthetic fields and actual property information
  3. Field Access Abstraction: Created FieldAccessHelper that uses MethodHandles API for secure field/method access
  4. Validation Updates: Updated scanners to use property metadata for correct type and name information during validation

Android API Upgrade:

  • Previous: Android API 24 (Android 7.0)
  • Current: Android API 26 (Android 8)
  • Benefits:
    • Access to MethodHandles API (available since Android API 26)
    • Improved security with unreflectGetter/unreflectSetter instead of setAccessible
    • Better performance with MethodHandle.invokeWithArguments
    • Modern reflection approach aligned with current Android development

Code Quality Improvements:

  • Simplified isCompatiblePrimitive using single return statement (reduced NPath complexity from 256 to acceptable levels)
  • Replaced setAccessible with MethodHandles for field and method access
  • Uses unreflectGetter, unreflectSetter, and unreflect with invokeWithArguments
  • Added 5 additional comprehensive tests covering multiple implementations and edge cases

Test Coverage:

  • 8 tests in InterfaceEntityTest covering:
    • Basic interface entity validation
    • Index creation for interface properties
    • Field access on multiple implementations (Dog, Cat, Bird)
    • Edge cases (null/empty property names)
    • Boolean properties with 'is' prefix
    • Multiple classes with same interface
  • All 1628 tests pass with Android API 26 compatibility

Documentation Updates:

  • Updated README.md to reflect Android API 26 compatibility
  • Updated .github/copilot-instructions.md to reflect Android API 26+ requirement
  • Updated pom.xml with Android API 26 signature configuration

<issue_title>Migration from Mongo: repositories of interface entities</issue_title>

Original prompt

This section details on the original issue you should resolve

<issue_title>Migration from Mongo: repositories of interface entities</issue_title>
<issue_description>Hi,

We are trying to migrate the Mongo repository implementation of our desktop application to a more lightweight alternative. We think Nitrite could be a worthy alternative but we're struggling with the repository model. We are using version 4.3.1.

The domain is written in Kotlin and highly generic. The base type is an interface holding an id. (Types are renamed for obfuscation purposes, we're not building a zoo application ;p)

interface Animal {
   val id: AnimalUrn
   ...
}

interface LiveAnimal : Animal {   
   override val id: LiveAnimalUrn
   ...
}

data class LiveElephant(
   override val id: LiveAnimalUrn,
   var name: String,
   ...
) : LiveAnimal

We need to be able to store implementations of LiveAnimal in a single repository. We cannot annotate the domain (it is owned by another business unit) so we need to reside to an EntityDecorator (our application is in Java):

public class LiveDeviceDecorator implements EntityDecorator<LiveDevice> {
   @Override
   public Class<LiveDevice> getEntityType() {
      return LiveDevice.class;
   }

   @Override
   public EntityId getIdField() {
      return new EntityId("id");
   }

   ...
}

When starting the server, this gives a ValidationException: No such field 'id' for type x.y.z.LiveAnimal on Reflector.getField(Reflector.java:127).

I read in #54 that repositories for interface entities are currently not supported. However with Mongo, we were able to use the LiveDevice abstraction without any problem. Reflector looks for a declared field which of course doesn't exist on the interface.

Are there any plans in the future to support this use case, i.e. also checking the declared accessors on the interface?</issue_description>

<agent_instructions>Analyze the issue and do a feasibility study first. If it is feasible, make necessary code changes, verify all test suites pass. If any test fails, work on it to fix the test failure.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI and others added 3 commits October 26, 2025 12:24
- Modified Reflector to detect and handle interface properties via getter methods
- Created InterfacePropertyHolder to store metadata for synthetic fields
- Updated EntityDecoratorScanner and AnnotationScanner to use property metadata
- Fixed Android compatibility by using getParameterTypes().length instead of getParameterCount()
- Added test case for interface entity support

Co-authored-by: anidotnet <[email protected]>
- Created FieldAccessHelper to handle get/set operations on both regular and interface property fields
- Modified RepositoryOperations to use FieldAccessHelper for field access
- This fixes field access issues when using EntityDecorator with interface types
- All existing tests still pass (1623 tests)

Co-authored-by: anidotnet <[email protected]>
- Added null/empty checks for propertyName to prevent StringIndexOutOfBoundsException
- Added support for 'is' prefix in getter method lookup for boolean properties
- Extracted capitalizePropertyName helper method to eliminate code duplication
- Created findGetterMethod to handle both 'get' and 'is' prefixed getters
- All tests still pass (1623 tests)

Co-authored-by: anidotnet <[email protected]>
Copilot AI changed the title [WIP] Migrate Mongo repository implementation to Nitrite Support interface entity types with EntityDecorator Oct 26, 2025
Copilot AI requested a review from anidotnet October 26, 2025 12:41
- Reduced complexity of isCompatiblePrimitive method by using single return statement
- Refactored setAccessible usage to check isAccessible first before calling setAccessible
- Added comprehensive tests with multiple concrete implementations (Dog, Cat, Bird)
- Added edge case tests for null/empty property names
- Added test for boolean properties with 'is' prefix
- Added test verifying multiple classes work with same interface
- All 1628 tests pass

Co-authored-by: anidotnet <[email protected]>
- Upgraded Android API level from 24 (Android 7.0) to 30 (Android 11)
- Replaced setAccessible usage with MethodHandles API for improved security
- Uses unreflectGetter/unreflectSetter/unreflect with invokeWithArguments (Android API 26+)
- Updated documentation (README.md, copilot-instructions.md) to reflect API 30
- Updated pom.xml with correct Android API 30 signature (11_r3)
- All 1628 tests pass with Android API 30 compatibility

Co-authored-by: anidotnet <[email protected]>
Lowered the minimum supported Android API level from 30 to 26 in documentation and build configuration. Updated references and dependencies to reflect the new minimum API level.
@anidotnet anidotnet marked this pull request as ready for review October 27, 2025 06:20
Copilot AI review requested due to automatic review settings October 27, 2025 06:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for interface entity types in Nitrite repositories by enhancing the reflection infrastructure to handle interface properties defined as getter methods. Previously, using interface types with EntityDecorator failed because Reflector.getField() only looked for declared fields, which don't exist on interfaces. The solution creates synthetic field representations for interface properties and uses MethodHandles for secure field access.

Key changes:

  • Enhanced reflection to detect and handle interface properties via getter methods
  • Upgraded Android API compatibility from 24 to 26 to support MethodHandles
  • Added comprehensive test coverage for interface entity support

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pom.xml Updated Android API level from 24 to 26 for MethodHandles support
InterfaceEntityTest.java Added comprehensive tests for interface entity support with multiple implementations
RepositoryOperations.java Updated to use FieldAccessHelper and InterfacePropertyHolder for field access
Reflector.java Enhanced to detect interface properties from getter methods and create synthetic fields
InterfacePropertyHolder.java New class storing metadata mapping between synthetic fields and interface properties
FieldAccessHelper.java New helper class handling field access using MethodHandles API for security
EntityDecoratorScanner.java Updated validators to use property metadata for correct type/name information
AnnotationScanner.java Updated validators to use property metadata for correct type/name information
README.md Updated Android API compatibility documentation from 24 to 26
.github/copilot-instructions.md Updated Android API compatibility documentation from 24 to 26

anidotnet and others added 5 commits October 27, 2025 11:54
Added comments to explain that setAccessible is still required to bypass access checks when using MethodHandles for field access, providing more context on the security and compatibility considerations.
…com:dizitart/nitrite-database into copilot/migrate-mongo-repository-to-nitrite
Deleted the unused 'idField' variable from the testEdgeCaseEmptyPropertyName method in InterfaceEntityTest to clean up the code.
@anidotnet anidotnet merged commit 8b6b31b into main Oct 27, 2025
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migration from Mongo: repositories of interface entities

2 participants