1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.xbean.recipe;
18
19 import java.lang.reflect.Array;
20 import java.lang.reflect.Type;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.EnumSet;
25 import java.util.List;
26
27
28
29
30 public class ArrayRecipe extends AbstractRecipe {
31 private final List<Object> list;
32 private String typeName;
33 private Class typeClass;
34 private final EnumSet<Option> options = EnumSet.noneOf(Option.class);
35
36 public ArrayRecipe() {
37 list = new ArrayList<Object>();
38 }
39
40 public ArrayRecipe(String type) {
41 list = new ArrayList<Object>();
42 this.typeName = type;
43 }
44
45 public ArrayRecipe(Class type) {
46 if (type == null) throw new NullPointerException("type is null");
47
48 this.list = new ArrayList<Object>();
49 this.typeClass = type;
50 }
51
52 public ArrayRecipe(ArrayRecipe collectionRecipe) {
53 if (collectionRecipe == null) throw new NullPointerException("setRecipe is null");
54 this.typeName = collectionRecipe.typeName;
55 this.typeClass = collectionRecipe.typeClass;
56 list = new ArrayList<Object>(collectionRecipe.list);
57 }
58
59 public void allow(Option option) {
60 options.add(option);
61 }
62
63 public void disallow(Option option) {
64 options.remove(option);
65 }
66
67 public List<Recipe> getNestedRecipes() {
68 List<Recipe> nestedRecipes = new ArrayList<Recipe>(list.size());
69 for (Object o : list) {
70 if (o instanceof Recipe) {
71 Recipe recipe = (Recipe) o;
72 nestedRecipes.add(recipe);
73 }
74 }
75 return nestedRecipes;
76 }
77
78 public List<Recipe> getConstructorRecipes() {
79 if (!options.contains(Option.LAZY_ASSIGNMENT)) {
80 return getNestedRecipes();
81 }
82 return Collections.emptyList();
83 }
84
85 public boolean canCreate(Type expectedType) {
86 Class expectedClass = RecipeHelper.toClass(expectedType);
87 Class myType = getType(expectedType);
88 return expectedClass.isArray() && RecipeHelper.isAssignable(expectedClass.getComponentType(), myType);
89 }
90
91 protected Object internalCreate(Type expectedType, boolean lazyRefAllowed) throws ConstructionException {
92 Class type = getType(expectedType);
93
94
95 Object array;
96 try {
97 array = Array.newInstance(type, list.size());
98 } catch (Exception e) {
99 throw new ConstructionException("Error while creating array instance: " + type.getName());
100 }
101
102
103 if (getName() != null) {
104 ExecutionContext.getContext().addObject(getName(), array);
105 }
106
107 boolean refAllowed = options.contains(Option.LAZY_ASSIGNMENT);
108
109 int index = 0;
110 for (Object value : list) {
111 value = RecipeHelper.convert(type, value, refAllowed);
112
113 if (value instanceof Reference) {
114 Reference reference = (Reference) value;
115 reference.setAction(new UpdateArray(array, index));
116 } else {
117
118 Array.set(array, index, value);
119 }
120 index++;
121 }
122
123 return array;
124 }
125
126 private Class getType(Type expectedType) {
127 Class expectedClass = RecipeHelper.toClass(expectedType);
128 if (expectedClass.isArray()) {
129 expectedClass = expectedClass.getComponentType();
130 }
131 Class type = expectedClass;
132 if (typeClass != null || typeName != null) {
133 type = typeClass;
134 if (type == null) {
135 try {
136 type = RecipeHelper.loadClass(typeName);
137 } catch (ClassNotFoundException e) {
138 throw new ConstructionException("Type class could not be found: " + typeName);
139 }
140 }
141
142
143 if (type.isAssignableFrom(expectedClass)) {
144 type = expectedClass;
145 }
146 }
147
148 return type;
149 }
150
151 public void add(Object value) {
152 list.add(value);
153 }
154
155 public void addAll(Collection<?> value) {
156 list.addAll(value);
157 }
158
159 public void remove(Object value) {
160 list.remove(value);
161 }
162
163 public void removeAll(Object value) {
164 list.remove(value);
165 }
166
167 public List<Object> getAll() {
168 return Collections.unmodifiableList(list);
169 }
170
171 private static class UpdateArray implements Reference.Action {
172 private final Object array;
173 private final int index;
174
175 public UpdateArray(Object array, int index) {
176 this.array = array;
177 this.index = index;
178 }
179
180 @SuppressWarnings({"unchecked"})
181 public void onSet(Reference ref) {
182 Array.set(array, index, ref.get());
183 }
184 }
185 }