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.Method;
020: import net.sf.cglib.core.*;
021: import org.objectweb.asm.ClassVisitor;
022: import org.objectweb.asm.Type;
023:
024: /**
025: * @author Chris Nokleberg
026: */
027: public class ImmutableBean {
028: private static final Type ILLEGAL_STATE_EXCEPTION = TypeUtils
029: .parseType("IllegalStateException");
030: private static final Signature CSTRUCT_OBJECT = TypeUtils
031: .parseConstructor("Object");
032: private static final Class[] OBJECT_CLASSES = { Object.class };
033: private static final String FIELD_NAME = "CGLIB$RWBean";
034:
035: private ImmutableBean() {
036: }
037:
038: public static Object create(Object bean) {
039: Generator gen = new Generator();
040: gen.setBean(bean);
041: return gen.create();
042: }
043:
044: public static class Generator extends AbstractClassGenerator {
045: private static final Source SOURCE = new Source(
046: ImmutableBean.class.getName());
047: private Object bean;
048: private Class target;
049:
050: public Generator() {
051: super (SOURCE);
052: }
053:
054: public void setBean(Object bean) {
055: this .bean = bean;
056: target = bean.getClass();
057: }
058:
059: protected ClassLoader getDefaultClassLoader() {
060: return target.getClassLoader();
061: }
062:
063: public Object create() {
064: String name = target.getName();
065: setNamePrefix(name);
066: return super .create(name);
067: }
068:
069: public void generateClass(ClassVisitor v) {
070: Type targetType = Type.getType(target);
071: ClassEmitter ce = new ClassEmitter(v);
072: ce.begin_class(Constants.V1_2, Constants.ACC_PUBLIC,
073: getClassName(), targetType, null,
074: Constants.SOURCE_FILE);
075:
076: ce.declare_field(Constants.ACC_FINAL
077: | Constants.ACC_PRIVATE, FIELD_NAME, targetType,
078: null);
079:
080: CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
081: CSTRUCT_OBJECT, null);
082: e.load_this ();
083: e.super _invoke_constructor();
084: e.load_this ();
085: e.load_arg(0);
086: e.checkcast(targetType);
087: e.putfield(FIELD_NAME);
088: e.return_value();
089: e.end_method();
090:
091: PropertyDescriptor[] descriptors = ReflectUtils
092: .getBeanProperties(target);
093: Method[] getters = ReflectUtils.getPropertyMethods(
094: descriptors, true, false);
095: Method[] setters = ReflectUtils.getPropertyMethods(
096: descriptors, false, true);
097:
098: for (int i = 0; i < getters.length; i++) {
099: MethodInfo getter = ReflectUtils
100: .getMethodInfo(getters[i]);
101: e = EmitUtils.begin_method(ce, getter,
102: Constants.ACC_PUBLIC);
103: e.load_this ();
104: e.getfield(FIELD_NAME);
105: e.invoke(getter);
106: e.return_value();
107: e.end_method();
108: }
109:
110: for (int i = 0; i < setters.length; i++) {
111: MethodInfo setter = ReflectUtils
112: .getMethodInfo(setters[i]);
113: e = EmitUtils.begin_method(ce, setter,
114: Constants.ACC_PUBLIC);
115: e.throw_exception(ILLEGAL_STATE_EXCEPTION,
116: "Bean is immutable");
117: e.end_method();
118: }
119:
120: ce.end_class();
121: }
122:
123: protected Object firstInstance(Class type) {
124: return ReflectUtils.newInstance(type, OBJECT_CLASSES,
125: new Object[] { bean });
126: }
127:
128: // TODO: optimize
129: protected Object nextInstance(Object instance) {
130: return firstInstance(instance.getClass());
131: }
132: }
133: }
|