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.Locale;
19 import java.util.Map;
20
21 import net.sf.composite.util.ObjectUtils;
22 import net.sf.morph.transform.DecoratedConverter;
23 import net.sf.morph.transform.DecoratedCopier;
24 import net.sf.morph.transform.NodeCopier;
25 import net.sf.morph.transform.Transformer;
26 import net.sf.morph.transform.transformers.BaseReflectorTransformer;
27 import net.sf.morph.util.TransformerUtils;
28
29 /**
30 * Base class for copiers that copy information from one bean to another based
31 * on the property names in the source and destination objects.
32 *
33 * @author Matt Sgarlata
34 * @author Alexander Volanis
35 * @since Feb 5, 2005
36 */
37 public abstract class BasePropertyNameCopier extends BaseReflectorTransformer implements
38 DecoratedCopier, DecoratedConverter, NodeCopier {
39
40 private static final Class[] SOURCE_AND_DESTINATION_TYPES = { Object.class };
41
42 private boolean errorOnMissingProperty = false;
43 private Map propertyTransformers;
44
45 /**
46 * Create a new BasePropertyNameCopier.
47 */
48 public BasePropertyNameCopier() {
49 super();
50 }
51
52 /**
53 * Create a new BasePropertyNameCopier.
54 * @param errorOnMissingProperty
55 */
56 public BasePropertyNameCopier(boolean errorOnMissingProperty) {
57 super();
58 this.errorOnMissingProperty = errorOnMissingProperty;
59 }
60
61 /**
62 * {@inheritDoc}
63 */
64 public Object createReusableSource(Class destinationClass, Object source) {
65 return super.createReusableSource(destinationClass, source);
66 }
67
68 /**
69 * Return <code>true</code> if errors should should be thrown when a
70 * property is missing.
71 *
72 * @return <code>true</code> if errors should be thrown when a property is
73 * missing or <br>
74 * <code>false</code>, otherwise.
75 */
76 public boolean isErrorOnMissingProperty() {
77 return errorOnMissingProperty;
78 }
79
80 /**
81 * Set the value of the errorOnMissingProperty flag.
82 *
83 * @param errorOnMissingProperty
84 * The value of errorOnMissingProperty to set.
85 */
86 public void setErrorOnMissingProperty(boolean isStrict) {
87 this.errorOnMissingProperty = isStrict;
88 }
89
90 /**
91 * Choose the appropriate property transformer.
92 * @param sourceProperty
93 * @param source
94 * @param destinationProperty
95 * @param destination
96 * @param locale
97 * @param preferredTransformationType
98 * @return
99 */
100 protected Transformer chooseTransformer(String sourceProperty, Object source,
101 String destinationProperty, Object destination, Locale locale,
102 Integer preferredTransformationType) {
103 Map m = getPropertyTransformers();
104 if (m != null) {
105 Transformer t = (Transformer) m.get(sourceProperty);
106 if (t != null) {
107 if (t instanceof NodeCopier) {
108 NodeCopier nc = (NodeCopier) t;
109 if (nc.getNestedTransformer() == null) {
110 nc.setNestedTransformer(getNestedTransformer());
111 }
112 }
113 return t;
114 }
115 }
116 return getNestedTransformer();
117 }
118
119 /**
120 * Perform the specified property copy.
121 * @param sourceProperty
122 * @param source
123 * @param destinationProperty
124 * @param destination
125 * @param locale
126 * @param preferredTransformationType
127 */
128 protected void copyProperty(String sourceProperty, Object source,
129 String destinationProperty, Object destination, Locale locale,
130 Integer preferredTransformationType) {
131 if (getLog().isTraceEnabled()) {
132 getLog().trace(
133 "Copying property '" + sourceProperty + "' of "
134 + ObjectUtils.getObjectDescription(source)
135 + " to property '" + destinationProperty + "' of "
136 + ObjectUtils.getObjectDescription(destination));
137 }
138
139
140 Class destinationType = getBeanReflector().getType(
141 destination, destinationProperty);
142
143 Object sourceValue = getBeanReflector().get(source,
144 sourceProperty);
145
146 Object destinationValue = null;
147 if (getBeanReflector().isReadable(destination, destinationProperty)) {
148 destinationValue = getBeanReflector().get(destination,
149 destinationProperty);
150 }
151
152 preferredTransformationType = getPreferredTransformationType(source,
153 sourceProperty, sourceValue, destination, destinationProperty,
154 destinationValue, locale, preferredTransformationType);
155
156 Transformer transformer = chooseTransformer(sourceProperty,
157 source, destinationProperty, destination, locale,
158 preferredTransformationType);
159
160 Object newDestinationValue = TransformerUtils.transform(transformer,
161 destinationType, destinationValue, sourceValue, locale,
162 preferredTransformationType);
163
164 getBeanReflector().set(destination, destinationProperty,
165 newDestinationValue);
166
167 if (getLog().isTraceEnabled()) {
168 getLog().trace(
169 "Done copying property '" + sourceProperty
170 + "' to property '" + destinationProperty
171 + "'. sourceValue was "
172 + ObjectUtils.getObjectDescription(sourceValue)
173 + " and destinationValue was "
174 + ObjectUtils.getObjectDescription(destinationValue));
175 }
176 }
177
178 /**
179 * Extension point for subclasses to override preferredTransformationType.
180 * @param source
181 * @param sourceProperty
182 * @param sourceValue
183 * @param destination
184 * @param destinationProperty
185 * @param destinationValue
186 * @param locale
187 * @param preferredTransformationType
188 * @return Integer
189 * @see Transformer
190 */
191 protected Integer getPreferredTransformationType(Object source,
192 String sourceProperty, Object sourceValue, Object destination,
193 String destinationProperty, Object destinationValue, Locale locale,
194 Integer preferredTransformationType) {
195 return preferredTransformationType;
196 }
197
198 /**
199 * {@inheritDoc}
200 */
201 protected boolean isWrappingRuntimeExceptions() {
202
203
204 return false;
205 }
206
207 /**
208 * {@inheritDoc}
209 */
210
211 public Transformer getNestedTransformer() {
212 return super.getNestedTransformer();
213 }
214
215 /**
216 * {@inheritDoc}
217 */
218
219 public void setNestedTransformer(Transformer transformer) {
220 super.setNestedTransformer(transformer);
221 }
222
223 /**
224 * Get the Map of Transformers to use instead of <code>nestedTransformer</code>.
225 * @return Map
226 */
227 public Map getPropertyTransformers() {
228 return propertyTransformers;
229 }
230
231 /**
232 * Set the Map of Transformers to use instead of <code>nestedTransformer</code>.
233 * @param propertyTransformers
234 */
235 public void setPropertyTransformers(Map propertyTransformers) {
236 this.propertyTransformers = propertyTransformers;
237 }
238
239 /**
240 * {@inheritDoc}
241 */
242 protected Class[] getSourceClassesImpl() throws Exception {
243 return SOURCE_AND_DESTINATION_TYPES;
244 }
245
246 /**
247 * {@inheritDoc}
248 */
249 public void setSourceClasses(Class[] sourceClasses) {
250 super.setSourceClasses(sourceClasses);
251 }
252
253 /**
254 * {@inheritDoc}
255 */
256 protected Class[] getDestinationClassesImpl() throws Exception {
257 return SOURCE_AND_DESTINATION_TYPES;
258 }
259
260 /**
261 * {@inheritDoc}
262 */
263 public void setDestinationClasses(Class[] destinationClasses) {
264 super.setDestinationClasses(destinationClasses);
265 }
266 }