001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.configuration2.beanutils; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027/** 028 * <p> 029 * A special implementation of the {@code BeanDeclaration} interface which 030 * allows combining multiple {@code BeanDeclaration} objects. 031 * </p> 032 * <p> 033 * An instance of this class can be used if a bean is defined using multiple 034 * sources. For instance, there can be one definition with default values and 035 * one with actual values; if actual values are provided, they are used; 036 * otherwise, the default values apply. 037 * </p> 038 * <p> 039 * When constructing an instance an arbitrary number of child 040 * {@code BeanDeclaration} objects can be specified. The implementations of the 041 * {@code BeanDeclaration} methods implement a logical combination of the data 042 * returned by these child declarations. The order in which child declarations 043 * are added is relevant; first entries take precedence over later ones. The 044 * comments of the single methods explain in which way a combination of the 045 * child declarations is built. 046 * </p> 047 * 048 * @version $Id: CombinedBeanDeclaration.java 1790899 2017-04-10 21:56:46Z ggregory $ 049 * @since 2.0 050 */ 051public class CombinedBeanDeclaration implements BeanDeclaration 052{ 053 /** A list with the child declarations. */ 054 private final List<BeanDeclaration> childDeclarations; 055 056 /** 057 * Creates a new instance of {@code CombinedBeanDeclaration} and initializes 058 * it with the given child declarations. 059 * 060 * @param decl the child declarations 061 * @throws NullPointerException if the array with child declarations is 062 * <b>null</b> 063 */ 064 public CombinedBeanDeclaration(BeanDeclaration... decl) 065 { 066 childDeclarations = new ArrayList<>(Arrays.asList(decl)); 067 } 068 069 /** 070 * {@inheritDoc} This implementation iterates over the list of child 071 * declarations and asks them for a bean factory name. The first 072 * non-<b>null</b> value is returned. If none of the child declarations have 073 * a defined bean factory name, result is <b>null</b>. 074 */ 075 @Override 076 public String getBeanFactoryName() 077 { 078 for (BeanDeclaration d : childDeclarations) 079 { 080 String factoryName = d.getBeanFactoryName(); 081 if (factoryName != null) 082 { 083 return factoryName; 084 } 085 } 086 return null; 087 } 088 089 /** 090 * {@inheritDoc} This implementation iterates over the list of child 091 * declarations and asks them for a bean factory parameter. The first 092 * non-<b>null</b> value is returned. If none of the child declarations have 093 * a defined bean factory parameter, result is <b>null</b>. 094 */ 095 @Override 096 public Object getBeanFactoryParameter() 097 { 098 for (BeanDeclaration d : childDeclarations) 099 { 100 Object factoryParam = d.getBeanFactoryParameter(); 101 if (factoryParam != null) 102 { 103 return factoryParam; 104 } 105 } 106 return null; 107 } 108 109 /** 110 * {@inheritDoc} This implementation iterates over the list of child 111 * declarations and asks them for the bean class name. The first 112 * non-<b>null</b> value is returned. If none of the child declarations have 113 * a defined bean class, result is <b>null</b>. 114 */ 115 @Override 116 public String getBeanClassName() 117 { 118 for (BeanDeclaration d : childDeclarations) 119 { 120 String beanClassName = d.getBeanClassName(); 121 if (beanClassName != null) 122 { 123 return beanClassName; 124 } 125 } 126 return null; 127 } 128 129 /** 130 * {@inheritDoc} This implementation creates a union of the properties 131 * returned by all child declarations. If a property is defined in multiple 132 * child declarations, the declaration that comes before in the list of 133 * children takes precedence. 134 */ 135 @Override 136 public Map<String, Object> getBeanProperties() 137 { 138 Map<String, Object> result = new HashMap<>(); 139 for (int i = childDeclarations.size() - 1; i >= 0; i--) 140 { 141 Map<String, Object> props = 142 childDeclarations.get(i).getBeanProperties(); 143 if (props != null) 144 { 145 result.putAll(props); 146 } 147 } 148 return result; 149 } 150 151 /** 152 * {@inheritDoc} This implementation creates a union of the nested bean 153 * declarations returned by all child declarations. If a complex property is 154 * defined in multiple child declarations, the declaration that comes before 155 * in the list of children takes precedence. 156 */ 157 @Override 158 public Map<String, Object> getNestedBeanDeclarations() 159 { 160 Map<String, Object> result = new HashMap<>(); 161 for (int i = childDeclarations.size() - 1; i >= 0; i--) 162 { 163 Map<String, Object> decls = 164 childDeclarations.get(i).getNestedBeanDeclarations(); 165 if (decls != null) 166 { 167 result.putAll(decls); 168 } 169 } 170 return result; 171 } 172 173 /** 174 * {@inheritDoc} This implementation iterates over the list of child 175 * declarations and asks them for constructor arguments. The first 176 * non-<b>null</b> and non empty collection is returned. If none of the 177 * child declarations provide constructor arguments, result is an empty 178 * collection. 179 */ 180 @Override 181 public Collection<ConstructorArg> getConstructorArgs() 182 { 183 for (BeanDeclaration d : childDeclarations) 184 { 185 Collection<ConstructorArg> args = d.getConstructorArgs(); 186 if (args != null && !args.isEmpty()) 187 { 188 return args; 189 } 190 } 191 return Collections.emptyList(); 192 } 193}