[ 
https://issues.apache.org/jira/browse/TAP5-2833?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ben Weidig reassigned TAP5-2833:
--------------------------------

    Assignee: Ben Weidig

> SelectModel should adopt upper-bounded wildcards for option collections
> -----------------------------------------------------------------------
>
>                 Key: TAP5-2833
>                 URL: https://issues.apache.org/jira/browse/TAP5-2833
>             Project: Tapestry 5
>          Issue Type: Improvement
>          Components: tapestry-core
>            Reporter: Ben Weidig
>            Assignee: Ben Weidig
>            Priority: Minor
>
> h2. Description
> {{SelectModel}} is used to implement domain-specific custom classes that 
> implement {{OptionModel}} or {{OptionGroupModel}}.
> However, due to Java's generic type invariance, passing collections of these 
> custom implementations (e.g., {{List<MyCustomOptionModel>}}) directly to 
> standard {{SelectModel}} constructors, factories, or builders is blocked by 
> the compiler.
> This forces developers to write tedious boilerplate code (such as 
> stream-mapping or copying arrays) to upcast their collections to 
> {{List<OptionModel>}} purely to satisfy the compiler type-checks.
> We can significantly improve developer ergonomics and framework usability by 
> modifying input parameter signatures across the selection APIs to adopt 
> upper-bounded wildcards (e.g., {{List<? extends OptionModel>}}).
> Furthermore, {{SelectModel.getOptions()}} should become a {{default}} method 
> returning {{null}}, as flat selects are by far the most common use case on 
> the web.
> h3. Functional Improvement
> * Eliminate redundant collection-copying boilerplate at call sites when 
> working with custom implementation lists.
> * Align Tapestry's internal model instantiation APIs with established Java 
> Generics design principles ("PECS", Producer Extends, Consumer Super).
> * Simplify {{SelectModel}} implementations by removing repetive {{null}} 
> value for groups.
> h2. Technical Tasks / Proposed Solution
> # *Relax Constructor Signatures*: Update concrete constructors (such as 
> {{SelectModelImpl}}) to accept wildcards:
> ** Change {{List<OptionGroupModel>}} to {{List<? extends OptionGroupModel>}}
> ** Change {{List<OptionModel>}} to {{List<? extends OptionModel>}}
> # *Relax Utility/Factory Signatures*: Apply the same change to any framework 
> helper/factory methods (such as {{SelectModelFactory}}) that consume 
> collections to build selection models.
> # *Add default method*: Return {{null}}
> h2. Why the Change?
> * *Framework Ergonomics*: Developers should be able to supply a collection of 
> any type implementing {{OptionModel}} directly to a select model without 
> manual type conversion. Not needing to implement the same "no groups" method 
> repeatedly simplifies the required code.
> * *PECS Best Practice*: Because these constructors and factories only read 
> (produce) elements from the provided lists to populate UI components, the 
> collections can safely be parameterized with {{? extends}}, which relaxes 
> caller constraints without compromising safety.
> h2. Risks / Breaking Changes (Downstream Perspective)
> h3. Method Overrides in Subclasses (Source-Breaking Change)
> *Risk Level*: Low-to-Medium
> If downstream developers have extended concrete classes (such as 
> {{SelectModelImpl}} or custom helper components) and overridden setter 
> methods, changing those parameter signatures in the parent class will break 
> compilation in the subclass.
> In Java, parameter types in overridden methods must match exactly.
> *Mitigation*: Ensure the change is documented in the release notes and 
> communicated on the mailing lists so developers can update overridden method 
> signatures in their custom subclasses to match the wildcards.
> h3. Modifying Interface Return Types (High Risk - Strongly Discouraged)
> *Risk Level*: High (if return types are changed)
> If the return types of core interface methods (such as 
> {{SelectModel.getOptions()}} or {{OptionGroupModel.getOptions()}}) are 
> changed from {{List<OptionModel>}} to {{List<? extends OptionModel>}}, it 
> will cause immediate compilation errors for any downstream consumer assigning 
> the result to a strict {{List<OptionModel>}} variable.
> *Mitigation*: Keep the wildcard relaxation restricted strictly to *input 
> parameters* (constructors, setters, and factory inputs). Do not change the 
> return types of the getters on public interfaces, preserving backward 
> compatibility for existing consumers.
> h3. Binary Compatibility
> *Risk Level*: None
> Due to Java's type erasure, {{List<OptionModel>}} and {{List<? extends 
> OptionModel>}} both erase to raw {{java.util.List}} at runtime.
> Existing pre-compiled binaries and compiled third-party modules running 
> against this updated version will link and execute successfully without 
> throwing {{NoSuchMethodError}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to