1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.morph.transform.copiers;
17
18 import java.util.Iterator;
19 import java.util.Locale;
20 import java.util.NoSuchElementException;
21
22 import net.sf.morph.reflect.IndexedContainerReflector;
23 import net.sf.morph.reflect.SizableReflector;
24 import net.sf.morph.transform.Converter;
25 import net.sf.morph.transform.DecoratedConverter;
26 import net.sf.morph.transform.DecoratedCopier;
27 import net.sf.morph.transform.TransformationException;
28 import net.sf.morph.transform.Transformer;
29 import net.sf.morph.util.ClassUtils;
30 import net.sf.morph.util.TransformerUtils;
31
32 /**
33 * A copier that copies a source to multiple destination objects, implementing a "Disassembler."
34 *
35 * @see http://www.martinfowler.com/eaaCatalog/dataTransferObject.html
36 *
37 * @author Matt Benson
38 * @since Morph 1.1
39 */
40 public class DisassemblerCopier extends AssemblyCopierSupport implements DecoratedCopier,
41 DecoratedConverter {
42
43 /**
44 * Adds the index to the source object to pass to the classConverter;
45 */
46 public static class Disassembly {
47 private Object source;
48 private int index;
49
50 private Disassembly(Object source) {
51 this.source = source;
52 }
53
54 /**
55 * Get the source object
56 * @return Object
57 */
58 public Object getSource() {
59 return source;
60 }
61
62 /**
63 * Get the current index.
64 * @return int index
65 */
66 public int getIndex() {
67 return index;
68 }
69
70 }
71
72 private static class DisassemblyIterator implements Iterator {
73 private Disassembly disassembly;
74 private int size;
75 private int index;
76
77 private DisassemblyIterator(Object source, int size) {
78 this.disassembly = new Disassembly(source);
79 this.size = size;
80 }
81
82 public synchronized boolean hasNext() {
83 return index < size;
84 }
85
86 public synchronized Object next() {
87 if (!hasNext()) {
88 throw new NoSuchElementException();
89 }
90 try {
91 disassembly.index = index;
92 return disassembly;
93 } finally {
94 index++;
95 }
96 }
97
98 public void remove() {
99 throw new UnsupportedOperationException();
100 }
101 }
102
103 private static final Class[] DEST_CLASS = new Class[] { Class.class };
104 private static final Class[] SOURCE_DISASSEMBLY = new Class[] { Disassembly.class };
105
106 private class DefaultClassConverter implements Converter {
107 public Object convert(Class destinationClass, Object source, Locale locale)
108 throws TransformationException {
109 Disassembly disassembly = (Disassembly) source;
110 Class[] destinationTypes = TransformerUtils.getDestinationClasses(
111 getCopier(disassembly.getIndex()), ClassUtils.getClass(disassembly
112 .getSource()));
113 if (destinationTypes.length != 1) {
114 throw new TransformationException(
115 "Could not infer destination mapping for index "
116 + disassembly.getIndex());
117 }
118 return destinationTypes[0];
119 }
120
121 public Class[] getDestinationClasses() {
122 return DEST_CLASS;
123 }
124
125 public Class[] getSourceClasses() {
126 return SOURCE_DISASSEMBLY;
127 }
128 }
129
130 private class DisassemblyContainerCopier extends ContainerCopier {
131 /**
132 * Create a new DisassemblyContainerCopier.
133 */
134 public DisassemblyContainerCopier() {
135 setPreferGrow(false);
136 }
137
138 /**
139 * {@inheritDoc}
140 */
141 protected Class determineDestinationContainedType(Object destination,
142 Object sourceValue, Class containedValueClass, Locale locale) {
143 try {
144 return (Class) getClassConverter().convert(Class.class, sourceValue,
145 locale);
146 } catch (TransformationException e) {
147 if (getComponents() == null) {
148
149 Class c = ClassUtils
150 .getClass(((IndexedContainerReflector) getReflector(IndexedContainerReflector.class))
151 .get(destination, ((Disassembly) sourceValue)
152 .getIndex()));
153 if (c != null) {
154 return c;
155 }
156 }
157 throw e;
158 }
159 }
160
161 /**
162 * {@inheritDoc}
163 */
164 protected Object nestedTransform(Class destinationContainedType,
165 Object destinationValue, Object sourceValue, Locale locale,
166 Integer preferredTransformationType) {
167 Disassembly d = (Disassembly) sourceValue;
168 return TransformerUtils.transform(getCopier(d.getIndex()),
169 destinationContainedType, destinationValue, d.getSource(), locale,
170 preferredTransformationType);
171 }
172
173 }
174
175 private Converter classConverter;
176 private DisassemblyContainerCopier containerCopier = new DisassemblyContainerCopier();
177
178 /**
179 * Create a new DisassemblerCopier.
180 */
181 public DisassemblerCopier() {
182 super();
183 }
184
185 /**
186 * Create a new DisassemblerCopier.
187 * @param components
188 */
189 public DisassemblerCopier(Object[] components) {
190 super(components);
191 }
192
193 /**
194 * {@inheritDoc}
195 * @see net.sf.morph.transform.transformers.BaseTransformer#copyImpl(java.lang.Object, java.lang.Object, java.util.Locale, java.lang.Integer)
196 */
197 protected void copyImpl(Object destination, Object source, Locale locale,
198 Integer preferredTransformationType) throws Exception {
199 int size;
200 if (getComponents() == null) {
201 SizableReflector szr = (SizableReflector) getReflector(SizableReflector.class);
202 size = szr.getSize(destination);
203 }
204 else {
205 size = getComponents().length;
206 }
207 containerCopier.copy(destination, new DisassemblyIterator(source, size), locale);
208 }
209
210 /**
211 * {@inheritDoc}
212 * @see net.sf.morph.transform.transformers.BaseTransformer#getSourceClassesImpl()
213 */
214 protected Class[] getSourceClassesImpl() throws Exception {
215 Object[] components = getComponents();
216 if (components == null) {
217 return getNestedTransformer().getSourceClasses();
218 }
219 if (components.length == 0) {
220 return new Class[0];
221 }
222 return TransformerUtils
223 .getSourceClassIntersection((Transformer[]) getComponents());
224 }
225
226 /**
227 * {@inheritDoc}
228 * @see net.sf.morph.transform.transformers.BaseTransformer#getDestinationClassesImpl()
229 */
230 protected synchronized Class[] getDestinationClassesImpl() throws Exception {
231 return containerCopier.getDestinationClasses();
232 }
233
234 /**
235 * Get the Converter used to convert a Disassembly object to a destination class.
236 * @return the classConverter
237 */
238 public synchronized Converter getClassConverter() {
239 if (classConverter == null) {
240 setClassConverter(new DefaultClassConverter());
241 }
242 return classConverter;
243 }
244
245 /**
246 * Set the classConverter used to convert a Disassembly object to a destination class.
247 * @param classConverter the classConverter to set
248 */
249 public synchronized void setClassConverter(Converter classConverter) {
250 this.classConverter = classConverter;
251 }
252
253 }