KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > beans > BeanCopier


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.sf.cglib.beans;
17
18 import java.beans.PropertyDescriptor JavaDoc;
19 import java.lang.reflect.*;
20 import net.sf.cglib.core.*;
21 import org.objectweb.asm.ClassVisitor;
22 import org.objectweb.asm.Type;
23 import java.util.*;
24
25 /**
26  * @author Chris Nokleberg
27  */

28 abstract public class BeanCopier
29 {
30     private static final BeanCopierKey KEY_FACTORY =
31       (BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
32     private static final Type CONVERTER =
33       TypeUtils.parseType("net.sf.cglib.core.Converter");
34     private static final Type BEAN_COPIER =
35       TypeUtils.parseType("net.sf.cglib.beans.BeanCopier");
36     private static final Signature COPY =
37       new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
38     private static final Signature CONVERT =
39       TypeUtils.parseSignature("Object convert(Object, Class, Object)");
40     
41     interface BeanCopierKey {
42         public Object JavaDoc newInstance(String JavaDoc source, String JavaDoc target, boolean useConverter);
43     }
44
45     public static BeanCopier create(Class JavaDoc source, Class JavaDoc target, boolean useConverter) {
46         Generator gen = new Generator();
47         gen.setSource(source);
48         gen.setTarget(target);
49         gen.setUseConverter(useConverter);
50         return gen.create();
51     }
52
53     abstract public void copy(Object JavaDoc from, Object JavaDoc to, Converter converter);
54
55     public static class Generator extends AbstractClassGenerator {
56         private static final Source SOURCE = new Source(BeanCopier.class.getName());
57         private Class JavaDoc source;
58         private Class JavaDoc target;
59         private boolean useConverter;
60
61         public Generator() {
62             super(SOURCE);
63         }
64
65         public void setSource(Class JavaDoc source) {
66             if(!Modifier.isPublic(source.getModifiers())){
67                setNamePrefix(source.getName());
68             }
69             this.source = source;
70         }
71         
72         public void setTarget(Class JavaDoc target) {
73             if(!Modifier.isPublic(target.getModifiers())){
74                setNamePrefix(target.getName());
75             }
76           
77             this.target = target;
78         }
79
80         public void setUseConverter(boolean useConverter) {
81             this.useConverter = useConverter;
82         }
83
84         protected ClassLoader JavaDoc getDefaultClassLoader() {
85             return source.getClassLoader();
86         }
87
88         public BeanCopier create() {
89             Object JavaDoc key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
90             return (BeanCopier)super.create(key);
91         }
92
93         public void generateClass(ClassVisitor v) {
94             Type sourceType = Type.getType(source);
95             Type targetType = Type.getType(target);
96             ClassEmitter ce = new ClassEmitter(v);
97             ce.begin_class(Constants.V1_2,
98                            Constants.ACC_PUBLIC,
99                            getClassName(),
100                            BEAN_COPIER,
101                            null,
102                            Constants.SOURCE_FILE);
103
104             EmitUtils.null_constructor(ce);
105             CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
106             PropertyDescriptor JavaDoc[] getters = ReflectUtils.getBeanGetters(source);
107             PropertyDescriptor JavaDoc[] setters = ReflectUtils.getBeanGetters(target);
108
109             Map names = new HashMap();
110             for (int i = 0; i < getters.length; i++) {
111                 names.put(getters[i].getName(), getters[i]);
112             }
113             Local targetLocal = e.make_local();
114             Local sourceLocal = e.make_local();
115             if (useConverter) {
116                 e.load_arg(1);
117                 e.checkcast(targetType);
118                 e.store_local(targetLocal);
119                 e.load_arg(0);
120                 e.checkcast(sourceType);
121                 e.store_local(sourceLocal);
122             } else {
123                 e.load_arg(1);
124                 e.checkcast(targetType);
125                 e.load_arg(0);
126                 e.checkcast(sourceType);
127             }
128             for (int i = 0; i < setters.length; i++) {
129                 PropertyDescriptor JavaDoc setter = setters[i];
130                 PropertyDescriptor JavaDoc getter = (PropertyDescriptor JavaDoc)names.get(setter.getName());
131                 if (getter != null) {
132                     MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
133                     MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
134                     if (useConverter) {
135                         Type setterType = write.getSignature().getArgumentTypes()[0];
136                         e.load_local(targetLocal);
137                         e.load_arg(2);
138                         e.load_local(sourceLocal);
139                         e.invoke(read);
140                         e.box(read.getSignature().getReturnType());
141                         EmitUtils.load_class(e, setterType);
142                         e.push(write.getSignature().getName());
143                         e.invoke_interface(CONVERTER, CONVERT);
144                         e.unbox_or_zero(setterType);
145                         e.invoke(write);
146                     } else if (compatible(getter, setter)) {
147                         e.dup2();
148                         e.invoke(read);
149                         e.invoke(write);
150                     }
151                 }
152             }
153             e.return_value();
154             e.end_method();
155             ce.end_class();
156         }
157
158         private static boolean compatible(PropertyDescriptor JavaDoc getter, PropertyDescriptor JavaDoc setter) {
159             // TODO: allow automatic widening conversions?
160
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
161         }
162
163         protected Object JavaDoc firstInstance(Class JavaDoc type) {
164             return ReflectUtils.newInstance(type);
165         }
166
167         protected Object JavaDoc nextInstance(Object JavaDoc instance) {
168             return instance;
169         }
170     }
171 }
172
Popular Tags