/** * Overloaded version of {@code addPropertyValue} that takes * a property name and a property value. * <p>Note: As of Spring 3.0, we recommend using the more concise * and chaining-capable variant {@link #add}. * @param propertyName name of the property * @param propertyValue value of the property * @see #addPropertyValue(PropertyValue) */ public void addPropertyValue(String propertyName, Object propertyValue) { addPropertyValue(new PropertyValue(propertyName, propertyValue)); }
/** * Add a PropertyValue object, replacing any existing one for the * corresponding property or getting merged with it (if applicable). * @param propertyName name of the property * @param propertyValue value of the property * @return this in order to allow for adding multiple property values in a chain */ public MutablePropertyValues add(String propertyName, @Nullable Object propertyValue) { addPropertyValue(new PropertyValue(propertyName, propertyValue)); return this; }
/** * Add all property values from the given Map. * @param other a Map with property values keyed by property name, * which must be a String * @return this in order to allow for adding multiple property values in a chain */ public MutablePropertyValues addPropertyValues(@Nullable Map<?, ?> other) { if (other != null) { other.forEach((attrName, attrValue) -> addPropertyValue( new PropertyValue(attrName.toString(), attrValue))); } return this; }
/** * Construct a new MutablePropertyValues object from a Map. * @param original a Map with property values keyed by property name Strings * @see #addPropertyValues(Map) */ public MutablePropertyValues(@Nullable Map<?, ?> original) { // We can optimize this because it's all new: // There is no replacement of existing property values. if (original != null) { this.propertyValueList = new ArrayList<>(original.size()); original.forEach((attrName, attrValue) -> this.propertyValueList.add( new PropertyValue(attrName.toString(), attrValue))); } else { this.propertyValueList = new ArrayList<>(0); } }
/** * Copy all given PropertyValues into this object. Guarantees PropertyValue * references are independent, although it can't deep copy objects currently * referenced by individual PropertyValue objects. * @param other the PropertyValues to copy * @return this in order to allow for adding multiple property values in a chain */ public MutablePropertyValues addPropertyValues(@Nullable PropertyValues other) { if (other != null) { PropertyValue[] pvs = other.getPropertyValues(); for (PropertyValue pv : pvs) { addPropertyValue(new PropertyValue(pv)); } } return this; }
/** * Apply the given property value to the corresponding bean. */ protected void applyPropertyValue( ConfigurableListableBeanFactory factory, String beanName, String property, String value) { BeanDefinition bd = factory.getBeanDefinition(beanName); BeanDefinition bdToUse = bd; while (bd != null) { bdToUse = bd; bd = bd.getOriginatingBeanDefinition(); } PropertyValue pv = new PropertyValue(property, value); pv.setOptional(this.ignoreInvalidKeys); bdToUse.getPropertyValues().addPropertyValue(pv); }
@Test public void testChangesOnEquals() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); pvs.addPropertyValue(new PropertyValue("age", "50")); MutablePropertyValues pvs2 = pvs; PropertyValues changes = pvs2.changesSince(pvs); assertTrue("changes are empty", changes.getPropertyValues().length == 0); }
@Test public void testAddOrOverride() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); pvs.addPropertyValue(new PropertyValue("age", "50")); doTestTony(pvs); PropertyValue addedPv = new PropertyValue("rod", "Rod"); pvs.addPropertyValue(addedPv); assertTrue(pvs.getPropertyValue("rod").equals(addedPv)); PropertyValue changedPv = new PropertyValue("forname", "Greg"); pvs.addPropertyValue(changedPv); assertTrue(pvs.getPropertyValue("forname").equals(changedPv)); }
@Override public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException { AbstractNestablePropertyAccessor nestedPa; try { nestedPa = getPropertyAccessorForPropertyPath(propertyName); } catch (NotReadablePropertyException ex) { throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, "Nested property in path '" + propertyName + "' does not exist", ex); } PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value)); }
private PropertyValue createDefaultPropertyValue(PropertyTokenHolder tokens) { TypeDescriptor desc = getPropertyTypeDescriptor(tokens.canonicalName); if (desc == null) { throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + tokens.canonicalName, "Could not determine property type for auto-growing a default value"); } Object defaultValue = newValue(desc.getType(), desc, tokens.canonicalName); return new PropertyValue(tokens.canonicalName, defaultValue); }
@Test public void testValid() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); pvs.addPropertyValue(new PropertyValue("age", "50")); doTestTony(pvs); MutablePropertyValues deepCopy = new MutablePropertyValues(pvs); doTestTony(deepCopy); deepCopy.setPropertyValueAt(new PropertyValue("name", "Gordon"), 0); doTestTony(pvs); assertEquals("Gordon", deepCopy.getPropertyValue("name").getValue()); }
/** * Merges the value of the supplied 'new' {@link PropertyValue} with that of * the current {@link PropertyValue} if merging is supported and enabled. * @see Mergeable */ private PropertyValue mergeIfRequired(PropertyValue newPv, PropertyValue currentPv) { Object value = newPv.getValue(); if (value instanceof Mergeable) { Mergeable mergeable = (Mergeable) value; if (mergeable.isMergeEnabled()) { Object merged = mergeable.merge(currentPv.getValue()); return new PropertyValue(newPv.getName(), merged); } } return newPv; }
@Test public void testComplexObject() { TestBean tb = new TestBean(); String newName = "Rod"; String tbString = "Kerry_34"; BeanWrapper bw = new BeanWrapperImpl(tb); bw.registerCustomEditor(ITestBean.class, new TestBeanEditor()); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("age", new Integer(55))); pvs.addPropertyValue(new PropertyValue("name", newName)); pvs.addPropertyValue(new PropertyValue("touchy", "valid")); pvs.addPropertyValue(new PropertyValue("spouse", tbString)); bw.setPropertyValues(pvs); assertTrue("spouse is non-null", tb.getSpouse() != null); assertTrue("spouse name is Kerry and age is 34", tb.getSpouse().getName().equals("Kerry") && tb.getSpouse().getAge() == 34); }
@Test public void testAspectsAndAdvisorAreAppliedEvenIfComingFromParentFactory() { ClassPathXmlApplicationContext ac = newContext("aspectsPlusAdvisor.xml"); GenericApplicationContext childAc = new GenericApplicationContext(ac); // Create a child factory with a bean that should be woven RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.getPropertyValues().addPropertyValue(new PropertyValue("name", "Adrian")) .addPropertyValue(new PropertyValue("age", 34)); childAc.registerBeanDefinition("adrian2", bd); // Register the advisor auto proxy creator with subclass childAc.registerBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class.getName(), new RootBeanDefinition( AnnotationAwareAspectJAutoProxyCreator.class)); childAc.refresh(); ITestBean beanFromChildContextThatShouldBeWeaved = (ITestBean) childAc.getBean("adrian2"); //testAspectsAndAdvisorAreApplied(childAc, (ITestBean) ac.getBean("adrian")); doTestAspectsAndAdvisorAreApplied(childAc, beanFromChildContextThatShouldBeWeaved); }
@Test public void testExtensiveCircularReference() { DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); for (int i = 0; i < 1000; i++) { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("spouse", new RuntimeBeanReference("bean" + (i < 99 ? i + 1 : 0)))); RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.setPropertyValues(pvs); lbf.registerBeanDefinition("bean" + i, bd); } lbf.preInstantiateSingletons(); for (int i = 0; i < 1000; i++) { TestBean bean = (TestBean) lbf.getBean("bean" + i); TestBean otherBean = (TestBean) lbf.getBean("bean" + (i < 99 ? i + 1 : 0)); assertTrue(bean.getSpouse() == otherBean); } }
@Test public void nestedBindingWithDisabledAutoGrow() throws Exception { FieldAccessBean rod = new FieldAccessBean(); DataBinder binder = new DataBinder(rod, "person"); binder.setAutoGrowNestedPaths(false); binder.initDirectFieldAccess(); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("spouse.name", "Kerry")); thrown.expect(NullValueInNestedPathException.class); binder.bind(pvs); }
@Test public void nestedBindingWithDefaultConversionNoErrors() throws Exception { FieldAccessBean rod = new FieldAccessBean(); DataBinder binder = new DataBinder(rod, "person"); assertTrue(binder.isIgnoreUnknownFields()); binder.initDirectFieldAccess(); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("spouse.name", "Kerry")); pvs.addPropertyValue(new PropertyValue("spouse.jedi", "on")); binder.bind(pvs); binder.close(); assertEquals("Kerry", rod.getSpouse().getName()); assertTrue((rod.getSpouse()).isJedi()); }
@Test public void testAutowireWithUnsatisfiedConstructorDependency() { DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("name", "Rod")); RootBeanDefinition bd = new RootBeanDefinition(TestBean.class); bd.setPropertyValues(pvs); lbf.registerBeanDefinition("rod", bd); assertEquals(1, lbf.getBeanDefinitionCount()); try { lbf.autowire(UnsatisfiedConstructorDependency.class, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, true); fail("Should have unsatisfied constructor dependency on SideEffectBean"); } catch (UnsatisfiedDependencyException ex) { // expected } }
@Test public void setUnknownOptionalProperty() { Simple target = new Simple("John", 2); AbstractPropertyAccessor accessor = createAccessor(target); try { PropertyValue value = new PropertyValue("foo", "value"); value.setOptional(true); accessor.setPropertyValue(value); } catch (NotWritablePropertyException e) { fail("Should not have failed to set an unknown optional property."); } }
@Test public void setAnotherNestedProperty() throws Exception { ITestBean target = new TestBean("rod", 31); ITestBean kerry = new TestBean("kerry", 0); AbstractPropertyAccessor accessor = createAccessor(target); accessor.setPropertyValue("spouse", kerry); assertTrue("nested set worked", target.getSpouse() == kerry); assertTrue("no back relation", kerry.getSpouse() == null); accessor.setPropertyValue(new PropertyValue("spouse.spouse", target)); assertTrue("nested set worked", kerry.getSpouse() == target); assertTrue("kerry age not set", kerry.getAge() == 0); accessor.setPropertyValue(new PropertyValue("spouse.age", 35)); assertTrue("Set primitive on spouse", kerry.getAge() == 35); assertEquals(kerry, accessor.getPropertyValue("spouse")); assertEquals(target, accessor.getPropertyValue("spouse.spouse")); }