pf4j-spring icon indicating copy to clipboard operation
pf4j-spring copied to clipboard

Not possible to create a CRUD repository as ExtensionPoint

Open dtrunk90 opened this issue 6 years ago • 7 comments
trafficstars

I'm not able to autowire an Extension in an Extension: https://github.com/keering/keering/blob/master/plugins/widgets/chat/src/main/java/com/github/keering/plugins/widgets/chat/service/impl/ChatHistoryServiceImpl.java#L16

You can start the project by running: $ ./gradlew build && cd build && java -jar app-1.0-SNAPSHOT.jar

dtrunk90 avatar Jan 03 '19 11:01 dtrunk90

I don't understand why you say that ChatHistoryRepository is an extension point. Put the log of PF4J on trace or debug (see demo) and see the details.

decebals avatar Jan 03 '19 19:01 decebals

Oh well, you're right. I didn't marked ChatHistoryRepository as an extension point. Now I did locally and getting this stacktrace as it is an interface, not a class:

java.lang.InstantiationException: com.github.keering.plugins.widgets.chat.repository.ChatHistoryRepository
        at java.base/java.lang.Class.newInstance(Class.java:547) ~[na:na]
        at org.pf4j.spring.SpringExtensionFactory.createWithoutSpring(SpringExtensionFactory.java:70) [pf4j-spring-0.5.0.jar!/:0.5.0]
        at org.pf4j.spring.SpringExtensionFactory.create(SpringExtensionFactory.java:51) [pf4j-spring-0.5.0.jar!/:0.5.0]
        at org.pf4j.spring.ExtensionsInjector.registerExtension(ExtensionsInjector.java:80) [pf4j-spring-0.5.0.jar!/:0.5.0]
        at org.pf4j.spring.ExtensionsInjector.injectExtensions(ExtensionsInjector.java:64) [pf4j-spring-0.5.0.jar!/:0.5.0]
        at org.pf4j.spring.SpringPluginManager.init(SpringPluginManager.java:66) [pf4j-spring-0.5.0.jar!/:0.5.0]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:363) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:419) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1737) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:576) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:307) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083) ~[spring-context-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:853) ~[spring-context-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.3.RELEASE.jar!/:5.1.3.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.1.RELEASE.jar!/:2.1.1.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.1.RELEASE.jar!/:2.1.1.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.1.RELEASE.jar!/:2.1.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.1.RELEASE.jar!/:2.1.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.1.RELEASE.jar!/:2.1.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.1.RELEASE.jar!/:2.1.1.RELEASE]
        at com.github.keering.app.Application.main(Application.java:10) ~[classes!/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) ~[app-1.0-SNAPSHOT.jar:na]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) ~[app-1.0-SNAPSHOT.jar:na]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) ~[app-1.0-SNAPSHOT.jar:na]
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) ~[app-1.0-SNAPSHOT.jar:na]
Caused by: java.lang.NoSuchMethodException: com.github.keering.plugins.widgets.chat.repository.ChatHistoryRepository.<init>()
        at java.base/java.lang.Class.getConstructor0(Class.java:3302) ~[na:na]
        at java.base/java.lang.Class.newInstance(Class.java:532) ~[na:na]
        ... 40 common frames omitted

It's a so called CRUD repository which doesn't need a class: https://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/html/jpa.repositories.html https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html

dtrunk90 avatar Jan 03 '19 20:01 dtrunk90

I guess SpringExtensionFactory#createWithoutSpring should check for org.springframework.data.repository.Repository.class.isAssignableFrom(extensionClass) and create a JpaRepositoryFactoryBean instead.

I'll do further research and open up a pull request if it fixes this restriction.

dtrunk90 avatar Jan 05 '19 21:01 dtrunk90

I was able to create a bean now with this method:

    protected Object createWithoutSpring(Class<?> extensionClass) {
        try {
            if (isClassAvailable("org.springframework.data.repository.Repository") && Repository.class.isAssignableFrom(extensionClass)) {
                PluginWrapper pluginWrapper = pluginManager.whichPlugin(extensionClass);
                if (pluginWrapper != null) {
                    Plugin plugin = pluginWrapper.getPlugin();
                    if (plugin instanceof SpringPlugin) {
                        JpaRepositoryFactoryBean repositoryFactoryBean = new JpaRepositoryFactoryBean(extensionClass);
                        ApplicationContext pluginContext = ((SpringPlugin) plugin).getApplicationContext();
                        repositoryFactoryBean.setEntityManager(pluginContext.getBean(EntityManager.class));
                        repositoryFactoryBean.setEntityPathResolver(pluginContext.getBeanProvider(EntityPathResolver.class));
                        repositoryFactoryBean.afterPropertiesSet();
                        return repositoryFactoryBean;
                    }
                }
            } else {
                return extensionClass.newInstance();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    private boolean isClassAvailable(String className) {
        try {
            Class.forName(className);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

But in the end I'm getting this exception:

java.lang.IllegalArgumentException: Not a managed type: class com.github.keering.plugins.widgets.chat.model.jpa.ChatHistory
	at org.hibernate.metamodel.internal.MetamodelImpl.managedType(MetamodelImpl.java:552) ~[hibernate-core-5.3.7.Final.jar!/:5.3.7.Final]
	at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:74) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:66) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:188) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:139) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:123) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:64) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:305) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:297) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:211) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.util.Lazy.get(Lazy.java:94) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:300) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:119) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.pf4j.spring.SpringExtensionFactory.createWithoutSpring(SpringExtensionFactory.java:84) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.SpringExtensionFactory.create(SpringExtensionFactory.java:56) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.ExtensionsInjector.registerExtension(ExtensionsInjector.java:80) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.ExtensionsInjector.injectExtensions(ExtensionsInjector.java:64) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.SpringPluginManager.init(SpringPluginManager.java:66) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]

