Deduplicate TypeMarker, ExceptionDeserializerArgs, and Deserializer fields in generated dialogue interfaces#2869
Deduplicate TypeMarker, ExceptionDeserializerArgs, and Deserializer fields in generated dialogue interfaces#2869
Conversation
Generate changelog in
|
…ields in generated dialogue interfaces
Generated dialogue service interfaces previously created per-endpoint TypeMarker
anonymous classes, ExceptionDeserializerArgs instances, and Deserializer fields,
causing excessive allocations when multiple endpoints share the same return type.
This change modifies DefaultStaticFactoryMethodGenerator to:
1. Generate one `private static final TypeMarker<T>` per distinct return type
instead of `new TypeMarker<T>() {}` inline per endpoint.
2. Generate one `private static final ExceptionDeserializerArgs<T>` per distinct
return type (error-respecting path), instead of calling
createExceptionDeserializerArgs per endpoint.
3. Generate one shared `Deserializer<T>` instance field per distinct return type,
referenced by all endpoints with the same return type.
For EteServiceBlocking (36 endpoints, 22 distinct return types) this reduces
anonymous TypeMarker classes, createExceptionDeserializerArgs calls, and
Deserializer allocations from 36 each to 22 each.
…enerate() Refactored the generate() method by extracting logic into smaller, focused methods to improve maintainability and reduce complexity.
…ersion, and deterministic hashing for deconfliction - Convert ReturnTypeFieldsContext from class to record for conciseness - Use Guava CaseFormat for converting type names instead of manual character manipulation - Use deterministic Guava Hashing (murmur3_32_fixed) with base-36 encoding for deconflicting field names instead of sequential numeric suffixes - Regenerate integration test expected files to reflect the new field naming
556ec6a to
f1bea45
Compare
✅ Successfully generated changelog entry!Need to regenerate?Simply interact with the changelog bot comment again to regenerate these entries. 📋Changelog Preview💡 Improvements
|
| /** Creates an asynchronous/non-blocking client for a EmptyPathService service. */ | ||
| static EmptyPathServiceAsync of(EndpointChannelFactory _endpointChannelFactory, ConjureRuntime _runtime) { | ||
| return new EmptyPathServiceAsync() { | ||
| private static final TypeMarker<Boolean> booleanTypeMarker = new TypeMarker<Boolean>() {}; |
There was a problem hiding this comment.
I probably would prefer if these weren't static. It means that simply loading these classes will requiring initializing and retaining these classes, even if the client is no longer used.
|
Discussed internally that this proposed Dialogue change is probably the more useful change to mitigate the overhead from using sticky clients. Hopefully that change will take the construction of these clients out of a hot path. I think this is a good idea though. I think the hashes added to the variable names when there are name collisions hurts the readability: I wonder if there's another way to deconflict here. |
Fixed up merge conflicts and finished out implementation of #2647 in palantir/dialogue#2955 on top of that branch |
Before this PR
Generated dialogue service interfaces previously created per-endpoint TypeMarker
anonymous classes, ExceptionDeserializerArgs instances, and Deserializer fields,
causing excessive allocations when multiple endpoints share the same return type.
This adds unnecessary overhead for conjure clients that use sticky channels such as ⛰️ clients via e.g.
DataServiceAsync#of(com.palantir.dialogue.EndpointChannelFactory, com.palantir.dialogue.ConjureRuntime).After this PR
==COMMIT_MSG==
This change modifies DefaultStaticFactoryMethodGenerator to:
private static final TypeMarker<T>per distinct return typeinstead of
new TypeMarker<T>() {}inline per endpoint.private static final ExceptionDeserializerArgs<T>per distinctreturn type (error-respecting path), instead of calling
createExceptionDeserializerArgs per endpoint.
Deserializer<T>instance field per distinct return type,referenced by all endpoints with the same return type.
For example EteServiceBlocking (36 endpoints, 22 distinct return types) this reduces
anonymous TypeMarker classes, createExceptionDeserializerArgs calls, and
Deserializer allocations from 36 each to 22 each.
==COMMIT_MSG==
Possible downsides?