blob: dd257d2ed34a07557347df154010181adaf4b60f [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
*
* 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.
*
*/
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import org.apache.bcel.Constants;
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.InstructionConstants;
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 {@code java.awt.event.ActionListener}
* via the classloader 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
* {@code 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 class_name) {
try {
final Class<?> cl = Class.forName(pack + "$$BCEL$$" + class_name);
return cl.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", "", Constants.ACC_PUBLIC,
new String[]{"java.awt.event.ActionListener"});
// That's important, otherwise newInstance() won't work
cg.addEmptyConstructor(Constants.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(Constants.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(InstructionConstants.DUP);
il.append(new PUSH(cp, "actionPerformed:"));
il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID,
new Type[]{Type.STRING}, Constants.INVOKESPECIAL));
il.append(new ALOAD(1));
il.append(factory.createAppend(Type.OBJECT));
il.append(new INVOKEVIRTUAL(println));
il.append(InstructionConstants.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");
}
}
}