net.sf.cglib.transform.impl.InterceptFieldTransformer Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.cglib.transform.impl;
import net.sf.cglib.transform.*;
import net.sf.cglib.core.*;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
/**
* @author Juozas Baliuka, Chris Nokleberg
*/
public class InterceptFieldTransformer extends ClassEmitterTransformer {
private static final String CALLBACK_FIELD = "$CGLIB_READ_WRITE_CALLBACK";
private static final Type CALLBACK =
TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldCallback");
private static final Type ENABLED =
TypeUtils.parseType("net.sf.cglib.transform.impl.InterceptFieldEnabled");
private static final Signature ENABLED_SET =
new Signature("setInterceptFieldCallback", Type.VOID_TYPE, new Type[]{ CALLBACK });
private static final Signature ENABLED_GET =
new Signature("getInterceptFieldCallback", CALLBACK, new Type[0]);
private InterceptFieldFilter filter;
public InterceptFieldTransformer(InterceptFieldFilter filter) {
this.filter = filter;
}
public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) {
if (!TypeUtils.isInterface(access)) {
super.begin_class(version, access, className, superType, TypeUtils.add(interfaces, ENABLED), sourceFile);
super.declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
CALLBACK_FIELD,
CALLBACK,
null);
CodeEmitter e;
e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_GET, null);
e.load_this();
e.getfield(CALLBACK_FIELD);
e.return_value();
e.end_method();
e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_SET, null);
e.load_this();
e.load_arg(0);
e.putfield(CALLBACK_FIELD);
e.return_value();
e.end_method();
} else {
super.begin_class(version, access, className, superType, interfaces, sourceFile);
}
}
public void declare_field(int access, String name, Type type, Object value) {
super.declare_field(access, name, type, value);
if (!TypeUtils.isStatic(access)) {
if (filter.acceptRead(getClassType(), name)) {
addReadMethod(name, type);
}
if (filter.acceptWrite(getClassType(), name)) {
addWriteMethod(name, type);
}
}
}
private void addReadMethod(String name, Type type) {
CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
readMethodSig(name, type.getDescriptor()),
null);
e.load_this();
e.getfield(name);
e.load_this();
e.invoke_interface(ENABLED,ENABLED_GET);
Label intercept = e.make_label();
e.ifnonnull(intercept);
e.return_value();
e.mark(intercept);
Local result = e.make_local(type);
e.store_local(result);
e.load_this();
e.invoke_interface(ENABLED,ENABLED_GET);
e.load_this();
e.push(name);
e.load_local(result);
e.invoke_interface(CALLBACK, readCallbackSig(type));
if (!TypeUtils.isPrimitive(type)) {
e.checkcast(type);
}
e.return_value();
e.end_method();
}
private void addWriteMethod(String name, Type type) {
CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
writeMethodSig(name, type.getDescriptor()),
null);
e.load_this();
e.dup();
e.invoke_interface(ENABLED,ENABLED_GET);
Label skip = e.make_label();
e.ifnull(skip);
e.load_this();
e.invoke_interface(ENABLED,ENABLED_GET);
e.load_this();
e.push(name);
e.load_this();
e.getfield(name);
e.load_arg(0);
e.invoke_interface(CALLBACK, writeCallbackSig(type));
if (!TypeUtils.isPrimitive(type)) {
e.checkcast(type);
}
Label go = e.make_label();
e.goTo(go);
e.mark(skip);
e.load_arg(0);
e.mark(go);
e.putfield(name);
e.return_value();
e.end_method();
}
public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
return new CodeEmitter(super.begin_method(access, sig, exceptions)) {
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
Type towner = TypeUtils.fromInternalName(owner);
switch (opcode) {
case Constants.GETFIELD:
if (filter.acceptRead(towner, name)) {
helper(towner, readMethodSig(name, desc));
return;
}
break;
case Constants.PUTFIELD:
if (filter.acceptWrite(towner, name)) {
helper(towner, writeMethodSig(name, desc));
return;
}
break;
}
super.visitFieldInsn(opcode, owner, name, desc);
}
private void helper(Type owner, Signature sig) {
invoke_virtual(owner, sig);
}
};
}
private static Signature readMethodSig(String name, String desc) {
return new Signature("$cglib_read_" + name, "()" + desc);
}
private static Signature writeMethodSig(String name, String desc) {
return new Signature("$cglib_write_" + name, "(" + desc + ")V");
}
private static Signature readCallbackSig(Type type) {
Type remap = remap(type);
return new Signature("read" + callbackName(remap),
remap,
new Type[]{ Constants.TYPE_OBJECT,
Constants.TYPE_STRING,
remap });
}
private static Signature writeCallbackSig(Type type) {
Type remap = remap(type);
return new Signature("write" + callbackName(remap),
remap,
new Type[]{ Constants.TYPE_OBJECT,
Constants.TYPE_STRING,
remap,
remap });
}
private static Type remap(Type type) {
switch (type.getSort()) {
case Type.OBJECT:
case Type.ARRAY:
return Constants.TYPE_OBJECT;
default:
return type;
}
}
private static String callbackName(Type type) {
return (type == Constants.TYPE_OBJECT) ?
"Object" :
TypeUtils.upperFirst(TypeUtils.getClassName(type));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy