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

Refactor KVI #512

Merged
merged 7 commits into from
Jan 3, 2022
Merged

Refactor KVI #512

merged 7 commits into from
Jan 3, 2022

Conversation

k163377
Copy link
Contributor

@k163377 k163377 commented Oct 30, 2021

This PR is a partial realization of the first step of the 3-step change I suggested in my comment #439.

Changes from existing

Many of the reflection operations performed by the KotlinValueInstantiator are now cached.
This is expected to speed up the process since the reflection process is omitted.

The results of the benchmark comparison are as follows.
From this result, we can see that it is actually faster.

before

Benchmark                                           Mode  Cnt        Score        Error  Units
c.w.constructor.Benchmarks.useDefaultKotlinMapper  thrpt    9   639074.213 ±  19600.918  ops/s
c.w.constructor.Benchmarks.useJavaMapper           thrpt    9  2883418.695 ± 117219.003  ops/s
c.w.constructor.Benchmarks.useKotlinMapper         thrpt    9  1163349.939 ±  34378.903  ops/s
c.w.factory.Benchmarks.useDefaultKotlinMapper      thrpt    9   556424.552 ±  10447.484  ops/s
c.w.factory.Benchmarks.useJavaMapper               thrpt    9  2848669.598 ±  25770.187  ops/s
c.w.factory.Benchmarks.useKotlinMapper             thrpt    9   571255.239 ±  14027.060  ops/s

after

Benchmark                                           Mode  Cnt        Score        Error  Units
c.w.constructor.Benchmarks.useDefaultKotlinMapper  thrpt    9   775820.306 ±  40891.839  ops/s
c.w.constructor.Benchmarks.useJavaMapper           thrpt    9  2823625.426 ± 107884.530  ops/s
c.w.constructor.Benchmarks.useKotlinMapper         thrpt    9  1312132.093 ±   6461.389  ops/s
c.w.factory.Benchmarks.useDefaultKotlinMapper      thrpt    9   749118.995 ±   2194.277  ops/s
c.w.factory.Benchmarks.useJavaMapper               thrpt    9  2873057.532 ± 142978.335  ops/s
c.w.factory.Benchmarks.useKotlinMapper             thrpt    9   820204.472 ±  32521.224  ops/s

Changes from #439

The class that was originally named Instantiator has been changed to ValueCreator.
Because the name Instantiator seemed to be confusing with the keyword derived from Jackson.

Also, the content that was originally defined as just an interface has been changed to a sealed class.
This makes it easier to standardize the process and improve the handling of conditional expressions.

Others

I don't think it's necessary to make it ExperimentalDeserializationBackend, since many of the changes are based on existing content.
Therefore, I have not incorporated the relevant changes.

Also, to keep the size of the PR small, I have not yet refactored the KVI.createFromObjectWith function, such as splitting it.
I plan to do that after this PR is merged.

return
}

throw IllegalAccessException("Cannot access to function or companion object instance, target: $callable")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The error message here is a summary of what was originally individual content.
Should I follow the existing content and give a more specific message for each one?

Also, I couldn't think of any good error message content, so I would appreciate any suggestions.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what you mean by individual content

Copy link
Contributor Author

@k163377 k163377 Jan 3, 2022

Choose a reason for hiding this comment

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

I don't remember exactly what I was thinking when I left this comment because it's been so long since I created the PR...

I think I was probably worrying about the following two points.

  • Whether people who read this error message will be able to respond appropriately
  • Should I indicate specifically which of constructor, factory function, or companion object was inaccessible?

Copy link
Member

Choose a reason for hiding this comment

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

Ahh, yes, if that's possible I think it could prove to be quite helpful

@dinomite dinomite self-requested a review October 31, 2021 10:08
@dinomite dinomite self-assigned this Oct 31, 2021
return
}

throw IllegalAccessException("Cannot access to function or companion object instance, target: $callable")
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure what you mean by individual content

}
}
else -> throw IllegalStateException("Expected a constructor or method to create a Kotlin object, instead found ${_withArgsCreator.annotated.javaClass.name}")
} // we cannot reflect this method so do the default Java-ish behavior
Copy link
Member

Choose a reason for hiding this comment

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

Won't the else -> throw prevent any further processing? Perhaps it should be else -> null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason is that the following process has been ported as is.

val callable = when (_withArgsCreator) {
is AnnotatedConstructor -> cache.kotlinFromJava(_withArgsCreator.annotated as Constructor<Any>)
is AnnotatedMethod -> cache.kotlinFromJava(_withArgsCreator.annotated as Method)
else -> throw IllegalStateException("Expected a constructor or method to create a Kotlin object, instead found ${_withArgsCreator.annotated.javaClass.name}")
} ?: return super.createFromObjectWith(
ctxt,
props,
buffer
) // we cannot reflect this method so do the default Java-ish behavior

Copy link
Member

Choose a reason for hiding this comment

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

Got it. For posterity the null half of that ?: was moved to KotlinValueInstantiator:31

@@ -157,23 +120,19 @@ internal class KotlinValueInstantiator(
numCallableParameters++
Copy link
Member

Choose a reason for hiding this comment

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

Existing code, but I think this would be a bit clearer as numCallableParameters + 1, since we don't need to increment the value in place. That'll also allow numCallableParameters to be declared as a val

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good.

Comment on lines +9 to +11
init {
callable.isAccessible = true
}
Copy link
Member

Choose a reason for hiding this comment

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

Does this override the above since this init block is lower? Is that the correct behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you saying that it is difficult to know which comes first, initializing the property or rewriting isAccessible?
If I believe Intellij IDEA's point, it should work correctly, but if I value readability, should I rewrite it as follows?(Rewriting the accessible property was surprisingly expensive, so I've included a change to rewrite it only when necessary.)

override val accessible: Boolean = run {
    val initialAccessible = callable.isAccessible

    if (!initialAccessible) callable.isAccessible = true

    initialAccessible
}

Copy link
Member

Choose a reason for hiding this comment

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

Understood, I was just a bit unsure whether that rewrite was intended 👍

This was referenced Jan 2, 2022
@dinomite dinomite merged commit c49144b into FasterXML:2.13 Jan 3, 2022
@k163377 k163377 deleted the refactor-KVI branch January 3, 2022 15:45
@k163377 k163377 mentioned this pull request Jan 3, 2022
dinomite added a commit that referenced this pull request Jan 7, 2022
@k163377 k163377 mentioned this pull request Jan 10, 2022
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.

2 participants