1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.morph.transform.transformers;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.Locale;
22 import java.util.Map;
23
24 import net.sf.morph.reflect.Reflector;
25 import net.sf.morph.reflect.reflectors.SimpleDelegatingReflector;
26 import net.sf.morph.reflect.reflectors.SimpleInstantiatingReflector;
27 import net.sf.morph.transform.TransformationException;
28 import net.sf.morph.transform.Transformer;
29 import net.sf.morph.transform.converters.IdentityConverter;
30 import net.sf.morph.transform.copiers.ContainerCopier;
31 import net.sf.morph.transform.copiers.PropertyNameMatchingCopier;
32 import net.sf.morph.util.ClassUtils;
33 import net.sf.morph.util.TransformerUtils;
34 import net.sf.morph.util.TypeMap;
35
36 /**
37 * <p>
38 * A transformer that performs a deep copy of the data in an object graph while
39 * also allowing the types in the destination graph to be different than the
40 * types in the source graph. A typical application of this transformer is to
41 * transform a domain model into a graph of transfer objects suitable for
42 * transferring to a remote client or another tier of an n-tier architecture.
43 * </p>
44 *
45 * <p>
46 * Note: if you are using this transformer to transformer an object graph
47 * composed of CGLIB proxies (such as an object graph created by Hibernate), you
48 * may need to specify your source types as interfaces, because CGLIB proxies
49 * may not necessarily be instances of the expected class.
50 * </p>
51 *
52 * @author Matt Sgarlata
53 * @since December 1, 2005
54 */
55 public class TypeChangingGraphTransformer extends SimpleDelegatingTransformer {
56
57 private Map sourceToDestinationTypeMapping;
58
59 /**
60 * Construct a new TypeChangingGraphTransformer.
61 */
62 public TypeChangingGraphTransformer() {
63 }
64
65 protected Transformer getTransformer(Class transformerType) {
66 Object[] components = getComponents();
67 for (int i = 0; i < components.length; i++) {
68 if (transformerType.isAssignableFrom(components[i].getClass())) {
69 return (Transformer) components[i];
70 }
71 }
72 throw new TransformationException(
73 "Could not find a component of type '"
74 + transformerType.getName() + "' in transformer "
75 + this);
76 }
77
78 protected ContainerCopier getContainerCopier() {
79 return (ContainerCopier) getTransformer(ContainerCopier.class);
80 }
81
82 protected PropertyNameMatchingCopier getPropertyNameMatchingCopier() {
83 return (PropertyNameMatchingCopier) getTransformer(PropertyNameMatchingCopier.class);
84 }
85
86 protected IdentityConverter getIdentityConverter() {
87 return (IdentityConverter) getTransformer(IdentityConverter.class);
88 }
89
90 protected Reflector createReflector() {
91
92
93
94
95 SimpleInstantiatingReflector instantiatingReflector = new SimpleInstantiatingReflector();
96 instantiatingReflector.setRequestedToInstantiatedTypeMap(sourceToDestinationTypeMapping);
97
98
99
100 SimpleDelegatingReflector reflector = new SimpleDelegatingReflector();
101 List components = new ArrayList(Arrays.asList(reflector.getComponents()));
102 components.add(0, instantiatingReflector);
103 reflector.setComponents(components.toArray(new Reflector[components.size()]));
104 return reflector;
105 }
106
107 protected void initializeImpl() throws Exception {
108 super.initializeImpl();
109
110 Reflector reflector = createReflector();
111
112 ContainerCopier cc = getContainerCopier();
113 cc.setContainedSourceToDestinationTypeMap(getSourceToDestinationTypeMapping());
114 cc.setReflector(reflector);
115
116 PropertyNameMatchingCopier pnmc = getPropertyNameMatchingCopier();
117 pnmc.setReflector(reflector);
118
119
120
121
122
123 IdentityConverter identityConverter = getIdentityConverter();
124 identityConverter.setSourceClasses(ClassUtils.getImmutableTypes());
125
126 this.setReflector(reflector);
127 }
128
129 protected Object convertImpl(Class destinationType, Object source, Locale locale) throws Exception {
130 Class transformedDestinationType =
131 TransformerUtils.getMappedDestinationType(
132 getSourceToDestinationTypeMapping(), destinationType);
133 if (transformedDestinationType == null) {
134 transformedDestinationType = destinationType;
135 }
136 return super.convertImpl(transformedDestinationType, source, locale);
137 }
138
139 public Map getSourceToDestinationTypeMapping() {
140 return sourceToDestinationTypeMapping;
141 }
142
143 public void setSourceToDestinationTypeMapping(Map sourceToDestinationTypeMapping) {
144 this.sourceToDestinationTypeMapping = new TypeMap(sourceToDestinationTypeMapping);
145 }
146
147 }