My scenario is that I want to add users to h2 database. My setup for restful provider is working without a problem. I can curl and get the response from the keycloak spi rest provider successfully. However, the problems is that my code fails to acquire EntityManager.
The code looks like this
public class MyResourceProvider implements RealmResourceProvider {
KeycloakSession session;
public MyResourceProvider(KeycloakSession session) {
this.session = session;
}
@Override
public Object getResource() {
return new MyResource(session);
}
}
public class MyResource {
KeycloakSession session;
public MyResource() {
this.session = session;
final Set<JpaConnectionProvider> set = session.getAllProviders(JpaConnectionProvider.class);
set.forEach((e) -> log.info("Element in the set: {}", e) ); // this prints element in the set: org.keycloak.connections.jpa.DefaultJpaConnectionProvider@39118fdc
this.em = session.getProvider(DefaultJpaConnectionProvider.class, "my-store").getEntityManager(); // this line throw NPE error and getProvider() with DefaultJpaConnectionProvider.class or JpaConnectionProvider.class all throws NPE error
}
}
The error message is
this throws “ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-1) Uncaught server error: java.lang.NullPointerException: Cannot invoke “org.keycloak.connections.jpa.DefaultJpaConnectionProvider.getEntityManager()” because the return value of “org.keycloak.models.KeycloakSession.getProvider(java.lang.Class, String)” is null”
It seems that jpa setting is not configured, but I have persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence ...>
<persistence-unit name="my-store" transaction-type="JTA">
<class>myorg.persistence.MyUserEntity</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<!-- Sets the name of the datasource to be the same as the datasource name in quarkus.properties-->
<property name="hibernate.connection.datasource" value="my-store" />
<property name="jakarta.persistence.transactionType" value="JTA" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
And quarkus.properties
is copied to /opt/keycloak/conf
(with or without copying this properties file to keycloak’s conf dir, the error is the same.
quarkus.datasource.my-store.db-kind=h2
quarkus.datasource.my-store.username=sa
quarkus.datasource.my-store.password=password
quarkus.datasource.my-store.jdbc.url=jdbc:h2:mem:user-store;DB_CLOSE_DELAY=-1
In Dockerfile
(again with or without KC_* ENV variables, the error remains the same)
... # the entire Dockerfile actually is copied from the keycloak container setup doc, it is working fine without a problem, except getProvider(JPAConnectionProvider.class) error.
COPY --from=builder /opt/keycloak/providers /opt/keycloak/providers
ENV KC_DB=dev-file
ENV KC_DB_URL=jdbc:h2:mem:user-store;DB_CLOSE_DELAY=-1
ENV KC_DB_USERNAME=sa
ENV KC_DB_PASSWORD=password
ENV KC_HOSTNAME=localhost
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
The docker command is
docker run -d --name $(KEYCLOAK_NAME) -p 8080:8080 \
-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:latest \
start-dev
All setting is just for local testing at the moment. so password is not set to production purpose. Anything I miss or misconfigure? I appreciate any advice. Thanks.