The other day while working on s/SpringBean/Inject/ I've faced a problem in org.apache.wicket.spring.SpringBeanLocator#getBeanDefinition() - it failed with ClassCastException that ApplicationContextMock is not an AbstractApplicationContext
What do you think about this change ? It allows to implement almost all methods in ApplicationContextMock and to use it here [1] and here [2] 1. https://github.com/apache/wicket/blob/67165d1820d247286f5c12c1755fe11424a74046/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java#L233 2. https://github.com/apache/wicket/blob/67165d1820d247286f5c12c1755fe11424a74046/wicket-spring/src/main/java/org/apache/wicket/spring/injection/annot/AnnotProxyFieldValueFactory.java#L252 On Fri, Jun 4, 2021 at 3:42 PM <mgrigo...@apache.org> wrote: > This is an automated email from the ASF dual-hosted git repository. > > mgrigorov pushed a commit to branch > make-spring-applicationcontextmock-smarter > in repository https://gitbox.apache.org/repos/asf/wicket.git > > commit 7839f8887184f5c19767c8e9b31d79dd896d45d1 > Author: Martin Tzvetanov Grigorov <mgrigo...@apache.org> > AuthorDate: Fri Jun 4 15:36:06 2021 +0300 > > Use DefaultListableBeanFactory as a delegate in ApplicationContextMock > > This way ApplicationContextMock could provide implementation for more > of its methods and more importantly SpringBeanLocation#getBeanDefinition() > [1] could work with it, also two more places in > org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory will > use it > > 1. > https://github.com/apache/wicket/blob/8d44c5b5094cccc9d5e05408e42ccc1bd0dd4da6/wicket-spring/src/main/java/org/apache/wicket/spring/SpringBeanLocator.java#L421 > --- > .../wicket/spring/test/ApplicationContextMock.java | 235 > +++++---------------- > 1 file changed, 57 insertions(+), 178 deletions(-) > > diff --git > a/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java > b/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java > index 5d285f7..d5a83f8 100644 > --- > a/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java > +++ > b/wicket-spring/src/main/java/org/apache/wicket/spring/test/ApplicationContextMock.java > @@ -19,45 +19,44 @@ package org.apache.wicket.spring.test; > import java.io.IOException; > import java.io.Serializable; > import java.lang.annotation.Annotation; > -import java.util.ArrayList; > -import java.util.HashMap; > -import java.util.Iterator; > import java.util.Locale; > import java.util.Map; > -import java.util.Map.Entry; > > import org.springframework.beans.BeansException; > import org.springframework.beans.factory.BeanFactory; > -import org.springframework.beans.factory.BeanNotOfRequiredTypeException; > -import org.springframework.beans.factory.FactoryBean; > import org.springframework.beans.factory.NoSuchBeanDefinitionException; > import org.springframework.beans.factory.ObjectProvider; > import > org.springframework.beans.factory.config.AutowireCapableBeanFactory; > +import > org.springframework.beans.factory.config.ConfigurableListableBeanFactory; > +import > org.springframework.beans.factory.support.DefaultListableBeanFactory; > +import org.springframework.beans.factory.support.RootBeanDefinition; > import org.springframework.context.ApplicationContext; > import org.springframework.context.ApplicationEvent; > import org.springframework.context.MessageSourceResolvable; > import org.springframework.context.NoSuchMessageException; > +import org.springframework.context.support.AbstractApplicationContext; > import org.springframework.core.ResolvableType; > -import org.springframework.core.env.Environment; > import org.springframework.core.io.Resource; > > /** > * Mock application context object. This mock context allows easy > creation of unit tests by allowing > * the user to put bean instances into the context. > * > - * Only {@link #getBean(String)}, {@link #getBean(String, Class)}, and > - * {@link #getBeansOfType(Class) > - * } are implemented so far. Any other method throws > - * {@link UnsupportedOperationException}. > - * > * @author Igor Vaynberg (ivaynberg) > * > */ > -public class ApplicationContextMock implements ApplicationContext, > Serializable > +public class ApplicationContextMock extends AbstractApplicationContext > implements Serializable > { > private static final long serialVersionUID = 1L; > > - private final Map<String, Object> beans = new HashMap<>(); > + private final DefaultListableBeanFactory beanFactory; > + private final long startupTime; > + > + public ApplicationContextMock() { > + this.beanFactory = new DefaultListableBeanFactory(); > + > beanFactory.setSerializationId(ApplicationContextMock.class.getName()); > + startupTime = System.currentTimeMillis(); > + } > > /** > * puts bean with the given name into the context > @@ -65,14 +64,9 @@ public class ApplicationContextMock implements > ApplicationContext, Serializable > * @param name > * @param bean > */ > - public void putBean(final String name, final Object bean) > + public <T extends Object> void putBean(final String name, final T > bean) > { > - if (beans.containsKey(name)) > - { > - throw new IllegalArgumentException("a bean with > name [" + name + > - "] has already been added to the context"); > - } > - beans.put(name, bean); > + beanFactory.registerBeanDefinition(name, new > RootBeanDefinition((Class<T>)bean.getClass(), () -> bean)); > } > > /** > @@ -88,159 +82,82 @@ public class ApplicationContextMock implements > ApplicationContext, Serializable > @Override > public Object getBean(final String name) throws BeansException > { > - Object bean = beans.get(name); > - if (bean == null) > - { > - throw new NoSuchBeanDefinitionException(name); > - } > - return bean; > + return beanFactory.getBean(name); > } > > @Override > public Object getBean(final String name, final Object... args) > throws BeansException > { > - return getBean(name); > + return beanFactory.getBean(name, args); > } > > - /** > - * @see > org.springframework.beans.factory.BeanFactory#getBean(java.lang.String, > java.lang.Class) > - */ > @Override > @SuppressWarnings({ "unchecked" }) > public <T> T getBean(String name, Class<T> requiredType) throws > BeansException > { > - Object bean = getBean(name); > - if (!(requiredType.isAssignableFrom(bean.getClass()))) > - { > - throw new BeanNotOfRequiredTypeException(name, > requiredType, bean.getClass()); > - } > - return (T)bean; > + return beanFactory.getBean(name, requiredType); > } > > - /** > - * @see > org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(java.lang.Class) > - */ > @Override > @SuppressWarnings({ "unchecked" }) > public <T> Map<String, T> getBeansOfType(Class<T> type) throws > BeansException > { > - final Map<String, T> found = new HashMap<>(); > - > - for (Entry<String, Object> entry : beans.entrySet()) > - { > - if > (type.isAssignableFrom(entry.getValue().getClass())) > - { > - found.put(entry.getKey(), > (T)entry.getValue()); > - } > - } > - > - return found; > + return beanFactory.getBeansOfType(type); > } > > @Override > public <T> T getBean(Class<T> requiredType) throws BeansException > { > - Iterator<T> beans = > getBeansOfType(requiredType).values().iterator(); > - > - if (beans.hasNext() == false) > - { > - throw new NoSuchBeanDefinitionException("bean of > required type " + requiredType + > - " not found"); > - } > - final T bean = beans.next(); > - > - if (beans.hasNext() != false) > - { > - throw new NoSuchBeanDefinitionException("more than > one bean of required type " + > - requiredType + " found"); > - } > - return bean; > + return beanFactory.getBean(requiredType); > } > > @Override > public <T> T getBean(Class<T> requiredType, Object... objects) > throws BeansException > { > - return getBean(requiredType); > + return beanFactory.getBean(requiredType, objects); > } > > @Override > public <T> ObjectProvider<T> getBeanProvider(Class<T> aClass) > { > - return null; > + return beanFactory.getBeanProvider(aClass); > } > > @Override > public <T> ObjectProvider<T> getBeanProvider(ResolvableType > resolvableType) > { > - return null; > + return beanFactory.getBeanProvider(resolvableType); > } > > @Override > public Map<String, Object> getBeansWithAnnotation(Class<? extends > Annotation> annotationType) > throws BeansException > { > - final Map<String, Object> found = new HashMap<>(); > - > - for (Entry<String, Object> entry : beans.entrySet()) > - { > - if > (entry.getValue().getClass().isAnnotationPresent(annotationType)) > - { > - found.put(entry.getKey(), > entry.getValue()); > - } > - } > - return found; > + return beanFactory.getBeansWithAnnotation(annotationType); > } > > @Override > public <A extends Annotation> A findAnnotationOnBean(String > beanName, Class<A> annotationType) > { > - return findAnnotationOnClass(getBean(beanName).getClass(), > annotationType); > - } > - > - private <A extends Annotation> A findAnnotationOnClass(Class<?> > cls, Class<A> annotationType) > - { > - // lookup annotation type on class > - A annotation = cls.getAnnotation(annotationType); > - > - // lookup annotation type on superclass > - if (annotation == null && cls.getSuperclass() != null) > - { > - annotation = > findAnnotationOnClass(cls.getSuperclass(), annotationType); > - } > - > - // lookup annotation type on interfaces > - if (annotation == null) > - { > - for (Class<?> intfClass : cls.getInterfaces()) > - { > - annotation = > findAnnotationOnClass(intfClass, annotationType); > - > - if (annotation != null) > - { > - break; > - } > - } > - } > - > - return annotation; > + return beanFactory.findAnnotationOnBean(beanName, > annotationType); > } > > @Override > public ApplicationContext getParent() > { > - throw new UnsupportedOperationException(); > + return null; > } > > @Override > public String getDisplayName() > { > - throw new UnsupportedOperationException(); > + return ApplicationContextMock.class.getSimpleName(); > } > > @Override > public long getStartupDate() > { > - throw new UnsupportedOperationException(); > + return startupTime; > } > > @Override > @@ -258,129 +175,103 @@ public class ApplicationContextMock implements > ApplicationContext, Serializable > @Override > public boolean containsBeanDefinition(final String beanName) > { > - return containsBean(beanName); > + return beanFactory.containsBean(beanName); > } > > @Override > public int getBeanDefinitionCount() > { > - return beans.size(); > + return beanFactory.getBeanDefinitionCount(); > } > > @Override > public String[] getBeanDefinitionNames() > { > - return beans.keySet().toArray(new String[0]); > + return beanFactory.getBeanDefinitionNames(); > } > > @Override > public <T> ObjectProvider<T> getBeanProvider(final Class<T> > aClass, final boolean b) { > - return null; > + return beanFactory.getBeanProvider(aClass, b); > } > > @Override > public <T> ObjectProvider<T> getBeanProvider(final ResolvableType > resolvableType, final boolean b) { > - return null; > + return beanFactory.getBeanProvider(resolvableType, b); > } > > @Override > public String[] getBeanNamesForType(ResolvableType resolvableType) > { > - return new String[0]; > + return beanFactory.getBeanNamesForType(resolvableType); > } > > @Override > public String[] getBeanNamesForType(ResolvableType resolvableType, > boolean includeNonSingletons, boolean allowEagerInit) > { > - return new String[0]; > + return beanFactory.getBeanNamesForType(resolvableType, > includeNonSingletons, allowEagerInit); > } > > @Override > - @SuppressWarnings({ "unchecked" }) > public String[] getBeanNamesForType(final Class type) > { > - ArrayList<String> names = new ArrayList<>(); > - for (Entry<String, Object> entry : beans.entrySet()) > - { > - Object bean = entry.getValue(); > - > - if (type.isAssignableFrom(bean.getClass())) > - { > - names.add(entry.getKey()); > - } > - } > - return names.toArray(new String[names.size()]); > + return beanFactory.getBeanNamesForType(type); > } > > @Override > - @SuppressWarnings({ "unchecked" }) > public String[] getBeanNamesForType(Class type, boolean > includeNonSingletons, > boolean allowEagerInit) > { > - throw new UnsupportedOperationException(); > + return beanFactory.getBeanNamesForType(type, > includeNonSingletons, allowEagerInit); > } > > @Override > public <T> Map<String, T> getBeansOfType(Class<T> type, boolean > includeNonSingletons, > boolean allowEagerInit) throws BeansException > { > - throw new UnsupportedOperationException(); > + return beanFactory.getBeansOfType(type, > includeNonSingletons, allowEagerInit); > } > > @Override > public String[] getBeanNamesForAnnotation(Class<? extends > Annotation> aClass) > { > - throw new UnsupportedOperationException(); > + return beanFactory.getBeanNamesForAnnotation(aClass); > } > > @Override > public boolean containsBean(final String name) > { > - return beans.containsKey(name); > + return beanFactory.containsBean(name); > } > > @Override > public boolean isSingleton(final String name) throws > NoSuchBeanDefinitionException > { > - return true; > + return beanFactory.isSingleton(name); > } > > @Override > public Class<?> getType(final String name) throws > NoSuchBeanDefinitionException > { > - return getType(name, true); > + return beanFactory.getType(name); > } > > @Override > public Class<?> getType(String name, boolean allowFactoryBeanInit) > throws NoSuchBeanDefinitionException > { > - Object bean = beans.get(name); > - if (bean == null) > - { > - throw new NoSuchBeanDefinitionException("No bean > with name '" + name + "'"); > - } > - > - if (bean instanceof FactoryBean) > - { > - return ((FactoryBean) bean).getObjectType(); > - } > - > - return bean.getClass(); > + return beanFactory.getType(name, allowFactoryBeanInit); > } > > @Override > public String[] getAliases(final String name) throws > NoSuchBeanDefinitionException > { > - throw new UnsupportedOperationException(); > + return beanFactory.getAliases(name); > } > > - /** > - * @see org.springframework.beans.factory.HierarchicalBeanFactory# > getParentBeanFactory() > - */ > @Override > public BeanFactory getParentBeanFactory() > { > - return null; > + return beanFactory.getParentBeanFactory(); > } > > @Override > @@ -411,64 +302,52 @@ public class ApplicationContextMock implements > ApplicationContext, Serializable > } > > @Override > - public Resource getResource(final String location) > - { > - throw new UnsupportedOperationException(); > + protected void refreshBeanFactory() throws BeansException, > IllegalStateException { > } > > @Override > - public AutowireCapableBeanFactory getAutowireCapableBeanFactory() > throws IllegalStateException > - { > - throw new UnsupportedOperationException(); > + protected void closeBeanFactory() { > } > > @Override > - public boolean containsLocalBean(final String arg0) > - { > - throw new UnsupportedOperationException(); > + public ConfigurableListableBeanFactory getBeanFactory() throws > IllegalStateException { > + return beanFactory; > } > > @Override > - public ClassLoader getClassLoader() > + public Resource getResource(final String location) > { > throw new UnsupportedOperationException(); > } > > @Override > - public String getId() > + public AutowireCapableBeanFactory getAutowireCapableBeanFactory() > throws IllegalStateException > { > - return null; > + return beanFactory; > } > > @Override > - public String getApplicationName() > + public boolean containsLocalBean(final String name) > { > - return ""; > + return beanFactory.containsLocalBean(name); > } > > @Override > public boolean isPrototype(final String name) throws > NoSuchBeanDefinitionException > { > - return !isSingleton(name); > + return beanFactory.isPrototype(name); > } > > @Override > public boolean isTypeMatch(String s, ResolvableType > resolvableType) throws NoSuchBeanDefinitionException > { > - return false; > + return beanFactory.isTypeMatch(s, resolvableType); > } > > @Override > - @SuppressWarnings({ "unchecked" }) > public boolean isTypeMatch(final String name, final Class > targetType) > throws NoSuchBeanDefinitionException > { > - throw new UnsupportedOperationException(); > - } > - > - @Override > - public Environment getEnvironment() > - { > - return null; > + return beanFactory.isTypeMatch(name, targetType); > } > } >