Skip to content

javagen: Enforce typing constraints for refined inherited slots.#3589

Open
gouttegd wants to merge 4 commits into
linkml:mainfrom
gouttegd:refined-specialised-slots
Open

javagen: Enforce typing constraints for refined inherited slots.#3589
gouttegd wants to merge 4 commits into
linkml:mainfrom
gouttegd:refined-specialised-slots

Conversation

@gouttegd

@gouttegd gouttegd commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #3530

This PR updates the Java code generator so that it can generate code that can correctly deal with the case of “refined inherited slots”.

It does that in three steps:

(A) First, the OOCodeGen class is augmented with a get_refined_ranges method that allows to query, for a given slot in a given class:

  • whether the class is refining the range of the slot compared to its parent class (with parameter upwards=True), and if so, to obtain the list of successive refinements that occurs in the ancestor hierarchy (up to the first class that originally defines the slot);
  • whether the slot is refined in any subclass (with parameter upwards=False), and if so, to obtain the list of refinements that occurs in all subclasses (down to the leaf classes of the class tree).

(B) The OOField class, representing a field in a class, is augmented with an additional member variable named refined_ranges. When the field is an inherited field, that variable is set with the list of refinements as obtained with get_refined_ranges(upwards=True). This provides the code templates with a way to know whether an inherited field (which would normally be completely ignored by the Java code generator, since it has been dealt with when the code for the parent class that defines it has been generated) is being refined in the current class and therefore requires special treatment.

(C) Lastly, the org.incenp.linkml template variant is updated to use the new features provided by OOCodeGen to generate suitable accessors that can enforce the type constraints of any refined inherited slot. For single-valued slot, the generated code follows the idea presented in the original comment of issue #3530. For multi-valued slots, it follows the idea presented in this comment.

How was this tested?

Unit tests have been added to the existing test_javagen.py module to cover parts (A) and (B) described above.

The actual code generation part (C) has been tested as part of the LinkML-Java runtime (gouttegd/linkml-java#2).

Areas of uncertainty

If any Java expert has a better idea for how to deal with multivalued refined inherited slots – in particular, an idea that does not involve wildcard generics –, I am all ears.

Checklist

  • My code follows the contributor guidelines
  • I have added tests that prove my fix/feature works
  • Existing tests pass locally with my changes

AI Assistance

None.

@gouttegd gouttegd self-assigned this May 29, 2026
When a class "refines" (through `slot_usage`) the range of a slot that
it has inherited from a parent class, code generators might need to know
how the slot was refined -- that is, instead of having just the
effective refined range, the generators might need to know the range(s)
the slot was refined from.

(The Java generator will need that information very soon.)

So this commit adds a new field to the `OOField` object called
`refined_ranges`, intended to hold the list of successively refined
ranges.
@gouttegd gouttegd force-pushed the refined-specialised-slots branch from 81fcc66 to eeb8d74 Compare May 29, 2026 15:37
@codecov

codecov Bot commented May 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.69767% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.60%. Comparing base (f9798a5) to head (bd00163).

Files with missing lines Patch % Lines
packages/linkml/src/linkml/generators/oocodegen.py 90.69% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3589      +/-   ##
==========================================
+ Coverage   80.18%   83.60%   +3.41%     
==========================================
  Files         157      157              
  Lines       18687    18709      +22     
  Branches     3939     3944       +5     
==========================================
+ Hits        14984    15641     +657     
+ Misses       2868     2185     -683     
- Partials      835      883      +48     
Flag Coverage Δ
linkml 80.18% <90.69%> (+0.01%) ⬆️
runtime 80.14% <90.69%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Add a boolean parameter to the `OOCodeGen._get_refined_ranges()` method
to specify the direction to follow when walking the inheritance tree.

That is, the method can now be used for both

(1) getting all the range refinements that may have occurred "above" the
class we are looking at (in parent classes; `upwards=True`), or

(2) getting all the range refinements that may occur "below" the class
we are looking at (in subclasses; `upwards=False`).

The Java code generator will need to do both.

The method is also renamed to `get_refined_ranges()` (no leading
underscore), because its use is no longer intended to be restricted to
within the OOCodeGen class.

commit e5bc2a117ac98cbd00c104ed11f75d615a7fb112
Author: Damien Goutte-Gattat <damien@gerbi-gmb.de>
Date:   Mon Jun 1 12:45:52 2026 +0100

    WIP
This commit updates the `org.incenp.linkml` template variant for the
Java code generator so that it will generate code that can correctly
deal with the case of "refined inherited slots" (when a class refines
the range of a slot that it inherited from a parent).

See embedded comments in the template, and comments on issue
linkml#3530, for details about the
logic the generated code implements. For single-valued slots, it is
reasonably straightforward (and completely type-safe). For multivalued
slots, it is alas not so straightforward, and still leaves the
possibility that the code can be used in a non-type-safe manner (but
this requires explicit casting on the part of the client code, so it
cannot happen inadvertently).
@gouttegd gouttegd force-pushed the refined-specialised-slots branch from 1fde5b8 to 889ebeb Compare June 2, 2026 16:46
@gouttegd gouttegd marked this pull request as ready for review June 2, 2026 16:57
@gouttegd gouttegd requested review from kevinschaper and matentzn June 2, 2026 17:06
@matentzn matentzn removed their request for review June 3, 2026 15:58
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.

Generated Java code does not enforce refined type constraints

2 participants