{"record":{"id":"f43ffa5d3803ea2b","repo":"hibernate/hibernate-orm","slug":"implementation-class-does-not-implement-strat","errorCode":null,"errorMessage":"Implementation class [{}] does not implement strategy interface [{}]","messagePattern":"Implementation class \\[(.+?)\\] does not implement strategy interface \\[(.+?)\\]","errorType":"exception","errorClass":"StrategySelectionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java","lineNumber":95,"sourceCode":"\t */\n\tpublic <T> void addExplicitStrategyRegistration(Class<T> strategy, Class<? extends T> implementation, String name) {\n\t\taddExplicitStrategyRegistration( new SimpleStrategyRegistrationImpl<>( strategy, implementation, name ) );\n\t}\n\n\t/**\n\t * Adds an explicit (as opposed to discovered) strategy registration.\n\t *\n\t * @param strategyRegistration The strategy implementation registration.\n\t * @param <T> The type of the strategy.  Used to make sure that the strategy and implementation are type\n\t * compatible.\n\t */\n\tpublic <T> void addExplicitStrategyRegistration(StrategyRegistration<T> strategyRegistration) {\n\t\tfinal var strategyRole = strategyRegistration.getStrategyRole();\n\t\tif ( BOOT_LOGGER.isTraceEnabled() && !strategyRole.isInterface() ) {\n\t\t\tBOOT_LOGGER.registeringNonInterfaceStrategy( strategyRole.getName() );\n\t\t}\n\t\tif ( !strategyRole.isAssignableFrom( strategyRegistration.getStrategyImplementation() ) ) {\n\t\t\tthrow new StrategySelectionException(\n\t\t\t\t\t\"Implementation class [\" + strategyRegistration.getStrategyImplementation().getName()\n\t\t\t\t\t+ \"] does not implement strategy interface [\"\n\t\t\t\t\t+ strategyRole.getName() + \"]\"\n\t\t\t);\n\t\t}\n\t\texplicitStrategyRegistrations.add( strategyRegistration );\n\t}\n\n\t/**\n\t * Builds the selector.\n\t *\n\t * @param classLoaderService The class loading service used to (attempt to) resolve any un-registered\n\t * strategy implementations.\n\t *\n\t * @return The selector.\n\t */\n\tpublic StrategySelector buildSelector(ClassLoaderService classLoaderService) {\n\t\tfinal var strategySelector = new StrategySelectorImpl( classLoaderService );","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java#L77-L113","documentation":"StrategySelectorBuilder.addExplicitStrategyRegistration() validates every explicit strategy registration (from a ServiceLoader-discovered StrategyRegistrationProvider or direct builder calls): the implementation class must be assignable to the strategy role. A mismatch throws StrategySelectionException naming both classes, because a registration that cannot stand in for its interface would break every later resolve against that strategy.","triggerScenarios":"A StrategyRegistrationProvider (registered via META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider) or explicit builder call that pairs a strategy interface with an implementation that does not implement/extend it - e.g., registering MyConnectionProvider under the Dialect role.","commonSituations":"Custom integration jars with copy-pasted or wrongly-generified StrategyRegistration classes; refactoring that dropped an implements/extends clause while the stale services file remained; mixed versions of an integration jar where the interface moved.","solutions":["Fix the registration so the implementation genuinely implements/extends the strategy interface (check the <T> generics of StrategyRegistration)","Remove stale entries from the META-INF/services strategy registration provider file","Add a unit test asserting strategyRole.isAssignableFrom(implementation) for every registration you ship"],"exampleFix":"// before\nnew StrategyRegistrationImpl<>(ConnectionProvider.class, // role\n    MyCustomDialect.class, \"myDialect\");            // does not implement role\n\n// after\nnew StrategyRegistrationImpl<>(Dialect.class,\n    MyCustomDialect.class, \"myDialect\");","handlingStrategy":"validation","validationCode":"// Validate a registration before contributing it\nstatic <T> void check(Class<T> role, Class<? extends T> impl) {\n    if (!role.isAssignableFrom(impl)) {\n        throw new IllegalArgumentException(\n            impl.getName() + \" does not implement \" + role.getName());\n    }\n}\ncheck(Dialect.class, MyDialect.class);","typeGuard":null,"tryCatchPattern":"try {\n    builder.addExplicitStrategyRegistration(registration);\n} catch (StrategySelectionException e) {\n    // message names both classes; fix the pairing in the StrategyRegistrationProvider\n    throw new ConfigurationException(e.getMessage(), e);\n}","preventionTips":["Unit-test every shipped StrategyRegistration for role.isAssignableFrom(implementation)","Keep META-INF/services entries in sync when interfaces change during refactors","Avoid raw types on StrategyRegistration - let generics catch mismatches at compile time"],"tags":["hibernate","strategy","spi","boot","classpath"],"backgroundTag":"strategy-registration-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}