Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading plugin on-runtime : Ambiguous hander methods mapped & ConcurrentModificationException when unregistering routes #60

Open
Anton-vanderTuijn opened this issue Dec 15, 2020 · 0 comments

Comments

@Anton-vanderTuijn
Copy link

Hi,

I'm trying to import plugins on-runtime,
I began without on-runtime plugin loading, base on the pf4j-spring demo I manage to create plugins and if I place the plugin file into /plugins before creating the Spring ApplicationContext everything is fine, I can access each of my mapped routes.
To implement on-runtime plugin loading, when I detect a new plugin I load them and then call the following méthod:

public void registerMvcEndpoints(PluginManager pm) {
    pm.getExtensions(PluginInterface.class).stream()
                .flatMap(g -> g.mvcControllers().stream())
                .forEach(r -> {
                    if (!beanAlreadyRegistered.contains(r.getClass().getName())){
                        ((ConfigurableBeanFactory) beanFactory).registerSingleton(r.getClass().getName(), r);
                        beanAlreadyRegistered.add(r.getClass().getName());
                    }
                });
    applicationContext
                .getBeansOfType(RequestMappingHandlerMapping.class)
                .forEach((k, v) -> {
                    v.afterPropertiesSet();
                });

But when I try to access a route, even without adding a plugin I get IllegalStateException: Ambiguous handler methods mapped for ...
That is because the routes are registered a second time, so because of that I try to use unregisterMapping() to clean the mapping by adding the following code:

RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
for (RequestMappingInfo key : handlerMethods.keySet()) {
    requestMappingHandlerMapping.unregisterMapping(key);
}

But I get this exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginEndpoints' defined in class path resource [fr/polytech/al3/PolyVilleActive/PluginConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [int]: Factory method 'pluginEndpoints' threw exception; nested exception is java.util.ConcurrentModificationException
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:882) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.6.RELEASE.jar!/:2.2.6.RELEASE]
        at fr.polytech.al3.PolyVilleActive.SpringPluginContainerApplication.main(SpringPluginContainerApplication.java:29) ~[classes!/:0.0.1-SNAPSHOT]
        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:566) ~[na:na]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) ~[spring-plugin-container-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) ~[spring-plugin-container-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:51) ~[spring-plugin-container-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52) ~[spring-plugin-container-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [int]: Factory method 'pluginEndpoints' threw exception; nested exception is java.util.ConcurrentModificationException
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        ... 27 common frames omitted
Caused by: java.util.ConcurrentModificationException: null
        at java.base/java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:719) ~[na:na]
        at java.base/java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:741) ~[na:na]
        at java.base/java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1047) ~[na:na]
        at fr.polytech.al3.PolyVilleActive.PluginConfig.registerMvcEndpoints(PluginConfig.java:81) ~[classes!/:0.0.1-SNAPSHOT]
        at fr.polytech.al3.PolyVilleActive.PluginConfig.pluginEndpoints(PluginConfig.java:54) ~[classes!/:0.0.1-SNAPSHOT]
        at fr.polytech.al3.PolyVilleActive.PluginConfig$$EnhancerBySpringCGLIB$$7f069b53.CGLIB$pluginEndpoints$2(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at fr.polytech.al3.PolyVilleActive.PluginConfig$$EnhancerBySpringCGLIB$$7f069b53$$FastClassBySpringCGLIB$$c0fdb9ae.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        at fr.polytech.al3.PolyVilleActive.PluginConfig$$EnhancerBySpringCGLIB$$7f069b53.pluginEndpoints(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        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:566) ~[na:na]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
        ... 28 common frames omitted
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

No branches or pull requests

1 participant