blob: d80158c953d1573c09a3af6f3bbd01cefa93fd8c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* https://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.
*/
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import org.apache.bcel.Const;
import org.apache.bcel.classfile.Utility;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionConst;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;
/**
* Dynamically creates and uses a proxy for {@link java.awt.event.ActionListener} via the class loader mechanism if
* called with
*
* <pre>
* java org.apache.bcel.util.JavaWrapper ProxyCreator
* </pre>
*
* The trick is to encode the byte code we need into the class name using the Utility.encode() method. This will result
* however in big ugly class name, so for many cases it will be more sufficient to put some clever creation code into
* the class loader.
* <p>
* This is comparable to the mechanism provided via {@link java.lang.reflect.Proxy}, but much more flexible.
* </p>
*
* @see org.apache.bcel.util.JavaWrapper
* @see Utility
*/
public class ProxyCreator {
/**
* Load class and create instance
*/
public static Object createProxy(final String pack, final String className) {
try {
final Class<?> cl = Class.forName(pack + "$$BCEL$$" + className);
return cl.getConstructor().newInstance();
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Create JavaClass object for a simple proxy for an java.awt.event.ActionListener that just prints the passed
* arguments, load and use it via the class loader mechanism.
*/
public static void main(final String[] argv) throws Exception {
final ClassLoader loader = ProxyCreator.class.getClassLoader();
// instanceof won't work here ...
// TODO this is broken; cannot ever be true now that ClassLoader has been dropped
if (loader.getClass().toString().equals("class org.apache.bcel.util.ClassLoader")) {
// Real class name will be set by the class loader
final ClassGen cg = new ClassGen("foo", "java.lang.Object", "", Const.ACC_PUBLIC, new String[] {"java.awt.event.ActionListener"});
// That's important, otherwise newInstance() won't work
cg.addEmptyConstructor(Const.ACC_PUBLIC);
final InstructionList il = new InstructionList();
final ConstantPoolGen cp = cg.getConstantPool();
final InstructionFactory factory = new InstructionFactory(cg);
final int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
final int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/Object;)V");
final MethodGen mg = new MethodGen(Const.ACC_PUBLIC, Type.VOID, new Type[] {new ObjectType("java.awt.event.ActionEvent")}, null,
"actionPerformed", "foo", il, cp);
// System.out.println("actionPerformed:" + event);
il.append(new GETSTATIC(out));
il.append(factory.createNew("java.lang.StringBuffer"));
il.append(InstructionConst.DUP);
il.append(new PUSH(cp, "actionPerformed:"));
il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] {Type.STRING}, Const.INVOKESPECIAL));
il.append(new ALOAD(1));
il.append(factory.createAppend(Type.OBJECT));
il.append(new INVOKEVIRTUAL(println));
il.append(InstructionConst.RETURN);
mg.stripAttributes(true);
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());
final byte[] bytes = cg.getJavaClass().getBytes();
System.out.println("Uncompressed class: " + bytes.length);
final String s = Utility.encode(bytes, true);
System.out.println("Encoded class: " + s.length());
System.out.print("Creating proxy... ");
final ActionListener a = (ActionListener) createProxy("foo.bar.", s);
System.out.println("Done. Now calling actionPerformed()");
a.actionPerformed(new ActionEvent(a, ActionEvent.ACTION_PERFORMED, "hello"));
} else {
System.err.println("Call me with java org.apache.bcel.util.JavaWrapper ProxyCreator");
}
}
}