-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[pigeon] Fixes support for Kotlin/Java classes that override equals and hashCode for ProxyApis #10039
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
Merged
Merged
[pigeon] Fixes support for Kotlin/Java classes that override equals and hashCode for ProxyApis #10039
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
c828fff
override fix
bparrishMines 3300041
add log and version bump
bparrishMines dcb38bc
Merge branch 'main' of github.com:flutter/packages into pigeon_overri…
bparrishMines 6d21fdd
better solution for equality
bparrishMines c369826
Merge branch 'main' of github.com:flutter/packages into pigeon_overri…
bparrishMines b4fa524
fix pigeonVersion
bparrishMines 3508c81
switch to identity hash code
bparrishMines 906b638
Merge branch 'main' of github.com:flutter/packages into pigeon_overri…
bparrishMines 39db552
use a shared weakreference object
bparrishMines 2e7258f
resort to using the saved hashcode and using the actual instance
bparrishMines b36e36c
Merge branch 'main' of github.com:flutter/packages into pigeon_overri…
bparrishMines 643f547
add tests for class
bparrishMines e10b405
another test and more docs
bparrishMines 38efe0f
Merge branch 'main' of github.com:flutter/packages into pigeon_overri…
bparrishMines f33dd17
create a local method for logging
bparrishMines File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -42,11 +42,39 @@ class ${kotlinInstanceManagerClassName(options)}(private val finalizationListene | |||||||||||||
| fun onFinalize(identifier: Long) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private val identifiers = java.util.WeakHashMap<Any, Long>() | ||||||||||||||
| private val weakInstances = HashMap<Long, java.lang.ref.WeakReference<Any>>() | ||||||||||||||
| // Extends WeakReference and overrides the `equals` and `hashCode` methods using identity rather | ||||||||||||||
| // than equality. | ||||||||||||||
| // | ||||||||||||||
| // Two `IdentityWeakReference`s are equal if either | ||||||||||||||
| // 1: `get()` returns the identical nonnull value for both references. | ||||||||||||||
| // 2: `get()` returns null for both references and the references are identical. | ||||||||||||||
| class IdentityWeakReference<T : Any> : java.lang.ref.WeakReference<T> { | ||||||||||||||
| private val savedHashCode: Int | ||||||||||||||
|
|
||||||||||||||
| constructor(instance: T) : this(instance, null) | ||||||||||||||
|
|
||||||||||||||
| constructor(instance: T, queue: java.lang.ref.ReferenceQueue<T>?) : super(instance, queue) { | ||||||||||||||
| savedHashCode = System.identityHashCode(instance) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| override fun equals(other: Any?): Boolean { | ||||||||||||||
| val instance = get() | ||||||||||||||
| if (instance != null) { | ||||||||||||||
| return other is IdentityWeakReference<*> && other.get() === instance | ||||||||||||||
| } | ||||||||||||||
| return other === this | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| override fun hashCode(): Int { | ||||||||||||||
| return savedHashCode | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+68
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
The correct approach is to use
Suggested change
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private val identifiers = java.util.WeakHashMap<IdentityWeakReference<Any>, Long>() | ||||||||||||||
| private val weakInstances = HashMap<Long, IdentityWeakReference<Any>>() | ||||||||||||||
| private val strongInstances = HashMap<Long, Any>() | ||||||||||||||
| private val referenceQueue = java.lang.ref.ReferenceQueue<Any>() | ||||||||||||||
| private val weakReferencesToIdentifiers = HashMap<java.lang.ref.WeakReference<Any>, Long>() | ||||||||||||||
| private val weakReferencesToIdentifiers = HashMap<IdentityWeakReference<Any>, Long>() | ||||||||||||||
| private val handler = android.os.Handler(android.os.Looper.getMainLooper()) | ||||||||||||||
| private val releaseAllFinalizedInstancesRunnable = Runnable { | ||||||||||||||
| this.releaseAllFinalizedInstances() | ||||||||||||||
|
|
@@ -112,9 +140,12 @@ class ${kotlinInstanceManagerClassName(options)}(private val finalizationListene | |||||||||||||
| */ | ||||||||||||||
| fun getIdentifierForStrongReference(instance: Any?): Long? { | ||||||||||||||
| logWarningIfFinalizationListenerHasStopped() | ||||||||||||||
| val identifier = identifiers[instance] | ||||||||||||||
| if (instance == null) { | ||||||||||||||
| return null | ||||||||||||||
| } | ||||||||||||||
| val identifier = identifiers[IdentityWeakReference(instance)] | ||||||||||||||
| if (identifier != null) { | ||||||||||||||
| strongInstances[identifier] = instance!! | ||||||||||||||
| strongInstances[identifier] = instance | ||||||||||||||
| } | ||||||||||||||
| return identifier | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -151,14 +182,14 @@ class ${kotlinInstanceManagerClassName(options)}(private val finalizationListene | |||||||||||||
| /** Retrieves the instance associated with identifier, if present, otherwise `null`. */ | ||||||||||||||
| fun <T> getInstance(identifier: Long): T? { | ||||||||||||||
| logWarningIfFinalizationListenerHasStopped() | ||||||||||||||
| val instance = weakInstances[identifier] as java.lang.ref.WeakReference<T>? | ||||||||||||||
| val instance = weakInstances[identifier] as IdentityWeakReference<T>? | ||||||||||||||
| return instance?.get() | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** Returns whether this manager contains the given `instance`. */ | ||||||||||||||
| fun containsInstance(instance: Any?): Boolean { | ||||||||||||||
| logWarningIfFinalizationListenerHasStopped() | ||||||||||||||
| return identifiers.containsKey(instance) | ||||||||||||||
| return instance != null && identifiers.containsKey(IdentityWeakReference(instance)) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
|
|
@@ -199,8 +230,8 @@ class ${kotlinInstanceManagerClassName(options)}(private val finalizationListene | |||||||||||||
| if (hasFinalizationListenerStopped()) { | ||||||||||||||
| return | ||||||||||||||
| } | ||||||||||||||
| var reference: java.lang.ref.WeakReference<Any>? | ||||||||||||||
| while ((referenceQueue.poll() as java.lang.ref.WeakReference<Any>?).also { reference = it } != null) { | ||||||||||||||
| var reference: IdentityWeakReference<Any>? | ||||||||||||||
| while ((referenceQueue.poll() as IdentityWeakReference<Any>?).also { reference = it } != null) { | ||||||||||||||
| val identifier = weakReferencesToIdentifiers.remove(reference) | ||||||||||||||
| if (identifier != null) { | ||||||||||||||
| weakInstances.remove(identifier) | ||||||||||||||
|
|
@@ -216,8 +247,8 @@ class ${kotlinInstanceManagerClassName(options)}(private val finalizationListene | |||||||||||||
| require(!weakInstances.containsKey(identifier)) { | ||||||||||||||
| "Identifier has already been added: \$identifier" | ||||||||||||||
| } | ||||||||||||||
| val weakReference = java.lang.ref.WeakReference(instance, referenceQueue) | ||||||||||||||
| identifiers[instance] = identifier | ||||||||||||||
| val weakReference = IdentityWeakReference(instance, referenceQueue) | ||||||||||||||
| identifiers[weakReference] = identifier | ||||||||||||||
| weakInstances[identifier] = weakReference | ||||||||||||||
| weakReferencesToIdentifiers[weakReference] = identifier | ||||||||||||||
| strongInstances[identifier] = instance | ||||||||||||||
|
|
||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this logging is a great addition for debugging, the current implementation in the generator leads to duplicated code blocks in the generated
writeValuemethod for eachProxyApitype. To improve the maintainability and readability of the generated code, consider refactoring this. You could generate a private helper method within theProxyApiBaseCodecclass to encapsulate the logging logic, and then call that helper from eachifblock.For example, you could generate a method like this:
Then, the call site in the
ifblock would be a single, clean line.