Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:Improve Binder change detection #19488

Merged
merged 13 commits into from
Aug 23, 2024
Merged

Conversation

onuridrisoglu
Copy link
Contributor

Description

Fixes #19260

Type of change

  • Bugfix
  • Feature

Checklist

  • I have read the contribution guide: https://vaadin.com/docs/latest/guide/contributing/overview/
  • I have added a description following the guideline.
  • The issue is created in the corresponding repository and I have referenced it.
  • I have added tests to ensure my change is effective and works as intended.
  • New and existing tests are passing locally with my change.
  • I have performed self-review and corrected misspellings.

Additional for Feature type of change

  • Enhancement / new feature was discussed in a corresponding GitHub issue and Acceptance Criteria were created.

@CLAassistant
Copy link

CLAassistant commented May 31, 2024

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@mcollovati mcollovati added the Contribution PRs coming from the community or external to the team label May 31, 2024
Copy link

github-actions bot commented May 31, 2024

Test Results

1 132 files  ±0  1 132 suites  ±0   1h 28m 45s ⏱️ - 1m 7s
7 356 tests +3  7 306 ✅ +3  50 💤 ±0  0 ❌ ±0 
7 717 runs   - 6  7 657 ✅  - 6  60 💤 ±0  0 ❌ ±0 

Results for commit 326ebf5. ± Comparison against base commit 999db1c.

♻️ This comment has been updated with latest results.

