You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2005/04/17 10:43:25 UTC
svn commit: r161631 - in jakarta/commons/proper/betwixt/trunk:
src/java/org/apache/commons/betwixt/
src/java/org/apache/commons/betwixt/digester/
src/java/org/apache/commons/betwixt/io/read/
src/java/org/apache/commons/betwixt/registry/ xdocs/ xdocs/guide/
Author: rdonkin
Date: Sun Apr 17 01:43:23 2005
New Revision: 161631
URL: http://svn.apache.org/viewcvs?view=rev&rev=161631
Log:
Added support for polymorphic elements. Contributed by Thomas Dudziak. Bugzilla issue #34443.
Modified:
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/ElementDescriptor.java
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/XMLIntrospector.java
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ChainedBeanCreatorFactory.java
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ReadContext.java
jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/registry/DefaultXMLBeanInfoRegistry.java
jakarta/commons/proper/betwixt/trunk/xdocs/guide/reading.xml
jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/ElementDescriptor.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/ElementDescriptor.java?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/ElementDescriptor.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/ElementDescriptor.java Sun Apr 17 01:43:23 2005
@@ -665,4 +665,15 @@
this.useBindTimeTypeForMapping = new Boolean(useBindTimeTypeForMapping);
}
}
+
+ /**
+ * Is this a polymorphic element?
+ * A polymorphic element's name is not fixed at
+ * introspection time and it's resolution is postponed to bind time.
+ * @return true if {@link #getQualifiedName} is null,
+ * false otherwise
+ */
+ public boolean isPolymorphic() {
+ return (getQualifiedName() == null);
+ }
}
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/XMLIntrospector.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/XMLIntrospector.java?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/XMLIntrospector.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/XMLIntrospector.java Sun Apr 17 01:43:23 2005
@@ -43,6 +43,7 @@
import org.apache.commons.betwixt.expression.MethodUpdater;
import org.apache.commons.betwixt.expression.StringExpression;
import org.apache.commons.betwixt.registry.DefaultXMLBeanInfoRegistry;
+import org.apache.commons.betwixt.registry.PolymorphicReferenceResolver;
import org.apache.commons.betwixt.registry.XMLBeanInfoRegistry;
import org.apache.commons.betwixt.strategy.ClassNormalizer;
import org.apache.commons.betwixt.strategy.DefaultNameMapper;
@@ -82,7 +83,7 @@
protected Log log = LogFactory.getLog( XMLIntrospector.class );
/** Maps classes to <code>XMLBeanInfo</code>'s */
- private XMLBeanInfoRegistry registry = new DefaultXMLBeanInfoRegistry();
+ private XMLBeanInfoRegistry registry;
/** Digester used to parse the XML descriptor files */
private XMLBeanInfoDigester digester;
@@ -93,6 +94,14 @@
/** Configuration to be used for introspection*/
private IntrospectionConfiguration configuration;
+ /**
+ * Resolves polymorphic references.
+ * Though this is used only at bind time,
+ * it is typically tightly couple to the xml registry.
+ * It is therefore convenient to keep both references together.
+ */
+ private PolymorphicReferenceResolver polymorphicReferenceResolver;
+
/** Base constructor */
public XMLIntrospector() {
this(new IntrospectionConfiguration());
@@ -106,6 +115,10 @@
*/
public XMLIntrospector(IntrospectionConfiguration configuration) {
setConfiguration(configuration);
+ DefaultXMLBeanInfoRegistry defaultRegistry
+ = new DefaultXMLBeanInfoRegistry();
+ setRegistry(defaultRegistry);
+ setPolymorphicReferenceResolver(defaultRegistry);
}
@@ -154,6 +167,11 @@
* It also allows the standard introspection mechanism
* to be overridden on a per class basis.</p>
*
+ * <p><strong>Note</strong> when using polymophic mapping with a custom
+ * registry, a call to
+ * {@link #setPolymorphicReferenceResolver(PolymorphicReferenceResolver)}
+ * may be necessary.
+ * </p>
* @param registry the XMLBeanInfoRegistry to use
*/
public void setRegistry(XMLBeanInfoRegistry registry) {
@@ -212,6 +230,47 @@
*/
public void setClassNormalizer(ClassNormalizer classNormalizer) {
getConfiguration().setClassNormalizer(classNormalizer);
+ }
+
+
+
+ /**
+ * <p>Gets the resolver for polymorphic references.</p>
+ * <p>
+ * Though this is used only at bind time,
+ * it is typically tightly couple to the xml registry.
+ * It is therefore convenient to keep both references together.
+ * </p>
+ * <p><strong>Note:</strong> though the implementation is
+ * set initially to the default registry,
+ * this reference is not updated when {@link #setRegistry(XMLBeanInfoRegistry)}
+ * is called. Therefore, a call to {@link #setPolymorphicReferenceResolver(PolymorphicReferenceResolver)}
+ * with the instance may be necessary.
+ * </p>
+ * @return <code>PolymorphicReferenceResolver</code>, not null
+ */
+ public PolymorphicReferenceResolver getPolymorphicReferenceResolver() {
+ return polymorphicReferenceResolver;
+ }
+
+ /**
+ * <p>Sets the resolver for polymorphic references.</p>
+ * <p>
+ * Though this is used only at bind time,
+ * it is typically tightly couple to the xml registry.
+ * It is therefore convenient to keep both references together.
+ * </p>
+ * <p><strong>Note:</strong> though the implementation is
+ * set initially to the default registry,
+ * this reference is not updated when {@link #setRegistry(XMLBeanInfoRegistry)}
+ * is called. Therefore, a call to {@link #setPolymorphicReferenceResolver(PolymorphicReferenceResolver)}
+ * with the instance may be necessary.
+ * </p>
+ * @param polymorphicReferenceResolver The polymorphicReferenceResolver to set.
+ */
+ public void setPolymorphicReferenceResolver(
+ PolymorphicReferenceResolver polymorphicReferenceResolver) {
+ this.polymorphicReferenceResolver = polymorphicReferenceResolver;
}
/**
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/digester/ElementRule.java Sun Apr 17 01:43:23 2005
@@ -112,7 +112,8 @@
// check that the name attribute is present
if ( !isCollective && (nameAttributeValue == null || nameAttributeValue.trim().equals( "" ) )) {
- throw new SAXException("Name attribute is required.");
+ // allow polymorphic mappings but log note for user
+ log.info("No name attribute has been specified. This element will be polymorphic.");
}
// check that name is well formed
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ChainedBeanCreatorFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ChainedBeanCreatorFactory.java?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ChainedBeanCreatorFactory.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ChainedBeanCreatorFactory.java Sun Apr 17 01:43:23 2005
@@ -16,6 +16,7 @@
package org.apache.commons.betwixt.io.read;
import org.apache.commons.betwixt.ElementDescriptor;
+import org.apache.commons.betwixt.registry.PolymorphicReferenceResolver;
import org.apache.commons.logging.Log;
/**
@@ -85,8 +86,17 @@
ElementDescriptor descriptor = element.getDescriptor();
if ( descriptor != null ) {
- // created based on implementation class
- theClass = descriptor.getImplementationClass();
+ // check for polymorphism
+ if (descriptor.isPolymorphic()) {
+ theClass = context.getXMLIntrospector().getPolymorphicReferenceResolver()
+ .resolveType(element, context);
+ }
+
+ if (theClass == null)
+ {
+ // created based on implementation class
+ theClass = descriptor.getImplementationClass();
+ }
}
if ( theClass == null ) {
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ReadContext.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ReadContext.java?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ReadContext.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/io/read/ReadContext.java Sun Apr 17 01:43:23 2005
@@ -526,4 +526,6 @@
return result;
}
+
+
}
Modified: jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/registry/DefaultXMLBeanInfoRegistry.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/registry/DefaultXMLBeanInfoRegistry.java?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/registry/DefaultXMLBeanInfoRegistry.java (original)
+++ jakarta/commons/proper/betwixt/trunk/src/java/org/apache/commons/betwixt/registry/DefaultXMLBeanInfoRegistry.java Sun Apr 17 01:43:23 2005
@@ -16,10 +16,15 @@
* limitations under the License.
*/
+import java.util.Collection;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
+import org.apache.commons.betwixt.ElementDescriptor;
import org.apache.commons.betwixt.XMLBeanInfo;
+import org.apache.commons.betwixt.io.read.ElementMapping;
+import org.apache.commons.betwixt.io.read.ReadContext;
/** The default caching implementation.
* A hashmap is used.
@@ -27,7 +32,7 @@
* @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
* @version $Id$
*/
-public class DefaultXMLBeanInfoRegistry implements XMLBeanInfoRegistry {
+public class DefaultXMLBeanInfoRegistry implements XMLBeanInfoRegistry, PolymorphicReferenceResolver {
/** Used to associated <code>XMLBeanInfo</code>'s to classes */
private Map xmlBeanInfos = new HashMap();
@@ -58,5 +63,37 @@
*/
public void flush() {
xmlBeanInfos.clear();
+ }
+
+ /**
+ * Checks all registered <code>XMLBeanInfo</code>'s for the
+ * first suitable match.
+ * If a suitable one is found, then the class of that info is used.
+ * @see org.apache.commons.betwixt.registry.PolymorphicReferenceResolver#resolveType(org.apache.commons.betwixt.io.read.ElementMapping, org.apache.commons.betwixt.io.read.ReadContext)
+ */
+ public Class resolveType(ElementMapping mapping, ReadContext context) {
+ Class result = null;
+ Collection cachedClasses = getCachedClasses();
+ ElementDescriptor mappedDescriptor = mapping.getDescriptor();
+ for (Iterator it = cachedClasses.iterator(); it.hasNext();) {
+ XMLBeanInfo beanInfo = get((Class)it.next());
+ ElementDescriptor typeDescriptor = beanInfo.getElementDescriptor();
+ if (mapping.getName().equals(typeDescriptor.getQualifiedName()) &&
+ mappedDescriptor.getPropertyType().isAssignableFrom(beanInfo.getBeanClass())) {
+ result = beanInfo.getBeanClass();
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets all classes that are cached in this registry.
+ *
+ * @return The classes
+ */
+ private Collection getCachedClasses()
+ {
+ return xmlBeanInfos.keySet();
}
}
Modified: jakarta/commons/proper/betwixt/trunk/xdocs/guide/reading.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/xdocs/guide/reading.xml?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/xdocs/guide/reading.xml (original)
+++ jakarta/commons/proper/betwixt/trunk/xdocs/guide/reading.xml Sun Apr 17 01:43:23 2005
@@ -323,6 +323,61 @@
available.
</p>
</subsection>
+ <subsection name='Reading Polymorphic Mappings'>
+ <p>
+A polymophic mapping is one where the decision about the element type and name
+is postponed from introspection time to bind time. This allows reading of
+collections containing mixed types distinguished by element name. For example:
+ </p>
+<source><![CDATA[
+<?xml version="1.0" ?>
+<container>
+ <elementA/>
+ <elementB/>
+</container>
+]]></source>
+ <p>
+Polymorphic mappings should be set up using dot betwixt files.
+The name attribute for the element should be omitted
+and mappings registered for the contained object types.
+It is usually more convenient to use a single file containing all the mappings.
+For example:
+ </p>
+<source><![CDATA[
+<?xml version="1.0"?>
+<betwixt-config>
+ <class name='SomeContainer'>
+ <element name='container'>
+ <!-- Polymorphic so no name attribute -->
+ <element property='element'/>
+ </element>
+ </class>
+ <!-- Need to register mappings for types of contained elements
+ (when Betwixt default strategy is used) -->
+ <class name='ContainedElementA'>
+ <element name='elementA'/>
+ </class>
+ <class name='ContainedElementB'>
+ <element name='elementB'/>
+ </class>
+</betwixt-config>
+]]></source>
+ <p>
+By default, in this circumstance Betwixt will try to guess the correct resolution
+by searching all registered <code>XMLBeanInfo</code>'s for an appropriate match.
+If more thn one is found, an arbitrary one is used.
+In many cases, this accords well with intuition. There are
+occasions when more finely grained control may be required. The resolution is
+therefore factored into <code>PolymorphicReferenceResolver</code>
+(a pluggable strategy) on <code>XMLIntrospector</code>.
+A custom resolver allows alternative algorithms for determining
+type to be used which can (for example) ignore the mappings registered.
+Note that the default implementation is provided by the default
+<code>XMLBeanInfoRegistry</code> implementation.
+Therefore, when using a custom registry a custom resolver must also
+be used.
+ </p>
+ </subsection>
</section>
</body>
Modified: jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml?view=diff&r1=161630&r2=161631
==============================================================================
--- jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml (original)
+++ jakarta/commons/proper/betwixt/trunk/xdocs/tasks.xml Sun Apr 17 01:43:23 2005
@@ -186,6 +186,10 @@
<section name='Completed'>
<subsection name='since 0.6'>
<ul>
+ <li>Added support for <strong>polymorphic mappings</strong>.
+ This allows the type of a property to be guessed at bind time
+ (rather than at compile time).
+ </li>
<li>Added <strong>options to context</strong>. This replaces direct flavour mechanism.
(Flavour becomes just a specific option).</li>
<li>Factored out <strong>id storage</strong> into strategy</li>
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org