/** * Perform a dependency check that all properties exposed have been set, * if desired. Dependency checks can be objects (collaborating beans), * simple (primitives and String), or all (both). * @param beanName the name of the bean * @param mbd the merged bean definition the bean was created with * @param pds the relevant property descriptors for the target bean * @param pvs the property values to be applied to the bean * @see #isExcludedFromDependencyCheck(java.beans.PropertyDescriptor) */ protected void checkDependencies( String beanName, AbstractBeanDefinition mbd, PropertyDescriptor[] pds, PropertyValues pvs) throws UnsatisfiedDependencyException { int dependencyCheck = mbd.getDependencyCheck(); for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() != null && !pvs.contains(pd.getName())) { boolean isSimple = BeanUtils.isSimpleProperty(pd.getPropertyType()); boolean unsatisfied = (dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_ALL) || (isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_SIMPLE) || (!isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS); if (unsatisfied) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, pd.getName(), "Set this property value or disable dependency checking for this bean."); } } } }
/** * Tests the SPR-2098 bug whereby no more than 1 property element could be * passed to a scripted bean :( */ @Test public void testCanPassInMoreThanOneProperty() { ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-multiple-properties.xml", getClass()); TestBean tb = (TestBean) ctx.getBean("testBean"); ContextScriptBean bean = (ContextScriptBean) ctx.getBean("bean"); assertEquals("The first property ain't bein' injected.", "Sophie Marceau", bean.getName()); assertEquals("The second property ain't bein' injected.", 31, bean.getAge()); assertEquals(tb, bean.getTestBean()); assertEquals(ctx, bean.getApplicationContext()); ContextScriptBean bean2 = (ContextScriptBean) ctx.getBean("bean2"); assertEquals(tb, bean2.getTestBean()); assertEquals(ctx, bean2.getApplicationContext()); try { ctx.getBean("bean3"); fail("Should have thrown BeanCreationException"); } catch (BeanCreationException ex) { // expected assertTrue(ex.contains(UnsatisfiedDependencyException.class)); } }
@Test public void testAutowiredConstructorArgumentWithSingleNonQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); RootBeanDefinition person = new RootBeanDefinition(Person.class, cavs, null); context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); try { context.refresh(); fail("expected BeanCreationException"); } catch (BeanCreationException e) { assertTrue(e instanceof UnsatisfiedDependencyException); assertEquals("autowired", e.getBeanName()); } }
@Test public void testAutowiredConstructorArgumentWithMultipleNonQualifiedCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); context.registerBeanDefinition(JUERGEN, person1); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); try { context.refresh(); fail("expected BeanCreationException"); } catch (BeanCreationException e) { assertTrue(e instanceof UnsatisfiedDependencyException); assertEquals("autowired", e.getBeanName()); } }
@Test public void testAutowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue("the real juergen"); RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null); person1.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue("juergen imposter"); RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); person2.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "juergen")); context.registerBeanDefinition("juergen1", person1); context.registerBeanDefinition("juergen2", person2); context.registerBeanDefinition("autowired", new RootBeanDefinition(QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean.class)); AnnotationConfigUtils.registerAnnotationConfigProcessors(context); try { context.refresh(); fail("expected BeanCreationException"); } catch (BeanCreationException e) { assertTrue(e instanceof UnsatisfiedDependencyException); assertEquals("autowired", e.getBeanName()); } }
@Test public void testAutowireWithDefault() throws Exception { DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(DEFAULT_AUTOWIRE_CONTEXT); DependenciesBean rod1 = (DependenciesBean) xbf.getBean("rod1"); // should have been autowired assertNotNull(rod1.getSpouse()); assertTrue(rod1.getSpouse().getName().equals("Kerry")); DependenciesBean rod2 = (DependenciesBean) xbf.getBean("rod2"); // should have been autowired assertNotNull(rod2.getSpouse()); assertTrue(rod2.getSpouse().getName().equals("Kerry")); try { xbf.getBean("rod3", DependenciesBean.class); fail("Must have thrown UnsatisfiedDependencyException"); } catch (UnsatisfiedDependencyException expected) { } }
/** * * ִ��һ�������Լ�飬�������ع�������ѱ����� * <p> * Perform a dependency check that all properties exposed have been set, if * desired. Dependency checks can be objects (collaborating beans), simple * (primitives and String), or all (both). * * @param beanName * the name of the bean * @param mbd * the merged bean definition the bean was created with * @param pds * the relevant property descriptors for the target bean * @param pvs * the property values to be applied to the bean * @see #isExcludedFromDependencyCheck(java.beans.PropertyDescriptor) */ protected void checkDependencies( String beanName, AbstractBeanDefinition mbd, PropertyDescriptor[] pds, PropertyValues pvs) throws UnsatisfiedDependencyException { int dependencyCheck = mbd.getDependencyCheck(); for (PropertyDescriptor pd : pds) { if (pd.getWriteMethod() != null && !pvs.contains(pd.getName())) { boolean isSimple = BeanUtils.isSimpleProperty(pd.getPropertyType()); boolean unsatisfied = (dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_ALL) || (isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_SIMPLE) || (!isSimple && dependencyCheck == RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS); // �����㣬���쳣 if (unsatisfied) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, pd.getName(), "Set this property value or disable dependency checking for this bean."); } } } }
@Test public void testConstructorResourceInjectionWithNoCandidatesAndNoFallback() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); bpp.setBeanFactory(bf); bf.addBeanPostProcessor(bpp); bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ConstructorWithoutFallbackBean.class)); try { bf.getBean("annotatedBean"); fail("Should have thrown UnsatisfiedDependencyException"); } catch (UnsatisfiedDependencyException ex) { // expected } }
@Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_BUILDER_BEAN_NAME) public StreamsBuilderFactoryBean defaultKafkaStreamBuilder( @Qualifier(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME) ObjectProvider<StreamsConfig> streamsConfigProvider) { StreamsConfig streamsConfig = streamsConfigProvider.getIfAvailable(); if (streamsConfig != null) { StreamsBuilderFactoryBean kStreamBuilderFactoryBean = new StreamsBuilderFactoryBean(streamsConfig); kStreamBuilderFactoryBean.setPhase(Integer.MAX_VALUE - 500); return kStreamBuilderFactoryBean; } else { throw new UnsatisfiedDependencyException(KafkaStreamsDefaultConfiguration.class.getName(), KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_BUILDER_BEAN_NAME, "streamsConfig", "There is no '" + KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME + "' StreamsConfig bean in the application context.\n"); } }
private String getConsumerDescription(UnsatisfiedDependencyException ex) { InjectionPoint injectionPoint = ex.getInjectionPoint(); if (injectionPoint != null) { if (injectionPoint.getField() != null) { return String.format("Field %s in %s", injectionPoint.getField().getName(), injectionPoint.getField().getDeclaringClass().getName()); } if (injectionPoint.getMethodParameter() != null) { if (injectionPoint.getMethodParameter().getConstructor() != null) { return String.format("Parameter %d of constructor in %s", injectionPoint.getMethodParameter().getParameterIndex(), injectionPoint.getMethodParameter().getDeclaringClass() .getName()); } return String.format("Parameter %d of method %s in %s", injectionPoint.getMethodParameter().getParameterIndex(), injectionPoint.getMethodParameter().getMethod().getName(), injectionPoint.getMethodParameter().getDeclaringClass() .getName()); } } return ex.getResourceDescription(); }
@Test public void testDataSourceInitializedWithSchemaCredentials() { this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:true", "spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.schema:" + ClassUtils .addResourcePathToPackagePath(getClass(), "encoding-schema.sql"), "spring.datasource.data:" + ClassUtils .addResourcePathToPackagePath(getClass(), "encoding-data.sql"), "spring.datasource.schema-username:admin", "spring.datasource.schema-password:admin"); try { this.context.refresh(); fail("User does not exist"); } catch (Exception ex) { assertThat(ex).isInstanceOf(UnsatisfiedDependencyException.class); } }
@Test public void testDataSourceInitializedWithDataCredentials() { this.context.register(DataSourceAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:true", "spring.datasource.sqlScriptEncoding:UTF-8", "spring.datasource.schema:" + ClassUtils .addResourcePathToPackagePath(getClass(), "encoding-schema.sql"), "spring.datasource.data:" + ClassUtils .addResourcePathToPackagePath(getClass(), "encoding-data.sql"), "spring.datasource.data-username:admin", "spring.datasource.data-password:admin"); try { this.context.refresh(); fail("User does not exist"); } catch (Exception ex) { assertThat(ex).isInstanceOf(UnsatisfiedDependencyException.class); } }
public void afterPropertiesSet() throws Exception { if (!(beanFactory instanceof ListableBeanFactory)) throw new BeanInitializationException( "The workflow processor [" + beanName + "] " + "is not managed by a ListableBeanFactory, please re-deploy using some dirivative of ListableBeanFactory such as" + "ClassPathXmlApplicationContext "); if (activities == null || activities.isEmpty()) throw new UnsatisfiedDependencyException(getBeanDesc(), beanName, "activities", "No activities were wired for this workflow"); for (Iterator iter = activities.iterator(); iter.hasNext();) { Command activitiy = (Command) iter.next(); if (!supports(activitiy)) throw new BeanInitializationException("The workflow processor [" + beanName + "] does " + "not support the activity of type" + activitiy.getClass().getName()); } }
private void tracingEnabledCheck() { context.register(SpringTracingConfiguration.class); try { context.refresh(); fail("Expect to throw UnsatisfiedDependencyException, but got none"); } catch (UnsatisfiedDependencyException ignored) { } catch (Exception e) { fail("Expect to throw UnsatisfiedDependencyException, but got Exception: " + e); } }
/** * Resolve the prepared arguments stored in the given bean definition. */ private Object[] resolvePreparedArguments( String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) { Class<?>[] paramTypes = (methodOrCtor instanceof Method ? ((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes()); TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ? this.beanFactory.getCustomTypeConverter() : bw); BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); Object[] resolvedArgs = new Object[argsToResolve.length]; for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) { Object argValue = argsToResolve[argIndex]; MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, argIndex); GenericTypeResolver.resolveParameterType(methodParam, methodOrCtor.getDeclaringClass()); if (argValue instanceof AutowiredArgumentMarker) { argValue = resolveAutowiredArgument(methodParam, beanName, null, converter); } else if (argValue instanceof BeanMetadataElement) { argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue); } else if (argValue instanceof String) { argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd); } Class<?> paramType = paramTypes[argIndex]; try { resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam); } catch (TypeMismatchException ex) { String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method"); throw new UnsatisfiedDependencyException( mbd.getResourceDescription(), beanName, argIndex, paramType, "Could not convert " + methodType + " argument value of type [" + ObjectUtils.nullSafeClassName(argValue) + "] to required type [" + paramType.getName() + "]: " + ex.getMessage()); } } return resolvedArgs; }
/** * Abstract method defining "autowire by type" (bean properties by type) behavior. * <p>This is like PicoContainer default, in which there must be exactly one bean * of the property type in the bean factory. This makes bean factories simple to * configure for small namespaces, but doesn't work as well as standard Spring * behavior for bigger applications. * @param beanName the name of the bean to autowire by type * @param mbd the merged bean definition to update through autowiring * @param bw BeanWrapper from which we can obtain information about the bean * @param pvs the PropertyValues to register wired objects with */ protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } Set<String> autowiredBeanNames = new LinkedHashSet<String>(4); String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) { try { PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); // Don't try autowiring by type for type Object: never makes sense, // even if it technically is a unsatisfied, non-simple property. if (!Object.class.equals(pd.getPropertyType())) { MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); // Do not allow eager init for type matching in case of a prioritized post-processor. boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass()); DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); if (autowiredArgument != null) { pvs.add(propertyName, autowiredArgument); } for (String autowiredBeanName : autowiredBeanNames) { registerDependentBean(autowiredBeanName, beanName); if (logger.isDebugEnabled()) { logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + autowiredBeanName + "'"); } } autowiredBeanNames.clear(); } } catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); } } }
@Test public void noMongoOperationsConfiguration() { this.thrown.expect(UnsatisfiedDependencyException.class); this.thrown.expectMessage("mongoSessionRepository"); registerAndRefresh(EmptyConfiguration.class); }
@Test public void missingReactorSessionRepositoryBreaksAppContext() { this.context = new AnnotationConfigApplicationContext(); this.context.register(BadConfig.class); assertThatExceptionOfType(UnsatisfiedDependencyException.class) .isThrownBy(this.context::refresh) .withMessageContaining("Error creating bean with name 'reactiveMongoOperationsSessionRepository'") .withMessageContaining("No qualifying bean of type '" + ReactiveMongoOperations.class.getCanonicalName()); }
@Test public void testAutowireByType() { GenericApplicationContext context = new GenericApplicationContext(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultAutowireByTypeTests.xml"); try { context.refresh(); fail("expected exception due to multiple matches for byType autowiring"); } catch (UnsatisfiedDependencyException e) { // expected } }
@Test public void testDependencyCheckAll() { GenericApplicationContext context = new GenericApplicationContext(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); reader.loadBeanDefinitions(LOCATION_PREFIX + "defaultDependencyCheckAllTests.xml"); try { context.refresh(); fail("expected exception due to dependency check"); } catch (UnsatisfiedDependencyException e) { // expected } }
/** * Abstract method defining "autowire by type" (bean properties by type) behavior. * <p>This is like PicoContainer default, in which there must be exactly one bean * of the property type in the bean factory. This makes bean factories simple to * configure for small namespaces, but doesn't work as well as standard Spring * behavior for bigger applications. * @param beanName the name of the bean to autowire by type * @param mbd the merged bean definition to update through autowiring * @param bw BeanWrapper from which we can obtain information about the bean * @param pvs the PropertyValues to register wired objects with */ protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } Set<String> autowiredBeanNames = new LinkedHashSet<String>(4); String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) { try { PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); // Don't try autowiring by type for type Object: never makes sense, // even if it technically is a unsatisfied, non-simple property. if (Object.class != pd.getPropertyType()) { MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); // Do not allow eager init for type matching in case of a prioritized post-processor. boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass()); DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); if (autowiredArgument != null) { pvs.add(propertyName, autowiredArgument); } for (String autowiredBeanName : autowiredBeanNames) { registerDependentBean(autowiredBeanName, beanName); if (logger.isDebugEnabled()) { logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + autowiredBeanName + "'"); } } autowiredBeanNames.clear(); } } catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); } } }
/** * @param clazz class of bean * @param extraContext additional context parameters * @return bean * @throws Exception in case of any errors */ @Override public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception { Object bean; try { // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies if (alwaysRespectAutowireStrategy) { // Leave the creation up to Spring bean = autoWiringFactory.createBean(clazz, autowireStrategy, false); injectApplicationContext(bean); return injectInternalBeans(bean); } else if (enableAopSupport) { bean = autoWiringFactory.createBean(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); bean = autoWireBean(bean, autoWiringFactory); bean = autoWiringFactory.initializeBean(bean, bean.getClass().getName()); return bean; } else { bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); bean = autoWiringFactory.initializeBean(bean, bean.getClass().getName()); return autoWireBean(bean, autoWiringFactory); } } catch (UnsatisfiedDependencyException e) { LOG.error("Error building bean", e); // Fall back return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory); } }
private String getConsumerDescription(Throwable ex) { UnsatisfiedDependencyException unsatisfiedDependency = findUnsatisfiedDependencyException( ex); if (unsatisfiedDependency != null) { return getConsumerDescription(unsatisfiedDependency); } BeanInstantiationException beanInstantiationException = findBeanInstantiationException( ex); if (beanInstantiationException != null) { return getConsumerDescription(beanInstantiationException); } return null; }