001/*
002 * Copyright 2002-2017 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.config;
018
019import java.util.LinkedHashSet;
020import java.util.Set;
021
022import org.springframework.beans.BeanUtils;
023import org.springframework.beans.TypeConverter;
024import org.springframework.core.ResolvableType;
025
026/**
027 * Simple factory for shared Set instances. Allows for central setup
028 * of Sets via the "set" element in XML bean definitions.
029 *
030 * @author Juergen Hoeller
031 * @since 09.12.2003
032 * @see ListFactoryBean
033 * @see MapFactoryBean
034 */
035public class SetFactoryBean extends AbstractFactoryBean<Set<Object>> {
036
037        private Set<?> sourceSet;
038
039        @SuppressWarnings("rawtypes")
040        private Class<? extends Set> targetSetClass;
041
042
043        /**
044         * Set the source Set, typically populated via XML "set" elements.
045         */
046        public void setSourceSet(Set<?> sourceSet) {
047                this.sourceSet = sourceSet;
048        }
049
050        /**
051         * Set the class to use for the target Set. Can be populated with a fully
052         * qualified class name when defined in a Spring application context.
053         * <p>Default is a linked HashSet, keeping the registration order.
054         * @see java.util.LinkedHashSet
055         */
056        @SuppressWarnings("rawtypes")
057        public void setTargetSetClass(Class<? extends Set> targetSetClass) {
058                if (targetSetClass == null) {
059                        throw new IllegalArgumentException("'targetSetClass' must not be null");
060                }
061                if (!Set.class.isAssignableFrom(targetSetClass)) {
062                        throw new IllegalArgumentException("'targetSetClass' must implement [java.util.Set]");
063                }
064                this.targetSetClass = targetSetClass;
065        }
066
067
068        @Override
069        @SuppressWarnings("rawtypes")
070        public Class<Set> getObjectType() {
071                return Set.class;
072        }
073
074        @Override
075        @SuppressWarnings("unchecked")
076        protected Set<Object> createInstance() {
077                if (this.sourceSet == null) {
078                        throw new IllegalArgumentException("'sourceSet' is required");
079                }
080                Set<Object> result = null;
081                if (this.targetSetClass != null) {
082                        result = BeanUtils.instantiateClass(this.targetSetClass);
083                }
084                else {
085                        result = new LinkedHashSet<Object>(this.sourceSet.size());
086                }
087                Class<?> valueType = null;
088                if (this.targetSetClass != null) {
089                        valueType = ResolvableType.forClass(this.targetSetClass).asCollection().resolveGeneric();
090                }
091                if (valueType != null) {
092                        TypeConverter converter = getBeanTypeConverter();
093                        for (Object elem : this.sourceSet) {
094                                result.add(converter.convertIfNecessary(elem, valueType));
095                        }
096                }
097                else {
098                        result.addAll(this.sourceSet);
099                }
100                return result;
101        }
102
103}