📄 beandefinitionparserdelegate.java
字号:
else if (DomUtils.nodeNameEquals(ele, REF_ELEMENT)) {
// A generic reference to any name of any bean.
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in the same XML file.
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in a parent context.
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean', 'local' or 'parent' is required for <ref> element", ele);
return null;
}
}
}
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
else if (DomUtils.nodeNameEquals(ele, IDREF_ELEMENT)) {
// A generic reference to any name of any bean.
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in the same XML file.
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
error("Either 'bean' or 'local' is required for <idref> element", ele);
return null;
}
}
if (!StringUtils.hasText(refName)) {
error("<idref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanNameReference ref = new RuntimeBeanNameReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
else if (DomUtils.nodeNameEquals(ele, VALUE_ELEMENT)) {
// It's a literal value.
String value = DomUtils.getTextValue(ele);
String typeClassName = ele.getAttribute(TYPE_ATTRIBUTE);
if (!StringUtils.hasText(typeClassName)) {
typeClassName = defaultTypeClassName;
}
try {
return buildTypedStringValue(value, typeClassName, ele);
}
catch (ClassNotFoundException ex) {
error("Type class [" + typeClassName + "] not found for <value> element", ele, ex);
return value;
}
}
else if (DomUtils.nodeNameEquals(ele, NULL_ELEMENT)) {
// It's a distinguished null value. Let's wrap it in a TypedStringValue
// object in order to preserve the source location.
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
else if (DomUtils.nodeNameEquals(ele, LIST_ELEMENT)) {
return parseListElement(ele, bd);
}
else if (DomUtils.nodeNameEquals(ele, SET_ELEMENT)) {
return parseSetElement(ele, bd);
}
else if (DomUtils.nodeNameEquals(ele, MAP_ELEMENT)) {
return parseMapElement(ele, bd);
}
else if (DomUtils.nodeNameEquals(ele, PROPS_ELEMENT)) {
return parsePropsElement(ele);
}
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
/**
* Build a typed String value Object for the given raw value.
* @see org.springframework.beans.factory.config.TypedStringValue
*/
protected Object buildTypedStringValue(String value, String targetTypeName, Element ele)
throws ClassNotFoundException {
ClassLoader classLoader = this.readerContext.getBeanClassLoader();
TypedStringValue typedValue = null;
if (!StringUtils.hasText(targetTypeName)) {
typedValue = new TypedStringValue(value);
}
else if (classLoader != null) {
Class targetType = ClassUtils.forName(targetTypeName, classLoader);
typedValue = new TypedStringValue(value, targetType);
}
else {
typedValue = new TypedStringValue(value, targetTypeName);
}
typedValue.setSource(extractSource(ele));
return typedValue;
}
/**
* Parse a list element.
*/
public List parseListElement(Element collectionEle, BeanDefinition bd) {
String defaultTypeClassName = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = collectionEle.getChildNodes();
ManagedList list = new ManagedList(nl.getLength());
list.setSource(extractSource(collectionEle));
list.setMergeEnabled(parseMergeAttribute(collectionEle));
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i) instanceof Element) {
Element ele = (Element) nl.item(i);
list.add(parsePropertySubElement(ele, bd, defaultTypeClassName));
}
}
return list;
}
/**
* Parse a set element.
*/
public Set parseSetElement(Element collectionEle, BeanDefinition bd) {
String defaultTypeClassName = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = collectionEle.getChildNodes();
ManagedSet set = new ManagedSet(nl.getLength());
set.setSource(extractSource(collectionEle));
set.setMergeEnabled(parseMergeAttribute(collectionEle));
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i) instanceof Element) {
Element ele = (Element) nl.item(i);
set.add(parsePropertySubElement(ele, bd, defaultTypeClassName));
}
}
return set;
}
/**
* Parse a map element.
*/
public Map parseMapElement(Element mapEle, BeanDefinition bd) {
String defaultKeyTypeClassName = mapEle.getAttribute(KEY_TYPE_ATTRIBUTE);
String defaultValueTypeClassName = mapEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
List entryEles = DomUtils.getChildElementsByTagName(mapEle, ENTRY_ELEMENT);
ManagedMap map = new ManagedMap(entryEles.size());
map.setMergeEnabled(parseMergeAttribute(mapEle));
map.setSource(extractSource(mapEle));
for (Iterator it = entryEles.iterator(); it.hasNext();) {
Element entryEle = (Element) it.next();
// Should only have one value child element: ref, value, list, etc.
// Optionally, there might be a key child element.
NodeList entrySubNodes = entryEle.getChildNodes();
Element keyEle = null;
Element valueEle = null;
for (int j = 0; j < entrySubNodes.getLength(); j++) {
if (entrySubNodes.item(j) instanceof Element) {
Element candidateEle = (Element) entrySubNodes.item(j);
if (DomUtils.nodeNameEquals(candidateEle, KEY_ELEMENT)) {
if (keyEle != null) {
error("<entry> element is only allowed to contain one <key> sub-element", entryEle);
}
else {
keyEle = candidateEle;
}
}
else {
// Child element is what we're looking for.
if (valueEle != null) {
error("<entry> element must not contain more than one value sub-element", entryEle);
}
else {
valueEle = candidateEle;
}
}
}
}
// Extract key from attribute or sub-element.
Object key = null;
boolean hasKeyAttribute = entryEle.hasAttribute(KEY_ATTRIBUTE);
boolean hasKeyRefAttribute = entryEle.hasAttribute(KEY_REF_ATTRIBUTE);
if ((hasKeyAttribute && hasKeyRefAttribute) ||
((hasKeyAttribute || hasKeyRefAttribute)) && keyEle != null) {
error("<entry> element is only allowed to contain either " +
"a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element", entryEle);
}
if (hasKeyAttribute) {
key = buildTypedStringValueForMap(
entryEle.getAttribute(KEY_ATTRIBUTE), defaultKeyTypeClassName, entryEle);
}
else if (hasKeyRefAttribute) {
String refName = entryEle.getAttribute(KEY_REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error("<entry> element contains empty 'key-ref' attribute", entryEle);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(entryEle));
key = ref;
}
else if (keyEle != null) {
key = parseKeyElement(keyEle, bd, defaultKeyTypeClassName);
}
else {
error("<entry> element must specify a key", entryEle);
}
// Extract value from attribute or sub-element.
Object value = null;
boolean hasValueAttribute = entryEle.hasAttribute(VALUE_ATTRIBUTE);
boolean hasValueRefAttribute = entryEle.hasAttribute(VALUE_REF_ATTRIBUTE);
if ((hasValueAttribute && hasValueRefAttribute) ||
((hasValueAttribute || hasValueRefAttribute)) && valueEle != null) {
error("<entry> element is only allowed to contain either " +
"'value' attribute OR 'value-ref' attribute OR <value> sub-element", entryEle);
}
if (hasValueAttribute) {
value = buildTypedStringValueForMap(
entryEle.getAttribute(VALUE_ATTRIBUTE), defaultValueTypeClassName, entryEle);
}
else if (hasValueRefAttribute) {
String refName = entryEle.getAttribute(VALUE_REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error("<entry> element contains empty 'value-ref' attribute", entryEle);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(entryEle));
value = ref;
}
else if (valueEle != null) {
value = parsePropertySubElement(valueEle, bd, defaultValueTypeClassName);
}
else {
error("<entry> element must specify a value", entryEle);
}
// Add final key and value to the Map.
map.put(key, value);
}
return map;
}
/**
* Build a typed String value Object for the given raw value.
* @see org.springframework.beans.factory.config.TypedStringValue
*/
protected final Object buildTypedStringValueForMap(String value, String defaultTypeClassName, Element entryEle) {
try {
return buildTypedStringValue(value, defaultTypeClassName, entryEle);
}
catch (ClassNotFoundException ex) {
error("Type class [" + defaultTypeClassName + "] not found for Map key/value type", entryEle, ex);
return value;
}
}
/**
* Parse a key sub-element of a map element.
*/
public Object parseKeyElement(Element keyEle, BeanDefinition bd, String defaultKeyTypeClassName) {
NodeList nl = keyEle.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i) instanceof Element) {
Element candidateEle = (Element) nl.item(i);
// Child element is what we're looking for.
if (subElement != null) {
error("<key> element must not contain more than one value sub-element", keyEle);
}
else {
subElement = candidateEle;
}
}
}
return parsePropertySubElement(subElement, bd, defaultKeyTypeClassName);
}
/**
* Parse a props element.
*/
public Properties parsePropsElement(Element propsEle) {
ManagedProperties props = new ManagedProperties();
props.setSource(extractSource(propsEle));
props.setMergeEnabled(parseMergeAttribute(propsEle));
List propEles = DomUtils.getChildElementsByTagName(propsEle, PROP_ELEMENT);
for (Iterator it = propEles.iterator(); it.hasNext();) {
Element propEle = (Element) it.next();
String key = propEle.getAttribute(KEY_ATTRIBUTE);
// Trim the text value to avoid unwanted whitespace
// caused by typical XML formatting.
String value = DomUtils.getTextValue(propEle).trim();
TypedStringValue keyHolder = new TypedStringValue(key);
keyHolder.setSource(extractSource(propEle));
TypedStringValue valueHolder = new TypedStringValue(value);
valueHolder.setSource(extractSource(propEle));
props.put(keyHolder, valueHolder);
}
return props;
}
/**
* Parse the merge attribute of a collection element, if any.
*/
public boolean parseMergeAttribute(Element collectionElement) {
String value = collectionElement.getAttribute(MERGE_ATTRIBUTE);
if (DEFAULT_VALUE.equals(value)) {
value = this.defaults.getMerge();
}
return TRUE_VALUE.equals(value);
}
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = ele.getNamespaceURI();
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
BeanDefinitionHolder finalDefinition = definitionHolder;
// Decorate based on custom attributes first.
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition);
}
// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition);
}
}
return finalDefinition;
}
private BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDefinition) {
String namespaceUri = node.getNamespaceURI();
if (!isDefaultNamespace(namespaceUri)) {
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
return handler.decorate(node, originalDefinition, new ParserContext(this.readerContext, this));
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDefinition;
}
public boolean isDefaultNamespace(String namespaceUri) {
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
}
private BeanDefinitionHolder parseNestedCustomElement(Element ele, BeanDefinition containingBd) {
BeanDefinition innerDefinition = parseCustomElement(ele, containingBd);
if (innerDefinition == null) {
error("Incorrect usage of element '" + ele.getNodeName() + "' in a nested manner. " +
"This tag cannot be used nested inside <property>.", ele);
return null;
}
String id = ele.getNodeName() + BeanDefinitionReaderUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(innerDefinition);
if (logger.isDebugEnabled()) {
logger.debug("Using generated bean name [" + id +
"] for nested custom element '" + ele.getNodeName() + "'");
}
return new BeanDefinitionHolder(innerDefinition, id);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -