This project is Homework 12 for the Java Fundamentals course.
The goal of this homework is to implement the method ProxyBuilder.proxifyBytes(Class<T> iface, Object obj)
to generate the bytecode for a custom dynamic proxy. The dynamic proxy should conform to/implementing the supplied interface and proxy/delegate method calls to the object.
Such a dynamic proxy is useful in scenarios where the object does not implement a specific interface, but still contains methods that have a similar signature to the ones defined in the interface. In this case a dynamic/runtime proxy can be used to make it "look like" the object implemented the interface
Consider an interface:
interface MyInterface {
public String firstMethod();
public String secondMethod();
}
and a class:
class MyClass {
public String firstMethod() {
return "Hello world!";
}
}
Its obvious that MyClass does not implement the MyInterface and an instance of MyClass cannot be used in the following method call (even if MyClass actually does have a method with that exact same signature):
public void doSomething(MyInterface iface) {
System.out.println(iface.firstMethod());
}
However, a static proxy/wrapper for MyClass that would conform to the interface and could be used as a substitute for an instance of MyClass could be created and would look like the following:
class MyClassProxy implements MyInterface {
private final MyClass wrapped;
public MyClassProxy(MyClass wrapped) {
this.wrapped = wrapped;
}
public String firstMethod() {
return wrapped.firstMethod();
}
public String secondMethod() {
throw new NoSuchMethodException();
}
}
Now creating such a static proxy/wrapper to achieve what we want is fine for a single class and interface combination, or even a small set of classes. However what if we want to make just about any class conform to just about any interface? Instead of having to define countless static proxy/wrapper classes, we'll instead build a dynamic proxy during runtime as needed.
Your assignment is to implement the method public <T> byte[] proxifyBytes(Class<T> iface, Object obj)
in the class ProxyBuilder
to generate the bytecode for a dynamic proxy
class for Object obj that would conform to the interface iface. Use the Javassist
library to generate the bytecode for the proxy class.
NB! This is the only method you should need to modify for this assignment.
The above method is used in method public T proxify(Class<T> iface, Object obj)
of the same class which uses the class bytecode from proxifyBytes
to create an instance
of the proxy. These proxy instances are used in unit tests defined in class HomeworkTest
.
NB! The proxify method is already implemented for you, you do not need to change it!
- The returned Object of
public T proxify(Class<T> iface, Object obj)
should be a custom dynamic proxy of the supplied interface, with obj as the Object it should proxy. - The returned byte-array of
public <T> byte[] proxifyBytes(Class<T> iface, Object obj)
should contain the bytecode used to generate the Class used inproxify
- The class of the dynamic proxy should be generated by you using the bytecode manipulation capabilities of
Javassist
. - The generated proxy class should implement the specified interface, meaning all public non-static methods on the interface should be implemented in the class! Yes this includes super-interfaces!
- Note that
getDeclaredMethods
will only give you the methods declared in the class itself, but not the methods of the parent class(es). A method matching the interface may be declared in the parent(s) of the class instead, so make sure your proxy uses that one in this case. - When matching methods, you should match on: the method name, return type, parameter types and exception types of the method.
- The generated proxy class should have a constructor that takes the proxied object as an argument and a field to save the object for method delegation.
- The proxy should work as the following:
- If an implementation of the interface method (i.e. a public non-static method in that interface or any of its super-interfaces) exists on the proxied object (in the object class itself or on any of its superclasses), delegate to that method; passing the correct arguments, and returning whatever that method returns.
- If no such method exists in the proxied object (in the object class itself or on any of its superclasses), throw a NoSuchMethodException.
- The existing unit tests must pass
Note that your method implementation should only accept public interfaces (this avoids visibility errors during proxy instantiation).
When you have gotten the test passing and the build to succeed, you can submit your assignment by first running the following command in the homework root folder:
./mvnw clean deploy
It will ask you for your full name, Student Code (also known as matrikli number) and a comment (optional).
Example:
./mvnw clean deploy
#...skipping building, testing and packaging output from Maven...
[INFO] --- maven-antrun-plugin:1.7:run (package homework ZIP) ---
[INFO] Executing tasks
main:
Your full name (e.g. John Smith):
Jane Smith
Your Student Code (matrikli number, e.g. ABCD012345):
ABCD012345
Comment:
Java IO
[zip] Building zip: /Users/lanza/Projects/java/jf/jf-homework12/target/jf-howework12-ABCD012345.zip
[delete] Deleting: /Users/lanza/Projects/java/jf/jf-homework12/homework.properties
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 45.028s
[INFO] Finished at: Thu Aug 28 15:36:19 EEST 2014
[INFO] Final Memory: 17M/99M
[INFO] ------------------------------------------------------------------------
After Maven has finished and the build was successful, you can find a ZIP file at target/jf-homework12-ABCD012345.zip (the name of the zip file contains the homework number and your Student Code/matrikli number).
This ZIP file contains all the files that we need to check your homework. The only thing left to do now is to send the ZIP file as an attachment to an e-mail with subject "Homework 12 - your Student Code/maktrikli number" to jf@zeroturnaround.com.