From 1bbe93e535679b608c06f526e70896e47a19627f Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Wed, 27 Jan 2010 12:25:04 +0000 Subject: [PATCH] SPR-3709 + improved example to work with multi-nested declarations + used JDK 5 syntax + added documentation code into trunk (including unit test) for easier future reference --- .../src/test/java/com/foo/Component.java | 26 +++++++ .../foo/ComponentBeanDefinitionParser.java | 52 +++++++++++++ .../ComponentBeanDefinitionParserTest.java | 74 +++++++++++++++++++ .../java/com/foo/ComponentFactoryBean.java | 35 +++++++++ .../com/foo/ComponentNamespaceHandler.java | 10 +++ .../test/resources/META-INF/spring.handlers | 1 + .../test/resources/META-INF/spring.schemas | 1 + .../resources/com/foo/component-config.xml | 17 +++++ .../src/test/resources/com/foo/component.xsd | 19 +++++ spring-framework-reference/src/xml-custom.xml | 56 +++++++------- 10 files changed, 266 insertions(+), 25 deletions(-) create mode 100644 org.springframework.beans/src/test/java/com/foo/Component.java create mode 100644 org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java create mode 100644 org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java create mode 100644 org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java create mode 100644 org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java create mode 100644 org.springframework.beans/src/test/resources/META-INF/spring.handlers create mode 100644 org.springframework.beans/src/test/resources/META-INF/spring.schemas create mode 100644 org.springframework.beans/src/test/resources/com/foo/component-config.xml create mode 100644 org.springframework.beans/src/test/resources/com/foo/component.xsd diff --git a/org.springframework.beans/src/test/java/com/foo/Component.java b/org.springframework.beans/src/test/java/com/foo/Component.java new file mode 100644 index 0000000000..20d7d7e3c7 --- /dev/null +++ b/org.springframework.beans/src/test/java/com/foo/Component.java @@ -0,0 +1,26 @@ +package com.foo; + +import java.util.ArrayList; +import java.util.List; + +public class Component { + private String name; + private List components = new ArrayList(); + + // mmm, there is no setter method for the 'components' + public void addComponent(Component component) { + this.components.add(component); + } + + public List getComponents() { + return components; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java new file mode 100644 index 0000000000..519d2a6bc5 --- /dev/null +++ b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java @@ -0,0 +1,52 @@ +package com.foo; + +import java.util.List; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser { + + protected AbstractBeanDefinition parseInternal(Element element, + ParserContext parserContext) { + return parseComponentElement(element); + } + + private static AbstractBeanDefinition parseComponentElement(Element element) { + BeanDefinitionBuilder factory = BeanDefinitionBuilder + .rootBeanDefinition(ComponentFactoryBean.class); + + factory.addPropertyValue("parent", parseComponent(element)); + + List childElements = DomUtils.getChildElementsByTagName( + element, "component"); + if (childElements != null && childElements.size() > 0) { + parseChildComponents(childElements, factory); + } + + return factory.getBeanDefinition(); + } + + private static BeanDefinition parseComponent(Element element) { + BeanDefinitionBuilder component = BeanDefinitionBuilder + .rootBeanDefinition(Component.class); + component.addPropertyValue("name", element.getAttribute("name")); + return component.getBeanDefinition(); + } + + private static void parseChildComponents(List childElements, + BeanDefinitionBuilder factory) { + ManagedList children = new ManagedList( + childElements.size()); + for (Element element : childElements) { + children.add(parseComponentElement(element)); + } + factory.addPropertyValue("children", children); + } +} diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java new file mode 100644 index 0000000000..9b0cf6f5cb --- /dev/null +++ b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2006-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.foo; + +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; + +/** + * @author Costin Leau + */ +public class ComponentBeanDefinitionParserTest { + + private static XmlBeanFactory bf; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + bf = new XmlBeanFactory(new ClassPathResource( + "com/foo/component-config.xml")); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + bf.destroySingletons(); + } + + private Component getBionicFamily() { + return bf.getBean("bionic-family", Component.class); + } + + @Test + public void testBionicBasic() throws Exception { + Component cp = getBionicFamily(); + assertThat("Bionic-1", equalTo(cp.getName())); + } + + @Test + public void testBionicFirstLevelChildren() throws Exception { + Component cp = getBionicFamily(); + List components = cp.getComponents(); + assertThat(2, equalTo(components.size())); + assertThat("Mother-1", equalTo(components.get(0).getName())); + assertThat("Rock-1", equalTo(components.get(1).getName())); + } + + @Test + public void testBionicSecondLevenChildren() throws Exception { + Component cp = getBionicFamily(); + List components = cp.getComponents().get(0).getComponents(); + assertThat(2, equalTo(components.size())); + assertThat("Karate-1", equalTo(components.get(0).getName())); + assertThat("Sport-1", equalTo(components.get(1).getName())); + } +} \ No newline at end of file diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java b/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java new file mode 100644 index 0000000000..dbc7a03472 --- /dev/null +++ b/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java @@ -0,0 +1,35 @@ +package com.foo; + +import java.util.List; + +import org.springframework.beans.factory.FactoryBean; + +public class ComponentFactoryBean implements FactoryBean { + private Component parent; + private List children; + + public void setParent(Component parent) { + this.parent = parent; + } + + public void setChildren(List children) { + this.children = children; + } + + public Component getObject() throws Exception { + if (this.children != null && this.children.size() > 0) { + for (Component child : children) { + this.parent.addComponent(child); + } + } + return this.parent; + } + + public Class getObjectType() { + return Component.class; + } + + public boolean isSingleton() { + return true; + } +} diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java b/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java new file mode 100644 index 0000000000..aff5ab6a8d --- /dev/null +++ b/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java @@ -0,0 +1,10 @@ +package com.foo; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +public class ComponentNamespaceHandler extends NamespaceHandlerSupport { + public void init() { + registerBeanDefinitionParser("component", + new ComponentBeanDefinitionParser()); + } +} diff --git a/org.springframework.beans/src/test/resources/META-INF/spring.handlers b/org.springframework.beans/src/test/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..025131240f --- /dev/null +++ b/org.springframework.beans/src/test/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler \ No newline at end of file diff --git a/org.springframework.beans/src/test/resources/META-INF/spring.schemas b/org.springframework.beans/src/test/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..37c5d751d4 --- /dev/null +++ b/org.springframework.beans/src/test/resources/META-INF/spring.schemas @@ -0,0 +1 @@ +http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd \ No newline at end of file diff --git a/org.springframework.beans/src/test/resources/com/foo/component-config.xml b/org.springframework.beans/src/test/resources/com/foo/component-config.xml new file mode 100644 index 0000000000..33d1223caa --- /dev/null +++ b/org.springframework.beans/src/test/resources/com/foo/component-config.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/org.springframework.beans/src/test/resources/com/foo/component.xsd b/org.springframework.beans/src/test/resources/com/foo/component.xsd new file mode 100644 index 0000000000..9868ed0e33 --- /dev/null +++ b/org.springframework.beans/src/test/resources/com/foo/component.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-framework-reference/src/xml-custom.xml b/spring-framework-reference/src/xml-custom.xml index 234c71c239..46ae1ea209 100644 --- a/spring-framework-reference/src/xml-custom.xml +++ b/spring-framework-reference/src/xml-custom.xml @@ -297,7 +297,10 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schem http://www.foo.com/schema/component http://www.foo.com/schema/component/component.xsd"> ]]> - + + + + ]]> components = new ArrayList (); ]]>// mmm, there is no setter method for the 'components' getComponents() { return components; } @@ -342,33 +345,31 @@ public class Component { import org.springframework.beans.factory.FactoryBean; -import java.util.Iterator; import java.util.List; -public class ComponentFactoryBean implements FactoryBean { +public class ComponentFactoryBean implements FactoryBean { private Component parent; - private List children; + private List children; public void setParent(Component parent) { this.parent = parent; } - public void setChildren(List children) { + public void setChildren(List children) { this.children = children; } - public Object getObject() throws Exception { + public Component getObject() throws Exception { if (this.children != null && this.children.size() > 0) { - for (Iterator it = children.iterator(); it.hasNext();) { - Component childComponent = (Component) it.next(); - this.parent.addComponent(childComponent); + for (Component child : children) { + this.parent.addComponent(child); } } return this.parent; } - public Class getObjectType() { + public Class getObjectType() { return Component.class; } @@ -417,6 +418,7 @@ public class ComponentNamespaceHandler extends NamespaceHandlerSupport { a ComponentFactoryBean. childElements = DomUtils.getChildElementsByTagName(element, "component"); if (childElements != null && childElements.size() > 0) { parseChildComponents(childElements, factory); } + return factory.getBeanDefinition(); } - private static BeanDefinitionBuilder parseComponent(Element element) { + private static BeanDefinition parseComponent(Element element) { BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class); component.addPropertyValue("name", element.getAttribute("name")); - return component; + return component.getBeanDefinition(); } - - private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) { - ManagedList children = new ManagedList(childElements.size()); - for (int i = 0; i < childElements.size(); ++i) { - Element childElement = (Element) childElements.get(i); - BeanDefinitionBuilder child = parseComponent(childElement); - children.add(child.getBeanDefinition()); + + private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) { + ManagedList children = new ManagedList(childElements.size()); + + for (Element element : childElements) { + children.add(parseComponentElement(element)); } + factory.addPropertyValue("children", children); } }]]>