001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package net.sf.cglib.beans;
017:
018: import java.beans.PropertyDescriptor;
019: import java.lang.reflect.*;
020: import net.sf.cglib.core.*;
021: import org.objectweb.asm.ClassVisitor;
022: import org.objectweb.asm.Type;
023: import java.util.*;
024:
025: /**
026: * @author Chris Nokleberg
027: */
028: abstract public class BeanCopier {
029: private static final BeanCopierKey KEY_FACTORY = (BeanCopierKey) KeyFactory
030: .create(BeanCopierKey.class);
031: private static final Type CONVERTER = TypeUtils
032: .parseType("net.sf.cglib.core.Converter");
033: private static final Type BEAN_COPIER = TypeUtils
034: .parseType("net.sf.cglib.beans.BeanCopier");
035: private static final Signature COPY = new Signature("copy",
036: Type.VOID_TYPE, new Type[] { Constants.TYPE_OBJECT,
037: Constants.TYPE_OBJECT, CONVERTER });
038: private static final Signature CONVERT = TypeUtils
039: .parseSignature("Object convert(Object, Class, Object)");
040:
041: interface BeanCopierKey {
042: public Object newInstance(String source, String target,
043: boolean useConverter);
044: }
045:
046: public static BeanCopier create(Class source, Class target,
047: boolean useConverter) {
048: Generator gen = new Generator();
049: gen.setSource(source);
050: gen.setTarget(target);
051: gen.setUseConverter(useConverter);
052: return gen.create();
053: }
054:
055: abstract public void copy(Object from, Object to,
056: Converter converter);
057:
058: public static class Generator extends AbstractClassGenerator {
059: private static final Source SOURCE = new Source(
060: BeanCopier.class.getName());
061: private Class source;
062: private Class target;
063: private boolean useConverter;
064:
065: public Generator() {
066: super (SOURCE);
067: }
068:
069: public void setSource(Class source) {
070: if (!Modifier.isPublic(source.getModifiers())) {
071: setNamePrefix(source.getName());
072: }
073: this .source = source;
074: }
075:
076: public void setTarget(Class target) {
077: if (!Modifier.isPublic(target.getModifiers())) {
078: setNamePrefix(target.getName());
079: }
080:
081: this .target = target;
082: }
083:
084: public void setUseConverter(boolean useConverter) {
085: this .useConverter = useConverter;
086: }
087:
088: protected ClassLoader getDefaultClassLoader() {
089: return source.getClassLoader();
090: }
091:
092: public BeanCopier create() {
093: Object key = KEY_FACTORY.newInstance(source.getName(),
094: target.getName(), useConverter);
095: return (BeanCopier) super .create(key);
096: }
097:
098: public void generateClass(ClassVisitor v) {
099: Type sourceType = Type.getType(source);
100: Type targetType = Type.getType(target);
101: ClassEmitter ce = new ClassEmitter(v);
102: ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC,
103: getClassName(), BEAN_COPIER, null,
104: Constants.SOURCE_FILE);
105:
106: EmitUtils.null_constructor(ce);
107: CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY,
108: null);
109: PropertyDescriptor[] getters = ReflectUtils
110: .getBeanGetters(source);
111: PropertyDescriptor[] setters = ReflectUtils
112: .getBeanGetters(target);
113:
114: Map names = new HashMap();
115: for (int i = 0; i < getters.length; i++) {
116: names.put(getters[i].getName(), getters[i]);
117: }
118: Local targetLocal = e.make_local();
119: Local sourceLocal = e.make_local();
120: if (useConverter) {
121: e.load_arg(1);
122: e.checkcast(targetType);
123: e.store_local(targetLocal);
124: e.load_arg(0);
125: e.checkcast(sourceType);
126: e.store_local(sourceLocal);
127: } else {
128: e.load_arg(1);
129: e.checkcast(targetType);
130: e.load_arg(0);
131: e.checkcast(sourceType);
132: }
133: for (int i = 0; i < setters.length; i++) {
134: PropertyDescriptor setter = setters[i];
135: PropertyDescriptor getter = (PropertyDescriptor) names
136: .get(setter.getName());
137: if (getter != null) {
138: MethodInfo read = ReflectUtils.getMethodInfo(getter
139: .getReadMethod());
140: MethodInfo write = ReflectUtils
141: .getMethodInfo(setter.getWriteMethod());
142: if (useConverter) {
143: Type setterType = write.getSignature()
144: .getArgumentTypes()[0];
145: e.load_local(targetLocal);
146: e.load_arg(2);
147: e.load_local(sourceLocal);
148: e.invoke(read);
149: e.box(read.getSignature().getReturnType());
150: EmitUtils.load_class(e, setterType);
151: e.push(write.getSignature().getName());
152: e.invoke_interface(CONVERTER, CONVERT);
153: e.unbox_or_zero(setterType);
154: e.invoke(write);
155: } else if (compatible(getter, setter)) {
156: e.dup2();
157: e.invoke(read);
158: e.invoke(write);
159: }
160: }
161: }
162: e.return_value();
163: e.end_method();
164: ce.end_class();
165: }
166:
167: private static boolean compatible(PropertyDescriptor getter,
168: PropertyDescriptor setter) {
169: // TODO: allow automatic widening conversions?
170: return setter.getPropertyType().isAssignableFrom(
171: getter.getPropertyType());
172: }
173:
174: protected Object firstInstance(Class type) {
175: return ReflectUtils.newInstance(type);
176: }
177:
178: protected Object nextInstance(Object instance) {
179: return instance;
180: }
181: }
182: }
|