001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.xml; 018 019import java.util.List; 020import java.util.Map; 021import java.util.Properties; 022import java.util.Set; 023 024import org.w3c.dom.Element; 025 026import org.springframework.beans.factory.config.FieldRetrievingFactoryBean; 027import org.springframework.beans.factory.config.ListFactoryBean; 028import org.springframework.beans.factory.config.MapFactoryBean; 029import org.springframework.beans.factory.config.PropertiesFactoryBean; 030import org.springframework.beans.factory.config.PropertyPathFactoryBean; 031import org.springframework.beans.factory.config.SetFactoryBean; 032import org.springframework.beans.factory.support.AbstractBeanDefinition; 033import org.springframework.beans.factory.support.BeanDefinitionBuilder; 034import org.springframework.util.StringUtils; 035 036/** 037 * {@link NamespaceHandler} for the {@code util} namespace. 038 * 039 * @author Rob Harrop 040 * @author Juergen Hoeller 041 * @since 2.0 042 */ 043public class UtilNamespaceHandler extends NamespaceHandlerSupport { 044 045 private static final String SCOPE_ATTRIBUTE = "scope"; 046 047 048 @Override 049 public void init() { 050 registerBeanDefinitionParser("constant", new ConstantBeanDefinitionParser()); 051 registerBeanDefinitionParser("property-path", new PropertyPathBeanDefinitionParser()); 052 registerBeanDefinitionParser("list", new ListBeanDefinitionParser()); 053 registerBeanDefinitionParser("set", new SetBeanDefinitionParser()); 054 registerBeanDefinitionParser("map", new MapBeanDefinitionParser()); 055 registerBeanDefinitionParser("properties", new PropertiesBeanDefinitionParser()); 056 } 057 058 059 private static class ConstantBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser { 060 061 @Override 062 protected Class<?> getBeanClass(Element element) { 063 return FieldRetrievingFactoryBean.class; 064 } 065 066 @Override 067 protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) { 068 String id = super.resolveId(element, definition, parserContext); 069 if (!StringUtils.hasText(id)) { 070 id = element.getAttribute("static-field"); 071 } 072 return id; 073 } 074 } 075 076 077 private static class PropertyPathBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 078 079 @Override 080 protected Class<?> getBeanClass(Element element) { 081 return PropertyPathFactoryBean.class; 082 } 083 084 @Override 085 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { 086 String path = element.getAttribute("path"); 087 if (!StringUtils.hasText(path)) { 088 parserContext.getReaderContext().error("Attribute 'path' must not be empty", element); 089 return; 090 } 091 int dotIndex = path.indexOf('.'); 092 if (dotIndex == -1) { 093 parserContext.getReaderContext().error( 094 "Attribute 'path' must follow pattern 'beanName.propertyName'", element); 095 return; 096 } 097 String beanName = path.substring(0, dotIndex); 098 String propertyPath = path.substring(dotIndex + 1); 099 builder.addPropertyValue("targetBeanName", beanName); 100 builder.addPropertyValue("propertyPath", propertyPath); 101 } 102 103 @Override 104 protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) { 105 String id = super.resolveId(element, definition, parserContext); 106 if (!StringUtils.hasText(id)) { 107 id = element.getAttribute("path"); 108 } 109 return id; 110 } 111 } 112 113 114 private static class ListBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 115 116 @Override 117 protected Class<?> getBeanClass(Element element) { 118 return ListFactoryBean.class; 119 } 120 121 @Override 122 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { 123 List<Object> parsedList = parserContext.getDelegate().parseListElement(element, builder.getRawBeanDefinition()); 124 builder.addPropertyValue("sourceList", parsedList); 125 126 String listClass = element.getAttribute("list-class"); 127 if (StringUtils.hasText(listClass)) { 128 builder.addPropertyValue("targetListClass", listClass); 129 } 130 131 String scope = element.getAttribute(SCOPE_ATTRIBUTE); 132 if (StringUtils.hasLength(scope)) { 133 builder.setScope(scope); 134 } 135 } 136 } 137 138 139 private static class SetBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 140 141 @Override 142 protected Class<?> getBeanClass(Element element) { 143 return SetFactoryBean.class; 144 } 145 146 @Override 147 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { 148 Set<Object> parsedSet = parserContext.getDelegate().parseSetElement(element, builder.getRawBeanDefinition()); 149 builder.addPropertyValue("sourceSet", parsedSet); 150 151 String setClass = element.getAttribute("set-class"); 152 if (StringUtils.hasText(setClass)) { 153 builder.addPropertyValue("targetSetClass", setClass); 154 } 155 156 String scope = element.getAttribute(SCOPE_ATTRIBUTE); 157 if (StringUtils.hasLength(scope)) { 158 builder.setScope(scope); 159 } 160 } 161 } 162 163 164 private static class MapBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 165 166 @Override 167 protected Class<?> getBeanClass(Element element) { 168 return MapFactoryBean.class; 169 } 170 171 @Override 172 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { 173 Map<Object, Object> parsedMap = parserContext.getDelegate().parseMapElement(element, builder.getRawBeanDefinition()); 174 builder.addPropertyValue("sourceMap", parsedMap); 175 176 String mapClass = element.getAttribute("map-class"); 177 if (StringUtils.hasText(mapClass)) { 178 builder.addPropertyValue("targetMapClass", mapClass); 179 } 180 181 String scope = element.getAttribute(SCOPE_ATTRIBUTE); 182 if (StringUtils.hasLength(scope)) { 183 builder.setScope(scope); 184 } 185 } 186 } 187 188 189 private static class PropertiesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 190 191 @Override 192 protected Class<?> getBeanClass(Element element) { 193 return PropertiesFactoryBean.class; 194 } 195 196 @Override 197 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { 198 Properties parsedProps = parserContext.getDelegate().parsePropsElement(element); 199 builder.addPropertyValue("properties", parsedProps); 200 201 String location = element.getAttribute("location"); 202 if (StringUtils.hasLength(location)) { 203 location = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(location); 204 String[] locations = StringUtils.commaDelimitedListToStringArray(location); 205 builder.addPropertyValue("locations", locations); 206 } 207 208 builder.addPropertyValue("ignoreResourceNotFound", 209 Boolean.valueOf(element.getAttribute("ignore-resource-not-found"))); 210 211 builder.addPropertyValue("localOverride", 212 Boolean.valueOf(element.getAttribute("local-override"))); 213 214 String scope = element.getAttribute(SCOPE_ATTRIBUTE); 215 if (StringUtils.hasLength(scope)) { 216 builder.setScope(scope); 217 } 218 } 219 } 220 221}