I also had to add some dependencies in provided scope and update spring version:

diff --git a/pf4j-spring/pom.xml b/pf4j-spring/pom.xml
index b4a6713..748eeb9 100644
--- a/pf4j-spring/pom.xml
+++ b/pf4j-spring/pom.xml
@@ -33,6 +33,27 @@
             <version>${spring.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-commons</artifactId>
+            <version>${spring-data.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-jpa</artifactId>
+            <version>${spring-data.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.persistence</groupId>
+            <artifactId>persistence-api</artifactId>
+            <version>${persistence-api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
         <!-- Logs -->
         <dependency>
             <groupId>log4j</groupId>
diff --git a/pom.xml b/pom.xml
index 4ff28ac..3fcf403 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,7 +46,9 @@
         <java.version>1.7</java.version>
 
         <pf4j.version>2.5.0</pf4j.version>
-        <spring.version>4.0.5.RELEASE</spring.version>
+        <persistence-api.version>1.0.2</persistence-api.version>
+        <spring.version>5.1.0.RELEASE</spring.version>
+        <spring-data.version>2.1.3.RELEASE</spring-data.version>
         <slf4j.version>1.7.5</slf4j.version>
 
         <junit.version>4.12</junit.version>

Maybe it's just not possible. I don't know what to try else.

dtrunk90 avatar Jan 06 '19 00:01 dtrunk90

development ?

smitea avatar Feb 14 '19 14:02 smitea

look at https://pf4j.org/doc/development-mode.html

smitea avatar Feb 14 '19 14:02 smitea

I was able to create a bean now with this method:

    protected Object createWithoutSpring(Class<?> extensionClass) {
        try {
            if (isClassAvailable("org.springframework.data.repository.Repository") && Repository.class.isAssignableFrom(extensionClass)) {
                PluginWrapper pluginWrapper = pluginManager.whichPlugin(extensionClass);
                if (pluginWrapper != null) {
                    Plugin plugin = pluginWrapper.getPlugin();
                    if (plugin instanceof SpringPlugin) {
                        JpaRepositoryFactoryBean repositoryFactoryBean = new JpaRepositoryFactoryBean(extensionClass);
                        ApplicationContext pluginContext = ((SpringPlugin) plugin).getApplicationContext();
                        repositoryFactoryBean.setEntityManager(pluginContext.getBean(EntityManager.class));
                        repositoryFactoryBean.setEntityPathResolver(pluginContext.getBeanProvider(EntityPathResolver.class));
                        repositoryFactoryBean.afterPropertiesSet();
                        return repositoryFactoryBean;
                    }
                }
            } else {
                return extensionClass.newInstance();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    private boolean isClassAvailable(String className) {
        try {
            Class.forName(className);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

But in the end I'm getting this exception:

java.lang.IllegalArgumentException: Not a managed type: class com.github.keering.plugins.widgets.chat.model.jpa.ChatHistory
	at org.hibernate.metamodel.internal.MetamodelImpl.managedType(MetamodelImpl.java:552) ~[hibernate-core-5.3.7.Final.jar!/:5.3.7.Final]
	at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:74) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:66) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:188) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:139) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:123) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:64) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:305) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:297) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:211) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.util.Lazy.get(Lazy.java:94) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:300) ~[spring-data-commons-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:119) ~[spring-data-jpa-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
	at org.pf4j.spring.SpringExtensionFactory.createWithoutSpring(SpringExtensionFactory.java:84) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.SpringExtensionFactory.create(SpringExtensionFactory.java:56) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.ExtensionsInjector.registerExtension(ExtensionsInjector.java:80) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.ExtensionsInjector.injectExtensions(ExtensionsInjector.java:64) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]
	at org.pf4j.spring.SpringPluginManager.init(SpringPluginManager.java:66) [pf4j-spring-0.6.0-SNAPSHOT.jar!/:0.6.0-SNAPSHOT]

I also had to add some dependencies in provided scope and update spring version:

diff --git a/pf4j-spring/pom.xml b/pf4j-spring/pom.xml
index b4a6713..748eeb9 100644
--- a/pf4j-spring/pom.xml
+++ b/pf4j-spring/pom.xml
@@ -33,6 +33,27 @@
             <version>${spring.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-commons</artifactId>
+            <version>${spring-data.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-jpa</artifactId>
+            <version>${spring-data.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.persistence</groupId>
+            <artifactId>persistence-api</artifactId>
+            <version>${persistence-api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
         <!-- Logs -->
         <dependency>
             <groupId>log4j</groupId>
diff --git a/pom.xml b/pom.xml
index 4ff28ac..3fcf403 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,7 +46,9 @@
         <java.version>1.7</java.version>
 
         <pf4j.version>2.5.0</pf4j.version>
-        <spring.version>4.0.5.RELEASE</spring.version>
+        <persistence-api.version>1.0.2</persistence-api.version>
+        <spring.version>5.1.0.RELEASE</spring.version>
+        <spring-data.version>2.1.3.RELEASE</spring-data.version>
         <slf4j.version>1.7.5</slf4j.version>
 
         <junit.version>4.12</junit.version>

Maybe it's just not possible. I don't know what to try else.

Were you able to get the CRUD Repository to work?

satyakatta avatar Aug 16 '19 18:08 satyakatta