Skip to content

Replace BiMap with plain maps - #901

Merged
oryan-block merged 2 commits into
masterfrom
refactor/861-plain-maps
Oct 22, 2026
Merged

oryan-block merged 2 commits into
masterfrom
refactor/861-plain-maps

Conversation

@oryan-block

Copy link
Copy Markdown
Collaborator

Fixes #861

Checklist

  • Pull requests follows the contribution guide
  • New or modified functionality is covered by tests

Description

BiMap#put throwing was the only thing that stopped two object, interface or enum types from ending up with the same class. Interface and union type resolution maps a class back to its type, so they can't share one. Classes found through resolver return types got there too, not just dictionary entries. The error didn't say much:

SchemaClassScannerError: Error creating bimap of type => class
Caused by: java.lang.IllegalArgumentException: value already present: class scenarios.SharedOutputClassQuery$Titled

So TypeClassDictionary is now a small internal class that takes the type to class map and builds the class to type map from it. Building the inverse is the check, so one can't exist without the other. The same setup now fails with:

SchemaClassScannerError: Class 'scenarios.SharedOutputClassQuery$Titled' is used for types 'Book', 'Movie', but only input object types can share a class!

The wording matches the existing check for supplied dictionary entries. That check stays, since it also covers entries the scan never reaches and Map/Object classes, which the final dictionary leaves out.

BiMap is public and getDictionary() returns one, so neither can go before 15.0.0 (#900). Added SchemaParserDictionary#toMap(), which returns a plain Map<String, Class<*>> with every name, and deprecated getDictionary() and BiMap. graphql-spring-boot's builder.dictionary(dictionary.getDictionary()) still compiles and links. It should switch to dictionary.toMap() once it's on a version that has it. I didn't add a SchemaParserBuilder#dictionary(SchemaParserDictionary) overload, since toMap() already covers that call.

New tests in SchemaClassScannerTest build schemas where two object types, an interface and an object type, or two enums share a class, and check the message. On master all three fail with the bimap error. Another one checks that input types bound to the same class through resolver parameters still build. SchemaParserDictionaryTest now goes through toMap() and keeps one test for the deprecated getDictionary(). mvn clean verify passes on graphql-java 26.1 and 25.1. Also checked through the public API: the two-object-types setup gives the messages above on master and on this branch, and a dictionary passed as SchemaParserDictionary().add(Dog::class, Cat::class).toMap() resolves Dog and Cat for both an interface and a union.

Release notes: SchemaParserDictionary.getDictionary() and graphql.kickstart.tools.util.BiMap are deprecated, use SchemaParserDictionary.toMap() instead. Two output types sharing a class still fail the build, now with a message that names the class and the types.

@oryan-block
oryan-block force-pushed the refactor/861-plain-maps branch from 69638d2 to 6b53dba Compare October 22, 2026 22:40
@sonarqubecloud

Copy link
Copy Markdown

@oryan-block

Copy link
Copy Markdown
Collaborator Author

PASS
Two output types bound to one class (resolver return types) fail the build on head with Class 'scenarios.SharedPart' is used for types 'Gadget', 'Gizmo', but only input object types can share a class!. Parent fails with Error creating bimap of type => class, caused by value already present: class scenarios.SharedPart. Same on both sides for two enums ('Color', 'Shade') and an interface plus an object type ('Vehicle', 'Car').
An Animal interface and a Pet union (Dog, Cat, Parrot) built from a SchemaParserDictionary resolve the right __typenames through toMap() on head and through the deprecated getDictionary() on head and parent (identical JSON).
Three input types bound to one class (one through a nested input field) still build and run on head, distance and length both return 7, same as parent. The polymorphism and nested-unions scenarios pass on head with errors=0 and an empty probe.log.
javap -public of BiMap is identical between the two jars (head adds the deprecated flag). SchemaParserDictionary differs only by the added toMap(). The other signature changes are in Kotlin internal classes (ScannedSchemaObjects, the type resolvers).
Checked through the installed jar and the public API only, on graphql-java 26.1 and JDK 25. Covers head 6b53dba.

@oryan-block
oryan-block merged commit a24067d into master Oct 22, 2026
7 checks passed
@oryan-block
oryan-block deleted the refactor/861-plain-maps branch October 22, 2026 22:45
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.

Replace BiMap with plain maps

1 participant