@mshabarov mshabarov requested a review from tepi June 3, 2024 11:36
Comment on lines 1933 to 1937
protected void handleFieldValueChange(Binding<BEAN, ?> binding) {
changedBindings.add(binding);

protected void handleFieldValueChange(Binding<BEAN, ?> binding, ValueChangeEvent<?> event) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please avoid changing this method signature since it would be a breaking change and require waiting for the next major. Instead, one option could be to deprecate the current one, and if that is used, just skip the new change detection logic and function as before.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the current handleFieldValueChange back as deprecated

* @return true if the field value is reverted
*/
protected boolean isRevertedToInitialValue(Binding<BEAN, ?> binding, Object newValue) {
return Objects.equals(bindingInitialValuesMap.get(binding), newValue);
Copy link
Contributor

Choose a reason for hiding this comment

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

The logic here relies on equals of the value type being implemented properly. That is something the Binder has not required before, so it's potentially a breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, it migh make more sense to add Binding-level API for overriding the logic for checking if value is reverted. That way if custom logic is needed, one does not need to extend Binder to do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

introduced an equality predicate (I'm open for naming suggestions) that uses Objects::equals as default, but it can be overridden in binding-level

@tepi
Copy link
Contributor

tepi commented Jun 10, 2024

@mshabarov This change will introduce a slight change in behavior of Binder change tracking due to requiring equals to be implemented properly by value types. As well as reverting the tracked change if the value is reverted, which is not currently done (that is, the binding is considered as changed anyway). Do you think we'll need an enable/disable switch for this new change tracking?

@mshabarov mshabarov self-requested a review June 10, 2024 11:37
and deprecated the old handleFieldValueChange method
* @param equalityPredicate the predicate to use for equality comparison
* @return this {@code BindingBuilder}, for method chaining
*/
public BindingBuilder<BEAN, TARGET> withEqualityPredicate(SerializableBiPredicate<Object, Object> equalityPredicate);
Copy link
Contributor

Choose a reason for hiding this comment

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

Vote 4 default implementation; otherwise this is a breaking change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@onuridrisoglu onuridrisoglu marked this pull request as ready for review June 17, 2024 15:49
Copy link

sonarcloud bot commented Jun 17, 2024

Quality Gate Passed Quality Gate passed

Issues
2 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@@ -320,6 +321,8 @@ default BindingValidationStatus<TARGET> validate() {
* changes, otherwise {@literal false}.
*/
boolean hasChanges();

SerializableBiPredicate<Object, Object> getEqualityPredicate();
Copy link
Contributor

Choose a reason for hiding this comment

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

This misses Javadoc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can the type be instead TARGET (data type of the binding), not Object ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -1810,6 +1850,7 @@ void setIdentity() {

private BindingExceptionHandler exceptionHandler = new DefaultBindingExceptionHandler();

private Map<Binding<BEAN, ?>, Object> bindingInitialValuesMap = new HashMap<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

What if the initial values would be a class field in the BindingImpl instead and have a getter method in Binding? Then you can call newly added method Binding::getInitialValue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I refactored the changes and removed bindingInitialValuesMap. Now the initial value is kept in Binding level which is set during readBean.

@mshabarov
Copy link
Contributor

@mshabarov This change will introduce a slight change in behavior of Binder change tracking due to requiring equals to be implemented properly by value types. As well as reverting the tracked change if the value is reverted, which is not currently done (that is, the binding is considered as changed anyway). Do you think we'll need an enable/disable switch for this new change tracking?

I'd propose to set the equality predicate null by default (or some other value that marks it not defined), that means the change detection feature is not enabled by default. Then if this predicate is set by BindingBuilder::withEqualityPredicate, then this feature is enabled. In this way this would be backwards compatible.

onuridrisoglu and others added 2 commits August 7, 2024 12:45
- removed bindingInitialValuesMap from Binder, and kept the initial
value in binding level instead
- removed the default implementation for equalityPredicate and now this
feature will only be active if an equalityPredicate is set
@vaadin-bot vaadin-bot added +0.0.0 and removed +1.0.0 labels Aug 7, 2024
@onuridrisoglu
Copy link
Contributor Author

@mshabarov This change will introduce a slight change in behavior of Binder change tracking due to requiring equals to be implemented properly by value types. As well as reverting the tracked change if the value is reverted, which is not currently done (that is, the binding is considered as changed anyway). Do you think we'll need an enable/disable switch for this new change tracking?

I'd propose to set the equality predicate null by default (or some other value that marks it not defined), that means the change detection feature is not enabled by default. Then if this predicate is set by BindingBuilder::withEqualityPredicate, then this feature is enabled. In this way this would be backwards compatible.

I did the changes, however my only concern is now withEqualityPredicate should be called for each binding in order to activate this feature.

@mcollovati mcollovati removed the +0.0.0 label Aug 7, 2024
Copy link
Contributor

@mshabarov mshabarov left a comment

Choose a reason for hiding this comment

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

Looks good to me, but I haven't tested it.

I agree with the concern about having this API only on a binding level, would be good to allow doing the same for the whole form.

@mshabarov
Copy link
Contributor

Just discussed with @tepi, the Binder-level API could be done in a way:

  1. Adding a method on Binder's level that enables/disables usage of these predicates on bindings level.
  2. Then, if enabled, Binder will use a configured predicate for a binding, if it exists, otherwise it uses equals as a fallback. If disabled, nothing is used (default).

Copy link
Contributor

@mshabarov mshabarov left a comment

Choose a reason for hiding this comment

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

Setting to request changes

@tepi
Copy link
Contributor

tepi commented Aug 23, 2024

Just discussed with @tepi, the Binder-level API could be done in a way:

1. Adding a method on Binder's level that enables/disables usage of these predicates on bindings level.

2. Then, if enabled, Binder will use a configured predicate for a binding, if it exists, otherwise it uses `equals` as a fallback. If disabled, nothing is used (default).

@onuridrisoglu fyi, I'll pick this up and do the changes

Copy link

sonarcloud bot commented Aug 23, 2024

@mshabarov mshabarov merged commit 7973103 into main Aug 23, 2024
25 of 26 checks passed
@mshabarov mshabarov deleted the issues/19260-binder-change-detection branch August 23, 2024 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Contribution PRs coming from the community or external to the team +0.1.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Binder: Improve change detection
7 participants