{"record":{"id":"6b3c7dafd9253757","repo":"hibernate/hibernate-orm","slug":"unloadable-java-type-typename","errorCode":null,"errorMessage":"Unloadable Java type: \" + typeName","messagePattern":"Unloadable Java type: \" \\+ typeName","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/UnknownBasicJavaType.java","lineNumber":50,"sourceCode":"\t\tsuper( type, mutabilityPlan );\n\t\tthis.typeName = type.getTypeName();\n\t}\n\n\tpublic UnknownBasicJavaType(Type type, MutabilityPlan<T> mutabilityPlan) {\n\t\tsuper( type, mutabilityPlan );\n\t\tthis.typeName = type.getTypeName();\n\t}\n\n\t@Override\n\tpublic String getTypeName() {\n\t\treturn typeName;\n\t}\n\n\t@Override\n\tpublic Type getJavaType() {\n\t\tfinal Type type = super.getJavaType();\n\t\tif ( type == null ) {\n\t\t\tthrow new UnsupportedOperationException( \"Unloadable Java type: \" + typeName );\n\t\t}\n\t\telse {\n\t\t\treturn type;\n\t\t}\n\t}\n\n\t@Override\n\tpublic JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {\n\t\tthrow new JdbcTypeRecommendationException(\n\t\t\t\t\"Could not determine recommended JdbcType for Java type '\" + getTypeName() + \"'\"\n\t\t);\n\t}\n\n\t@Override\n\tpublic <X> X unwrap(T value, Class<X> type, WrapperOptions options) {\n\t\tif ( type.isAssignableFrom( getJavaTypeClass() ) ) {\n\t\t\treturn type.cast( value );\n\t\t}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/UnknownBasicJavaType.java#L32-L68","documentation":"UnknownBasicJavaType is registered by the JavaTypeRegistry when a basic type is known only by name and its Class cannot be loaded by the active classloader. The descriptor carries just the type name, so getJavaType() throws UnsupportedOperationException('Unloadable Java type: <name>') as soon as real class access is needed (binding, reflection, DDL generation). The root cause is a classpath/classloader problem, not mapping semantics.","triggerScenarios":"SessionFactory bootstrap resolves a type by class name that the classloader cannot load; later anything calls getJavaType()/getJavaTypeClass() on that descriptor - metamodel building, schema export/validation, or binding a value at flush time.","commonSituations":"Schema generation run from Ant/Gradle/Maven plugins without the entity classes on the plugin classpath; app servers, OSGi or native-image where the Thread-Context ClassLoader differs from the entities' loader; a typo in a class name in orm.xml/hbm.xml or a TypeContributor; hot-reload tooling dropping classes.","solutions":["Make the named class loadable by the SessionFactory's classloader: put the domain jar on the tool/plugin classpath or align the TCCL with the loader that owns the entities.","Check the exact type name in the message against orm.xml/hbm.xml, @Type values and TypeContributor registrations for typos or wrong packages.","For schema tooling, run it in the same JVM/module path as the application (SchemaExport via the persistence unit) instead of a separate bare classpath.","Build the StandardServiceRegistry with the owning classloader (new StandardServiceRegistryBuilder(entityClassLoader)) so Hibernate uses it for name resolution."],"exampleFix":"// before (tool runs with its own classloader; entity class invisible)\nStandardServiceRegistry registry = new StandardServiceRegistryBuilder().build();\nMetadata metadata = new MetadataSources(registry).addResource(\"org/acme/Order.orm.xml\").buildMetadata();\n// -> Unloadable Java type: org.acme.Order when metadata touches the class\n\n// after: build the registry with the application classloader\nStandardServiceRegistry registry = new StandardServiceRegistryBuilder(MyApp.class.getClassLoader())\n        .build();","handlingStrategy":"validation","validationCode":"// Fail fast at startup: every mapping-referenced class must load\nstatic void assertAllLoadable(ClassLoader cl, String... classNames) {\n    for (String name : classNames) {\n        try {\n            Class.forName(name, false, cl);\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(\"Type not on classpath: \" + name, e);\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    sessionFactory = metadata.buildSessionFactory();\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Unloadable Java type\")) {\n        // message names the missing class: add it to the classpath of the SessionFactory's classloader\n    } else {\n        throw e;\n    }\n}","preventionTips":["Run schema tooling in the same JVM/classpath as the domain model","Pass the owning classloader when building the StandardServiceRegistry","Class.forName every mapping-referenced class during a startup smoke test"],"tags":["hibernate","classpath","classloader","bootstrap","schema-export"],"backgroundTag":"class-not-found-classpath","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}