📄 beancreaterule.java
字号:
}
}
/**
* Tidy up.
*/
public void finish() {}
// Properties
//-------------------------------------------------------------------------
/**
* The name of the attribute which can be specified in the XML to override the
* type of a bean used at a certain point in the schema.
*
* <p>The default value is 'className'.</p>
*
* @return The name of the attribute used to overload the class name of a bean
*/
public String getClassNameAttribute() {
return classNameAttribute;
}
/**
* Sets the name of the attribute which can be specified in
* the XML to override the type of a bean used at a certain
* point in the schema.
*
* <p>The default value is 'className'.</p>
*
* @param classNameAttribute The name of the attribute used to overload the class name of a bean
*/
public void setClassNameAttribute(String classNameAttribute) {
this.classNameAttribute = classNameAttribute;
}
// Implementation methods
//-------------------------------------------------------------------------
/**
* Factory method to create new bean instances
*
* @param attributes the <code>Attributes</code> used to match <code>ID/IDREF</code>
* @return the created bean
*/
protected Object createBean(Attributes attributes) {
//
// See if we've got an IDREF
//
// XXX This should be customizable but i'm not really convinced by the existing system
// XXX maybe it's going to have to change so i'll use 'idref' for nows
//
if ( matchIDs ) {
String idref = attributes.getValue( "idref" );
if ( idref != null ) {
// XXX need to check up about ordering
// XXX this is a very simple system that assumes that id occurs before idrefs
// XXX would need some thought about how to implement a fuller system
log.trace( "Found IDREF" );
Object bean = getBeansById().get( idref );
if ( bean != null ) {
if (log.isTraceEnabled()) {
log.trace( "Matched bean " + bean );
}
return bean;
}
log.trace( "No match found" );
}
}
Class theClass = beanClass;
try {
String className = attributes.getValue(classNameAttribute);
if (className != null) {
// load the class we should instantiate
theClass = getDigester().getClassLoader().loadClass(className);
}
if (log.isTraceEnabled()) {
log.trace( "Creating instance of " + theClass );
}
return theClass.newInstance();
} catch (Exception e) {
log.warn( "Could not create instance of type: " + theClass.getName() );
return null;
}
}
/** Adds the rules to the digester for all child elements */
protected void addChildRules() {
if ( ! addedChildren ) {
addedChildren = true;
addChildRules( pathPrefix, descriptor );
}
}
/**
* Add child rules for given descriptor at given prefix
*
* @param prefix add child rules at this (digester) path prefix
* @param currentDescriptor add child rules for this descriptor
*/
protected void addChildRules(String prefix, ElementDescriptor currentDescriptor ) {
if (log.isTraceEnabled()) {
log.trace("Adding child rules for " + currentDescriptor + "@" + prefix);
}
// if we are a reference to a type we should lookup the original
// as this ElementDescriptor will be 'hollow' and have no child attributes/elements.
// XXX: this should probably be done by the NodeDescriptors...
ElementDescriptor typeDescriptor = getElementDescriptor( currentDescriptor );
//ElementDescriptor typeDescriptor = descriptor;
ElementDescriptor[] childDescriptors = typeDescriptor.getElementDescriptors();
if ( childDescriptors != null ) {
for ( int i = 0, size = childDescriptors.length; i < size; i++ ) {
final ElementDescriptor childDescriptor = childDescriptors[i];
if (log.isTraceEnabled()) {
log.trace("Processing child " + childDescriptor);
}
String qualifiedName = childDescriptor.getQualifiedName();
if ( qualifiedName == null ) {
log.trace( "Ignoring" );
continue;
}
String path = prefix + qualifiedName;
// this code is for making sure that recursive elements
// can also be used..
if ( qualifiedName.equals( currentDescriptor.getQualifiedName() )
&& currentDescriptor.getPropertyName() != null ) {
log.trace("Creating generic rule for recursive elements");
int index = -1;
if (childDescriptor.isWrapCollectionsInElement()) {
index = prefix.indexOf(qualifiedName);
if (index == -1) {
// shouldn't happen..
log.debug( "Oops - this shouldn't happen" );
continue;
}
int removeSlash = prefix.endsWith("/")?1:0;
path = "*/" + prefix.substring(index, prefix.length()-removeSlash);
}else{
// we have a element/element type of thing..
ElementDescriptor[] desc = currentDescriptor.getElementDescriptors();
if (desc.length == 1) {
path = "*/"+desc[0].getQualifiedName();
}
}
Rule rule = new BeanCreateRule( childDescriptor, context, path, matchIDs);
addRule(path, rule);
continue;
}
if ( childDescriptor.getUpdater() != null ) {
if (log.isTraceEnabled()) {
log.trace("Element has updater "
+ ((MethodUpdater) childDescriptor.getUpdater()).getMethod().getName());
}
if ( childDescriptor.isPrimitiveType() ) {
addPrimitiveTypeRule(path, childDescriptor);
} else {
// add the first child to the path
ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors();
if ( grandChildren != null && grandChildren.length > 0 ) {
ElementDescriptor grandChild = grandChildren[0];
String grandChildQName = grandChild.getQualifiedName();
if ( grandChildQName != null && grandChildQName.length() > 0 ) {
if (childDescriptor.isWrapCollectionsInElement()) {
path += '/' + grandChildQName;
} else {
path = prefix + (prefix.endsWith("/")?"":"/") + grandChildQName;
}
}
}
// maybe we are adding a primitve type to a collection/array
Class beanClass = childDescriptor.getSingularPropertyType();
if ( XMLIntrospectorHelper.isPrimitiveType( beanClass ) ) {
addPrimitiveTypeRule(path, childDescriptor);
} else {
Rule rule = new BeanCreateRule(
childDescriptor,
context,
path + '/',
matchIDs );
addRule( path, rule );
}
}
} else {
log.trace("Element does not have updater");
}
ElementDescriptor[] grandChildren = childDescriptor.getElementDescriptors();
if ( grandChildren != null && grandChildren.length > 0 ) {
log.trace("Adding grand children");
addChildRules( path + '/', childDescriptor );
}
}
}
}
/**
* Get the associated bean reader.
*
* @return the <code>BeanReader</code digesting the xml
*/
protected BeanReader getBeanReader() {
// XXX this breaks the rule contact
// XXX maybe the reader should be passed in the constructor
return (BeanReader) getDigester();
}
/** Allows the navigation from a reference to a property object to the descriptor defining what
* the property is. i.e. doing the join from a reference to a type to lookup its descriptor.
* This could be done automatically by the NodeDescriptors. Refer to TODO.txt for more info.
*
* @param propertyDescriptor find descriptor for property object referenced by this descriptor
* @return descriptor for the singular property class type referenced.
*/
protected ElementDescriptor getElementDescriptor( ElementDescriptor propertyDescriptor ) {
Class beanClass = propertyDescriptor.getSingularPropertyType();
if ( beanClass != null ) {
XMLIntrospector introspector = getBeanReader().getXMLIntrospector();
try {
XMLBeanInfo xmlInfo = introspector.introspect( beanClass );
return xmlInfo.getElementDescriptor();
} catch (Exception e) {
log.warn( "Could not introspect class: " + beanClass, e );
}
}
// could not find a better descriptor so use the one we've got
return propertyDescriptor;
}
/**
* Adds a new Digester rule to process the text as a primitive type
*
* @param path digester path where this rule will be attached
* @param childDescriptor update this <code>ElementDescriptor</code> with the body text
*/
protected void addPrimitiveTypeRule(String path, final ElementDescriptor childDescriptor) {
Rule rule = new Rule() {
public void body(String text) throws Exception {
childDescriptor.getUpdater().update( context, text );
}
};
addRule( path, rule );
}
/**
* Safely add a rule with given path.
*
* @param path the digester path to add rule at
* @param rule the <code>Rule</code> to add
*/
protected void addRule(String path, Rule rule) {
Rules rules = digester.getRules();
List matches = rules.match(null, path);
if ( matches.isEmpty() ) {
if ( log.isDebugEnabled() ) {
log.debug( "Adding digester rule for path: " + path + " rule: " + rule );
}
digester.addRule( path, rule );
} else {
if ( log.isDebugEnabled() ) {
log.debug( "Ignoring duplicate digester rule for path: "
+ path + " rule: " + rule );
log.debug( "New rule (not added): " + rule );
log.debug( "Existing rule:" + matches.get(0) );
}
}
}
/**
* Get the map used to index beans (previously read in) by id.
* This is stored in the evaluation context.
*
* @return map indexing beans created by id
*/
protected Map getBeansById() {
//
// we need a single index for beans read in by id
// so that we can use them for idref-matching
// store this in the context
//
Map beansById = (Map) context.getVariable( "beans-index" );
if ( beansById == null ) {
// lazy creation
beansById = new HashMap();
context.setVariable( "beans-index", beansById );
log.trace( "Created new index-by-id map" );
}
return beansById;
}
/**
* Return something meaningful for logging.
*
* @return something useful for logging
*/
public String toString() {
return "BeanCreateRule [path prefix=" + pathPrefix + " descriptor=" + descriptor + "]";
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -